overhaul attributes

This commit is contained in:
Quaternions 2023-10-17 19:12:25 -07:00
parent 849dcf98f7
commit 38f6e1df3f
3 changed files with 126 additions and 42 deletions

View File

@ -50,8 +50,17 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_interse
let mut contacting=crate::model::ContactingAttributes::default(); let mut contacting=crate::model::ContactingAttributes::default();
let mut force_can_collide=can_collide; let mut force_can_collide=can_collide;
match name{ match name{
"Water"=>intersecting.water=Some(crate::model::IntersectingWater{density:Planar64::ONE,viscosity:Planar64::ONE/10,current:velocity}), "Water"=>{
"Accelerator"=>{force_can_collide=false;intersecting.accelerator=Some(crate::model::IntersectingAccelerator{acceleration:velocity})}, force_can_collide=false;
//TODO: read stupid CustomPhysicalProperties
intersecting.water=Some(crate::model::IntersectingWater{density:Planar64::ONE,viscosity:Planar64::ONE/10,current:velocity});
},
"Accelerator"=>{
//although the new game supports collidable accelerators, this is a roblox compatability map loader
force_can_collide=false;
general.accelerator=Some(crate::model::GameMechanicAccelerator{acceleration:velocity});
},
"SetVelocity"=>general.trajectory=Some(crate::model::GameMechanicSetTrajectory::Velocity(velocity)),
"MapFinish"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Finish})}, "MapFinish"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Finish})},
"MapAnticheat"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Anitcheat})}, "MapAnticheat"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Anitcheat})},
"Platform"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{ "Platform"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{
@ -72,12 +81,28 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_interse
}, },
behaviour:match &captures[2]{ behaviour:match &captures[2]{
"Spawn"|"SpawnAt"=>crate::model::StageElementBehaviour::SpawnAt, "Spawn"|"SpawnAt"=>crate::model::StageElementBehaviour::SpawnAt,
//cancollide false so you don't hit the side
//NOT a decoration
"Trigger"=>{force_can_collide=false;crate::model::StageElementBehaviour::Trigger}, "Trigger"=>{force_can_collide=false;crate::model::StageElementBehaviour::Trigger},
"Teleport"=>{force_can_collide=false;crate::model::StageElementBehaviour::Teleport}, "Teleport"=>{force_can_collide=false;crate::model::StageElementBehaviour::Teleport},
"Platform"=>crate::model::StageElementBehaviour::Platform, "Platform"=>crate::model::StageElementBehaviour::Platform,
_=>panic!("regex1[2] messed up bad"), _=>panic!("regex1[2] messed up bad"),
} }
})); }));
}else if let Some(captures)=lazy_regex::regex!(r"^(Force)?(Jump)(\d+)$")
.captures(other){
general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{
mode_id:0,
stage_id:0,
force:match captures.get(1){
Some(m)=>m.as_str()=="Force",
None=>false,
},
behaviour:match &captures[2]{
"Jump"=>crate::model::StageElementBehaviour::JumpLimit(captures[3].parse::<u32>().unwrap()),
_=>panic!("regex4[1] messed up bad"),
}
}));
}else if let Some(captures)=lazy_regex::regex!(r"^Bonus(Finish|Anticheat)(\d+)$") }else if let Some(captures)=lazy_regex::regex!(r"^Bonus(Finish|Anticheat)(\d+)$")
.captures(other){ .captures(other){
force_can_collide=false; force_can_collide=false;
@ -86,39 +111,33 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_interse
"Anticheat"=>general.zone=Some(crate::model::GameMechanicZone{mode_id:captures[2].parse::<u32>().unwrap(),behaviour:crate::model::ZoneBehaviour::Anitcheat}), "Anticheat"=>general.zone=Some(crate::model::GameMechanicZone{mode_id:captures[2].parse::<u32>().unwrap(),behaviour:crate::model::ZoneBehaviour::Anitcheat}),
_=>panic!("regex2[1] messed up bad"), _=>panic!("regex2[1] messed up bad"),
} }
} }else if let Some(captures)=lazy_regex::regex!(r"^(WormholeIn)(\d+)$")
}
}
//need some way to skip this
if velocity!=Planar64Vec3::ZERO{
general.booster=Some(crate::model::GameMechanicBooster{velocity});
}
match force_can_collide{
true=>{
match name{
"Bounce"=>contacting.elasticity=Some(u32::MAX),
"Surf"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Surf),
"Ladder"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Ladder(crate::model::ContactingLadder{sticky:true})),
other=>{
if let Some(captures)=lazy_regex::regex!(r"^(Jump|WormholeIn)(\d+)$")
.captures(other){ .captures(other){
force_can_collide=false;
match &captures[1]{ match &captures[1]{
"Jump"=>general.jump_limit=Some(crate::model::GameMechanicJumpLimit{count:captures[2].parse::<u32>().unwrap()}),
"WormholeIn"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::Wormhole(crate::model::GameMechanicWormhole{destination_model_id:captures[2].parse::<u32>().unwrap()})), "WormholeIn"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::Wormhole(crate::model::GameMechanicWormhole{destination_model_id:captures[2].parse::<u32>().unwrap()})),
_=>panic!("regex3[1] messed up bad"), _=>panic!("regex3[1] messed up bad"),
} }
} }
} }
} }
//need some way to skip this
if velocity!=Planar64Vec3::ZERO{
general.booster=Some(crate::model::GameMechanicBooster::Velocity(velocity));
}
match force_can_collide{
true=>{
match name{
"Bounce"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Elastic(u32::MAX)),
"Surf"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Surf),
"Ladder"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Ladder(crate::model::ContactingLadder{sticky:true})),
_=>(),
}
crate::model::CollisionAttributes::Contact{contacting,general} crate::model::CollisionAttributes::Contact{contacting,general}
}, },
false=>if force_intersecting false=>if force_intersecting
||general.jump_limit.is_some() ||general.any()
||general.booster.is_some() ||intersecting.any()
||general.zone.is_some()
||general.teleport_behaviour.is_some()
||intersecting.water.is_some()
||intersecting.accelerator.is_some()
{ {
crate::model::CollisionAttributes::Intersect{intersecting,general} crate::model::CollisionAttributes::Intersect{intersecting,general}
}else{ }else{

View File

@ -1,4 +1,4 @@
use crate::integer::{Planar64,Planar64Vec3,Planar64Affine3}; use crate::integer::{Time,Planar64,Planar64Vec3,Planar64Affine3};
pub type TextureCoordinate=glam::Vec2; pub type TextureCoordinate=glam::Vec2;
pub type Color4=glam::Vec4; pub type Color4=glam::Vec4;
#[derive(Clone,Hash,PartialEq,Eq)] #[derive(Clone,Hash,PartialEq,Eq)]
@ -99,6 +99,7 @@ pub struct ContactingLadder{
pub enum ContactingBehaviour{ pub enum ContactingBehaviour{
Surf, Surf,
Ladder(ContactingLadder), Ladder(ContactingLadder),
Elastic(u32),//[1/2^32,1] 0=None (elasticity+1)/2^32
} }
//you have this effect while intersecting //you have this effect while intersecting
#[derive(Clone)] #[derive(Clone)]
@ -107,18 +108,37 @@ pub struct IntersectingWater{
pub density:Planar64, pub density:Planar64,
pub current:Planar64Vec3, pub current:Planar64Vec3,
} }
#[derive(Clone)]
pub struct IntersectingAccelerator{
pub acceleration:Planar64Vec3
}
//All models can be given these attributes //All models can be given these attributes
#[derive(Clone)] #[derive(Clone)]
pub struct GameMechanicJumpLimit{ pub struct GameMechanicAccelerator{
pub count:u32, pub acceleration:Planar64Vec3
} }
#[derive(Clone)] #[derive(Clone)]
pub struct GameMechanicBooster{ pub enum GameMechanicBooster{
pub velocity:Planar64Vec3, Affine(Planar64Affine3),//capable of SetVelocity,DotVelocity,normal booster,bouncy part,redirect velocity, and much more
Velocity(Planar64Vec3),//straight up boost velocity adds to your current velocity
Energy{direction:Planar64Vec3,energy:Planar64},//increase energy in direction
}
#[derive(Clone)]
pub enum TrajectoryChoice{
HighArcLongDuration,//underhand lob at target: less horizontal speed and more air time
LowArcShortDuration,//overhand throw at target: more horizontal speed and less air time
}
#[derive(Clone)]
pub enum GameMechanicSetTrajectory{
AirTime(Time),//air time (relative to gravity direction) is invariant across mass and gravity changes
Height(Planar64),//boost height (relative to gravity direction) is invariant across mass and gravity changes
TargetPointTime{//launch on a trajectory that will land at a target point in a set amount of time
target_point:Planar64Vec3,
time:Time,//short time = fast and direct, long time = launch high in the air, negative time = wrong way
},
TrajectoryTargetPoint{//launch at a fixed speed and land at a target point
target_point:Planar64Vec3,
speed:Planar64,//if speed is too low this will fail to reach the target. The closest-passing trajectory will be chosen instead
trajectory_choice:TrajectoryChoice,
},
Velocity(Planar64Vec3),//SetVelocity
DotVelocity{direction:Planar64Vec3,dot:Planar64},//set your velocity in a specific direction without touching other directions
} }
#[derive(Clone)] #[derive(Clone)]
pub enum ZoneBehaviour{ pub enum ZoneBehaviour{
@ -133,10 +153,10 @@ pub struct GameMechanicZone{
pub behaviour:ZoneBehaviour, pub behaviour:ZoneBehaviour,
} }
// enum TrapCondition{ // enum TrapCondition{
// FasterThan(i64), // FasterThan(Planar64),
// SlowerThan(i64), // SlowerThan(Planar64),
// InRange(i64,i64), // InRange(Planar64,Planar64),
// OutsideRange(i64,i64), // OutsideRange(Planar64,Planar64),
// } // }
#[derive(Clone)] #[derive(Clone)]
pub enum StageElementBehaviour{ pub enum StageElementBehaviour{
@ -145,6 +165,7 @@ pub enum StageElementBehaviour{
Trigger, Trigger,
Teleport, Teleport,
Platform, Platform,
JumpLimit(u32),
//Speedtrap(TrapCondition),//Acts as a trigger with a speed condition //Speedtrap(TrapCondition),//Acts as a trigger with a speed condition
} }
#[derive(Clone)] #[derive(Clone)]
@ -167,23 +188,42 @@ pub enum TeleportBehaviour{
StageElement(GameMechanicStageElement), StageElement(GameMechanicStageElement),
Wormhole(GameMechanicWormhole), Wormhole(GameMechanicWormhole),
} }
//attributes listed in order of handling
#[derive(Default,Clone)] #[derive(Default,Clone)]
pub struct GameMechanicAttributes{ pub struct GameMechanicAttributes{
pub jump_limit:Option<GameMechanicJumpLimit>,
pub booster:Option<GameMechanicBooster>,
pub zone:Option<GameMechanicZone>, pub zone:Option<GameMechanicZone>,
pub booster:Option<GameMechanicBooster>,
pub trajectory:Option<GameMechanicSetTrajectory>,
pub teleport_behaviour:Option<TeleportBehaviour>, pub teleport_behaviour:Option<TeleportBehaviour>,
pub accelerator:Option<GameMechanicAccelerator>,
}
impl GameMechanicAttributes{
pub fn any(&self)->bool{
self.booster.is_some()
||self.trajectory.is_some()
||self.zone.is_some()
||self.teleport_behaviour.is_some()
||self.accelerator.is_some()
}
} }
#[derive(Default,Clone)] #[derive(Default,Clone)]
pub struct ContactingAttributes{ pub struct ContactingAttributes{
pub elasticity:Option<u32>,//[1/2^32,1] 0=None (elasticity+1)/2^32
//friction? //friction?
pub contact_behaviour:Option<ContactingBehaviour>, pub contact_behaviour:Option<ContactingBehaviour>,
} }
impl ContactingAttributes{
pub fn any(&self)->bool{
self.contact_behaviour.is_some()
}
}
#[derive(Default,Clone)] #[derive(Default,Clone)]
pub struct IntersectingAttributes{ pub struct IntersectingAttributes{
pub water:Option<IntersectingWater>, pub water:Option<IntersectingWater>,
pub accelerator:Option<IntersectingAccelerator>, }
impl IntersectingAttributes{
pub fn any(&self)->bool{
self.water.is_some()
}
} }
//Spawn(u32) NO! spawns are indexed in the map header instead of marked with attibutes //Spawn(u32) NO! spawns are indexed in the map header instead of marked with attibutes
pub enum CollisionAttributes{ pub enum CollisionAttributes{

View File

@ -1313,12 +1313,18 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
let model=c.model(&self.models).unwrap(); let model=c.model(&self.models).unwrap();
match &model.attributes{ match &model.attributes{
PhysicsCollisionAttributes::Contact{contacting,general}=>{ PhysicsCollisionAttributes::Contact{contacting,general}=>{
let mut v=self.body.velocity;
match &contacting.contact_behaviour{ match &contacting.contact_behaviour{
Some(crate::model::ContactingBehaviour::Surf)=>println!("I'm surfing!"), Some(crate::model::ContactingBehaviour::Surf)=>println!("I'm surfing!"),
&Some(crate::model::ContactingBehaviour::Elastic(elasticity))=>{
let n=c.normal(&self.models);
let d=n.dot(v)*Planar64::raw(-1-elasticity as i64);
v-=n*(d/n.dot(n));
},
Some(crate::model::ContactingBehaviour::Ladder(contacting_ladder))=>{ Some(crate::model::ContactingBehaviour::Ladder(contacting_ladder))=>{
if contacting_ladder.sticky{ if contacting_ladder.sticky{
//kill v //kill v
self.body.velocity=Planar64Vec3::ZERO;//model.velocity v=Planar64Vec3::ZERO;//model.velocity
} }
//ladder walkstate //ladder walkstate
let (walk_state,a)=WalkState::ladder(&self.touching,&self.body,&self.style,&self.models,self.style.get_ladder_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time),&c.normal(&self.models)); let (walk_state,a)=WalkState::ladder(&self.touching,&self.body,&self.style,&self.models,self.style.get_ladder_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time),&c.normal(&self.models));
@ -1342,7 +1348,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
if stage_element.force||self.game.stage_id<stage_element.stage_id{ if stage_element.force||self.game.stage_id<stage_element.stage_id{
self.game.stage_id=stage_element.stage_id; self.game.stage_id=stage_element.stage_id;
} }
match stage_element.behaviour{ match &stage_element.behaviour{
crate::model::StageElementBehaviour::SpawnAt=>(), crate::model::StageElementBehaviour::SpawnAt=>(),
crate::model::StageElementBehaviour::Trigger crate::model::StageElementBehaviour::Trigger
|crate::model::StageElementBehaviour::Teleport=>{ |crate::model::StageElementBehaviour::Teleport=>{
@ -1360,6 +1366,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
}else{println!("bad3");} }else{println!("bad3");}
}, },
crate::model::StageElementBehaviour::Platform=>(), crate::model::StageElementBehaviour::Platform=>(),
crate::model::StageElementBehaviour::JumpLimit(_)=>(),//TODO
} }
}, },
Some(crate::model::TeleportBehaviour::Wormhole(wormhole))=>{ Some(crate::model::TeleportBehaviour::Wormhole(wormhole))=>{
@ -1368,11 +1375,28 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
None=>(), None=>(),
} }
//flatten v //flatten v
let mut v=self.body.velocity;
self.touching.constrain_velocity(&self.models,&mut v); self.touching.constrain_velocity(&self.models,&mut v);
match &general.booster{ match &general.booster{
Some(booster)=>{ Some(booster)=>{
v+=booster.velocity; match booster{
&crate::model::GameMechanicBooster::Affine(transform)=>v=transform.transform_point3(v),
&crate::model::GameMechanicBooster::Velocity(velocity)=>v+=velocity,
&crate::model::GameMechanicBooster::Energy{direction,energy}=>todo!(),
}
self.touching.constrain_velocity(&self.models,&mut v);
},
None=>(),
}
match &general.trajectory{
Some(trajectory)=>{
match trajectory{
crate::model::GameMechanicSetTrajectory::AirTime(_) => todo!(),
crate::model::GameMechanicSetTrajectory::Height(_) => todo!(),
crate::model::GameMechanicSetTrajectory::TargetPointTime { target_point, time } => todo!(),
crate::model::GameMechanicSetTrajectory::TrajectoryTargetPoint { target_point, speed, trajectory_choice } => todo!(),
&crate::model::GameMechanicSetTrajectory::Velocity(velocity)=>v=velocity,
crate::model::GameMechanicSetTrajectory::DotVelocity { direction, dot } => todo!(),
}
self.touching.constrain_velocity(&self.models,&mut v); self.touching.constrain_velocity(&self.models,&mut v);
}, },
None=>(), None=>(),
@ -1391,7 +1415,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
if stage_element.force||self.game.stage_id<stage_element.stage_id{ if stage_element.force||self.game.stage_id<stage_element.stage_id{
self.game.stage_id=stage_element.stage_id; self.game.stage_id=stage_element.stage_id;
} }
match stage_element.behaviour{ match &stage_element.behaviour{
crate::model::StageElementBehaviour::SpawnAt=>(), crate::model::StageElementBehaviour::SpawnAt=>(),
crate::model::StageElementBehaviour::Trigger crate::model::StageElementBehaviour::Trigger
|crate::model::StageElementBehaviour::Teleport=>{ |crate::model::StageElementBehaviour::Teleport=>{
@ -1409,6 +1433,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
}else{println!("bad3");} }else{println!("bad3");}
}, },
crate::model::StageElementBehaviour::Platform=>(), crate::model::StageElementBehaviour::Platform=>(),
crate::model::StageElementBehaviour::JumpLimit(_)=>(),//TODO
} }
}, },
Some(crate::model::TeleportBehaviour::Wormhole(wormhole))=>{ Some(crate::model::TeleportBehaviour::Wormhole(wormhole))=>{