This commit is contained in:
Quaternions 2024-09-12 12:17:18 -07:00
parent df12b9f126
commit 4f79d6c8bf

View File

@ -11,7 +11,7 @@ use strafesnet_common::gameplay_modes::{self,StageId};
use strafesnet_common::gameplay_style::{self,StyleModifiers}; use strafesnet_common::gameplay_style::{self,StyleModifiers};
use strafesnet_common::controls_bitflag::Controls; use strafesnet_common::controls_bitflag::Controls;
use strafesnet_common::instruction::{self,InstructionEmitter,InstructionConsumer,TimedInstruction}; use strafesnet_common::instruction::{self,InstructionEmitter,InstructionConsumer,TimedInstruction};
use strafesnet_common::integer::{self,Time,Planar64,Planar64Vec3,Planar64Mat3,Angle32,Ratio64Vec2}; use strafesnet_common::integer::{self,vec3,mat3,Time,Planar64,Planar64Vec3,Planar64Mat3,Angle32,Ratio64Vec2};
use gameplay::ModeState; use gameplay::ModeState;
//external influence //external influence
@ -36,7 +36,7 @@ enum PhysicsInstruction{
Input(PhysicsInputInstruction), Input(PhysicsInputInstruction),
} }
#[derive(Clone,Copy,Debug,Default,Hash)] #[derive(Clone,Copy,Debug,Hash)]
pub struct Body{ pub struct Body{
pub position:Planar64Vec3,//I64 where 2^32 = 1 u pub position:Planar64Vec3,//I64 where 2^32 = 1 u
pub velocity:Planar64Vec3,//I64 where 2^32 = 1 u/s pub velocity:Planar64Vec3,//I64 where 2^32 = 1 u/s
@ -124,13 +124,13 @@ struct ContactMoveState{
} }
impl TransientAcceleration{ impl TransientAcceleration{
fn with_target_diff(target_diff:Planar64Vec3,accel:Planar64,time:Time)->Self{ fn with_target_diff(target_diff:Planar64Vec3,accel:Planar64,time:Time)->Self{
if target_diff==Planar64Vec3::ZERO{ if target_diff==vec3::ZERO{
TransientAcceleration::Reached TransientAcceleration::Reached
}else{ }else{
//normal friction acceleration is clippedAcceleration.dot(normal)*friction //normal friction acceleration is clippedAcceleration.dot(normal)*friction
TransientAcceleration::Reachable{ TransientAcceleration::Reachable{
acceleration:target_diff.with_length(accel), acceleration:target_diff.with_length(accel).divide().fix_1(),
time:time+Time::from(target_diff.length()/accel) time:time+Time::from((target_diff.length()/accel).divide().fix_1())
} }
} }
} }
@ -147,7 +147,7 @@ impl TransientAcceleration{
} }
fn acceleration(&self)->Planar64Vec3{ fn acceleration(&self)->Planar64Vec3{
match self{ match self{
TransientAcceleration::Reached=>Planar64Vec3::ZERO, TransientAcceleration::Reached=>vec3::ZERO,
&TransientAcceleration::Reachable{acceleration,time:_}=>acceleration, &TransientAcceleration::Reachable{acceleration,time:_}=>acceleration,
&TransientAcceleration::Unreachable{acceleration}=>acceleration, &TransientAcceleration::Unreachable{acceleration}=>acceleration,
} }
@ -158,7 +158,7 @@ impl ContactMoveState{
Self{ Self{
target:TransientAcceleration::ground(walk_settings,body,gravity,target_velocity), target:TransientAcceleration::ground(walk_settings,body,gravity,target_velocity),
contact, contact,
jump_direction:JumpDirection::Exactly(Planar64Vec3::Y), jump_direction:JumpDirection::Exactly(vec3::Y),
} }
} }
fn ladder(ladder_settings:&gameplay_style::LadderSettings,body:&Body,gravity:Planar64Vec3,target_velocity:Planar64Vec3,contact:ContactCollision)->Self{ fn ladder(ladder_settings:&gameplay_style::LadderSettings,body:&Body,gravity:Planar64Vec3,target_velocity:Planar64Vec3,contact:ContactCollision)->Self{
@ -296,7 +296,7 @@ impl PhysicsCamera{
let ay=Angle32::clamp_from_i64(a.y) let ay=Angle32::clamp_from_i64(a.y)
//clamp to actual vertical cam limit //clamp to actual vertical cam limit
.clamp(Self::ANGLE_PITCH_LOWER_LIMIT,Self::ANGLE_PITCH_UPPER_LIMIT); .clamp(Self::ANGLE_PITCH_LOWER_LIMIT,Self::ANGLE_PITCH_UPPER_LIMIT);
Planar64Mat3::from_rotation_yx(ax,ay) mat3::from_rotation_yx(ax,ay)
} }
fn rotation(&self)->Planar64Mat3{ fn rotation(&self)->Planar64Mat3{
self.get_rotation(self.clamped_mouse_pos) self.get_rotation(self.clamped_mouse_pos)
@ -306,7 +306,7 @@ impl PhysicsCamera{
} }
fn get_rotation_y(&self,mouse_pos_x:i32)->Planar64Mat3{ fn get_rotation_y(&self,mouse_pos_x:i32)->Planar64Mat3{
let ax=-self.sensitivity.x.mul_int(mouse_pos_x as i64); let ax=-self.sensitivity.x.mul_int(mouse_pos_x as i64);
Planar64Mat3::from_rotation_y(Angle32::wrap_from_i64(ax)) mat3::from_rotation_y(Angle32::wrap_from_i64(ax))
} }
fn rotation_y(&self)->Planar64Mat3{ fn rotation_y(&self)->Planar64Mat3{
self.get_rotation_y(self.clamped_mouse_pos.x) self.get_rotation_y(self.clamped_mouse_pos.x)
@ -438,7 +438,7 @@ impl StyleHelper for StyleModifiers{
fn get_control_dir(&self,controls:Controls)->Planar64Vec3{ fn get_control_dir(&self,controls:Controls)->Planar64Vec3{
//don't get fancy just do it //don't get fancy just do it
let mut control_dir:Planar64Vec3 = Planar64Vec3::ZERO; let mut control_dir:Planar64Vec3 = vec3::ZERO;
//Apply mask after held check so you can require non-allowed keys to be held for some reason //Apply mask after held check so you can require non-allowed keys to be held for some reason
let controls=controls.intersection(self.controls_mask); let controls=controls.intersection(self.controls_mask);
if controls.contains(Controls::MoveForward){ if controls.contains(Controls::MoveForward){
@ -463,19 +463,19 @@ impl StyleHelper for StyleModifiers{
} }
fn get_y_control_dir(&self,camera:&PhysicsCamera,controls:Controls)->Planar64Vec3{ fn get_y_control_dir(&self,camera:&PhysicsCamera,controls:Controls)->Planar64Vec3{
camera.rotation_y()*self.get_control_dir(controls) (camera.rotation_y()*self.get_control_dir(controls)).fix_1()
} }
fn get_propulsion_control_dir(&self,camera:&PhysicsCamera,controls:Controls)->Planar64Vec3{ fn get_propulsion_control_dir(&self,camera:&PhysicsCamera,controls:Controls)->Planar64Vec3{
//don't interpolate this! discrete mouse movement, constant acceleration //don't interpolate this! discrete mouse movement, constant acceleration
camera.rotation()*self.get_control_dir(controls) (camera.rotation()*self.get_control_dir(controls)).fix_1()
} }
fn calculate_mesh(&self)->HitboxMesh{ fn calculate_mesh(&self)->HitboxMesh{
let mesh=match self.hitbox.mesh{ let mesh=match self.hitbox.mesh{
gameplay_style::HitboxMesh::Box=>PhysicsMesh::unit_cube(), gameplay_style::HitboxMesh::Box=>PhysicsMesh::unit_cube(),
gameplay_style::HitboxMesh::Cylinder=>PhysicsMesh::unit_cylinder(), gameplay_style::HitboxMesh::Cylinder=>PhysicsMesh::unit_cylinder(),
}; };
let transform=Planar64Mat3::from_diagonal(self.hitbox.halfsize).extend(Planar64Vec3::ZERO); let transform=mat3::from_diagonal(self.hitbox.halfsize).extend_column(vec3::ZERO);
HitboxMesh::new(mesh,transform) HitboxMesh::new(mesh,transform)
} }
} }
@ -491,7 +491,7 @@ impl MoveState{
//call this after state.move_state is changed //call this after state.move_state is changed
fn apply_enum(&self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){ fn apply_enum(&self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
match self{ match self{
MoveState::Fly=>body.acceleration=Planar64Vec3::ZERO, MoveState::Fly=>body.acceleration=vec3::ZERO,
MoveState::Air=>{ MoveState::Air=>{
//calculate base acceleration //calculate base acceleration
let a=touching.base_acceleration(models,style,camera,input_state); let a=touching.base_acceleration(models,style,camera,input_state);
@ -766,7 +766,7 @@ impl TouchingState{
let contacts=self.contacts.iter().map(|contact|{ let contacts=self.contacts.iter().map(|contact|{
let n=contact_normal(models,hitbox_mesh,contact); let n=contact_normal(models,hitbox_mesh,contact);
crate::push_solve::Contact{ crate::push_solve::Contact{
position:Planar64Vec3::ZERO, position:vec3::ZERO,
velocity:n, velocity:n,
normal:n, normal:n,
} }
@ -780,7 +780,7 @@ impl TouchingState{
let contacts=self.contacts.iter().map(|contact|{ let contacts=self.contacts.iter().map(|contact|{
let n=contact_normal(models,hitbox_mesh,contact); let n=contact_normal(models,hitbox_mesh,contact);
crate::push_solve::Contact{ crate::push_solve::Contact{
position:Planar64Vec3::ZERO, position:vec3::ZERO,
velocity:n, velocity:n,
normal:n, normal:n,
} }
@ -791,7 +791,7 @@ impl TouchingState{
} }
} }
fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<PhysicsInternalInstruction>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,time:Time){ fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<PhysicsInternalInstruction>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,time:Time){
let relative_body=VirtualBody::relative(&Body::default(),body).body(time); let relative_body=VirtualBody::relative(&Body::ZERO,body).body(time);
for contact in &self.contacts{ for contact in &self.contacts{
//detect face slide off //detect face slide off
let model_mesh=models.contact_mesh(contact); let model_mesh=models.contact_mesh(contact);
@ -822,6 +822,7 @@ impl TouchingState{
} }
impl Body{ impl Body{
pub const ZERO:Self=Self::new(vec3::ZERO,vec3::ZERO,vec3::ZERO,Time::ZERO);
pub const fn new(position:Planar64Vec3,velocity:Planar64Vec3,acceleration:Planar64Vec3,time:Time)->Self{ pub const fn new(position:Planar64Vec3,velocity:Planar64Vec3,acceleration:Planar64Vec3,time:Time)->Self{
Self{ Self{
position, position,
@ -832,11 +833,13 @@ impl Body{
} }
pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{ pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{
let dt=time-self.time; let dt=time-self.time;
self.position+self.velocity*dt+self.acceleration*(dt*dt/2) self.position
+(self.velocity*dt).map(|elem|elem.divide().fix_1())
+self.acceleration.map(|elem|(dt*dt*elem/2).divide().fix_1())
} }
pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{ pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{
let dt=time-self.time; let dt=time-self.time;
self.velocity+self.acceleration*dt self.velocity+(self.acceleration*dt).map(|elem|elem.divide().fix_1())
} }
pub fn advance_time(&mut self,time:Time){ pub fn advance_time(&mut self,time:Time){
self.position=self.extrapolated_position(time); self.position=self.extrapolated_position(time);
@ -844,8 +847,8 @@ impl Body{
self.time=time; self.time=time;
} }
pub fn infinity_dir(&self)->Option<Planar64Vec3>{ pub fn infinity_dir(&self)->Option<Planar64Vec3>{
if self.velocity==Planar64Vec3::ZERO{ if self.velocity==vec3::ZERO{
if self.acceleration==Planar64Vec3::ZERO{ if self.acceleration==vec3::ZERO{
None None
}else{ }else{
Some(self.acceleration) Some(self.acceleration)
@ -859,19 +862,19 @@ impl Body{
aabb.grow(self.extrapolated_position(t1)); aabb.grow(self.extrapolated_position(t1));
//v+a*t==0 //v+a*t==0
//goober code //goober code
if self.acceleration.x!=Planar64::ZERO{ if !self.acceleration.x.is_zero(){
let t=Time::from(-self.velocity.x/self.acceleration.x); let t=Time::from(-self.velocity.x/self.acceleration.x);
if t0<t&&t<t1{ if t0<t&&t<t1{
aabb.grow(self.extrapolated_position(t)); aabb.grow(self.extrapolated_position(t));
} }
} }
if self.acceleration.y!=Planar64::ZERO{ if !self.acceleration.y.is_zero(){
let t=Time::from(-self.velocity.y/self.acceleration.y); let t=Time::from(-self.velocity.y/self.acceleration.y);
if t0<t&&t<t1{ if t0<t&&t<t1{
aabb.grow(self.extrapolated_position(t)); aabb.grow(self.extrapolated_position(t));
} }
} }
if self.acceleration.z!=Planar64::ZERO{ if !self.acceleration.z.is_zero(){
let t=Time::from(-self.velocity.z/self.acceleration.z); let t=Time::from(-self.velocity.z/self.acceleration.z);
if t0<t&&t<t1{ if t0<t&&t<t1{
aabb.grow(self.extrapolated_position(t)); aabb.grow(self.extrapolated_position(t));
@ -947,7 +950,7 @@ pub struct PhysicsData{
impl Default for PhysicsState{ impl Default for PhysicsState{
fn default()->Self{ fn default()->Self{
Self{ Self{
body:Body::new(Planar64Vec3::int(0,50,0),Planar64Vec3::int(0,0,0),Planar64Vec3::int(0,-100,0),Time::ZERO), body:Body::new(vec3::int(0,50,0),vec3::int(0,0,0),vec3::int(0,-100,0),Time::ZERO),
time:Time::ZERO, time:Time::ZERO,
style:StyleModifiers::default(), style:StyleModifiers::default(),
touching:TouchingState::default(), touching:TouchingState::default(),
@ -1339,12 +1342,12 @@ fn set_velocity_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsM
let mut culled=false; let mut culled=false;
touching.contacts.retain(|contact|{ touching.contacts.retain(|contact|{
let n=contact_normal(models,hitbox_mesh,contact); let n=contact_normal(models,hitbox_mesh,contact);
let r=n.dot(v)<=Planar64::ZERO; let r=n.dot(v).is_positive();
if !r{ if r{
culled=true; culled=true;
println!("set_velocity_cull contact={:?}",contact); println!("set_velocity_cull contact={:?}",contact);
} }
r !r
}); });
set_velocity(body,touching,models,hitbox_mesh,v); set_velocity(body,touching,models,hitbox_mesh,v);
culled culled
@ -1358,12 +1361,12 @@ fn set_acceleration_cull(body:&mut Body,touching:&mut TouchingState,models:&Phys
let mut culled=false; let mut culled=false;
touching.contacts.retain(|contact|{ touching.contacts.retain(|contact|{
let n=contact_normal(models,hitbox_mesh,contact); let n=contact_normal(models,hitbox_mesh,contact);
let r=n.dot(a)<=Planar64::ZERO; let r=n.dot(a).is_positive();
if !r{ if r{
culled=true; culled=true;
println!("set_acceleration_cull contact={:?}",contact); println!("set_acceleration_cull contact={:?}",contact);
} }
r !r
}); });
set_acceleration(body,touching,models,hitbox_mesh,a); set_acceleration(body,touching,models,hitbox_mesh,a);
culled culled
@ -1501,7 +1504,7 @@ fn run_teleport_behaviour(
} }
if let Some(&gameplay_attributes::Wormhole{destination_model})=wormhole{ if let Some(&gameplay_attributes::Wormhole{destination_model})=wormhole{
if let (Some(origin),Some(destination))=(models.get_model_transform(model_id),models.get_model_transform(destination_model)){ if let (Some(origin),Some(destination))=(models.get_model_transform(model_id),models.get_model_transform(destination_model)){
let point=body.position-origin.vertex.translation+destination.vertex.translation; let point=body.position-origin.vertex.col(3)+destination.vertex.col(3);
//TODO: camera angles //TODO: camera angles
teleport(point,move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time); teleport(point,move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time);
} }
@ -1543,7 +1546,7 @@ fn collision_start_contact(
//kill v //kill v
//actually you could do this with a booster attribute :thinking: //actually you could do this with a booster attribute :thinking:
//it's a little bit different because maybe you want to chain ladders together //it's a little bit different because maybe you want to chain ladders together
set_velocity(body,touching,models,hitbox_mesh,Planar64Vec3::ZERO);//model.velocity set_velocity(body,touching,models,hitbox_mesh,vec3::ZERO);//model.velocity
} }
//ladder walkstate //ladder walkstate
let (gravity,target_velocity)=ladder_things(ladder_settings,&contact,touching,models,hitbox_mesh,style,camera,input_state); let (gravity,target_velocity)=ladder_things(ladder_settings,&contact,touching,models,hitbox_mesh,style,camera,input_state);
@ -1733,9 +1736,9 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim
if strafe_settings.activates(controls){ if strafe_settings.activates(controls){
let masked_controls=strafe_settings.mask(controls); let masked_controls=strafe_settings.mask(controls);
let control_dir=state.style.get_control_dir(masked_controls); let control_dir=state.style.get_control_dir(masked_controls);
if control_dir!=Planar64Vec3::ZERO{ if control_dir!=vec3::ZERO{
let camera_mat=state.camera.simulate_move_rotation_y(state.input_state.lerp_delta(state.time).x); let camera_mat=state.camera.simulate_move_rotation_y(state.input_state.lerp_delta(state.time).x);
if let Some(ticked_velocity)=strafe_settings.tick_velocity(state.body.velocity,(camera_mat*control_dir).with_length(Planar64::ONE)){ if let Some(ticked_velocity)=strafe_settings.tick_velocity(state.body.velocity,(camera_mat*control_dir).with_length(Planar64::ONE).divide().fix_1()){
//this is wrong but will work ig //this is wrong but will work ig
//need to note which push planes activate in push solve and keep those //need to note which push planes activate in push solve and keep those
state.cull_velocity(data,ticked_velocity); state.cull_velocity(data,ticked_velocity);
@ -1759,7 +1762,7 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim
//we know that the acceleration is precisely zero because the walk target is known to be reachable //we know that the acceleration is precisely zero because the walk target is known to be reachable
//which means that gravity can be fully cancelled //which means that gravity can be fully cancelled
//ignore moving platforms for now //ignore moving platforms for now
set_acceleration(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,Planar64Vec3::ZERO); set_acceleration(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,vec3::ZERO);
walk_state.target=TransientAcceleration::Reached; walk_state.target=TransientAcceleration::Reached;
}, },
//you are not supposed to reach an unreachable walk target! //you are not supposed to reach an unreachable walk target!
@ -1852,11 +1855,11 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
//TODO: spawn at the bottom of the start zone plus the hitbox size //TODO: spawn at the bottom of the start zone plus the hitbox size
//TODO: set camera andles to face the same way as the start zone //TODO: set camera andles to face the same way as the start zone
data.models.get_model_transform(mode.get_start().into()).map(|transform| data.models.get_model_transform(mode.get_start().into()).map(|transform|
transform.vertex.translation transform.vertex.col(3)
) )
).unwrap_or(Planar64Vec3::ZERO); ).unwrap_or(vec3::ZERO);
set_position(spawn_point,&mut state.move_state,&mut state.body,&mut state.touching,&mut state.run,&mut state.mode_state,mode,&data.models,&data.hitbox_mesh,&data.bvh,&state.style,&state.camera,&state.input_state,state.time); set_position(spawn_point,&mut state.move_state,&mut state.body,&mut state.touching,&mut state.run,&mut state.mode_state,mode,&data.models,&data.hitbox_mesh,&data.bvh,&state.style,&state.camera,&state.input_state,state.time);
set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,Planar64Vec3::ZERO); set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,vec3::ZERO);
state.set_move_state(data,MoveState::Air); state.set_move_state(data,MoveState::Air);
b_refresh_walk_target=false; b_refresh_walk_target=false;
} }
@ -1919,9 +1922,10 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
#[cfg(test)] #[cfg(test)]
mod test{ mod test{
use strafesnet_common::integer::{vec3::{self,int as int3},mat3};
use super::*; use super::*;
fn test_collision_axis_aligned(relative_body:Body,expected_collision_time:Option<Time>){ fn test_collision_axis_aligned(relative_body:Body,expected_collision_time:Option<Time>){
let h0=HitboxMesh::new(PhysicsMesh::unit_cube(),integer::Planar64Affine3::new(Planar64Mat3::from_diagonal(Planar64Vec3::int(5,1,5)/2),Planar64Vec3::ZERO)); let h0=HitboxMesh::new(PhysicsMesh::unit_cube(),mat3::from_diagonal(int3(5,1,5)>>1).extend_column(vec3::ZERO));
let h1=StyleModifiers::roblox_bhop().calculate_mesh(); let h1=StyleModifiers::roblox_bhop().calculate_mesh();
let hitbox_mesh=h1.transformed_mesh(); let hitbox_mesh=h1.transformed_mesh();
let platform_mesh=h0.transformed_mesh(); let platform_mesh=h0.transformed_mesh();
@ -1931,14 +1935,11 @@ mod test{
} }
fn test_collision_rotated(relative_body:Body,expected_collision_time:Option<Time>){ fn test_collision_rotated(relative_body:Body,expected_collision_time:Option<Time>){
let h0=HitboxMesh::new(PhysicsMesh::unit_cube(), let h0=HitboxMesh::new(PhysicsMesh::unit_cube(),
integer::Planar64Affine3::new( integer::Planar64Mat3::from_rows([
integer::Planar64Mat3::from_cols( int3(5,0,1)>>1,
Planar64Vec3::int(5,0,1)/2, int3(0,1,0)>>1,
Planar64Vec3::int(0,1,0)/2, int3(-1,0,5)>>1,
Planar64Vec3::int(-1,0,5)/2, ]).extend_column(vec3::ZERO),
),
Planar64Vec3::ZERO,
)
); );
let h1=StyleModifiers::roblox_bhop().calculate_mesh(); let h1=StyleModifiers::roblox_bhop().calculate_mesh();
let hitbox_mesh=h1.transformed_mesh(); let hitbox_mesh=h1.transformed_mesh();
@ -1954,180 +1955,180 @@ mod test{
#[test] #[test]
fn test_collision_degenerate(){ fn test_collision_degenerate(){
test_collision(Body::new( test_collision(Body::new(
Planar64Vec3::int(0,5,0), int3(0,5,0),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Planar64Vec3::ZERO, vec3::ZERO,
Time::ZERO Time::ZERO
),Some(Time::from_secs(2))); ),Some(Time::from_secs(2)));
} }
#[test] #[test]
fn test_collision_degenerate_east(){ fn test_collision_degenerate_east(){
test_collision(Body::new( test_collision(Body::new(
Planar64Vec3::int(3,5,0), int3(3,5,0),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Planar64Vec3::ZERO, vec3::ZERO,
Time::ZERO Time::ZERO
),Some(Time::from_secs(2))); ),Some(Time::from_secs(2)));
} }
#[test] #[test]
fn test_collision_degenerate_south(){ fn test_collision_degenerate_south(){
test_collision(Body::new( test_collision(Body::new(
Planar64Vec3::int(0,5,3), int3(0,5,3),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Planar64Vec3::ZERO, vec3::ZERO,
Time::ZERO Time::ZERO
),Some(Time::from_secs(2))); ),Some(Time::from_secs(2)));
} }
#[test] #[test]
fn test_collision_degenerate_west(){ fn test_collision_degenerate_west(){
test_collision(Body::new( test_collision(Body::new(
Planar64Vec3::int(-3,5,0), int3(-3,5,0),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Planar64Vec3::ZERO, vec3::ZERO,
Time::ZERO Time::ZERO
),Some(Time::from_secs(2))); ),Some(Time::from_secs(2)));
} }
#[test] #[test]
fn test_collision_degenerate_north(){ fn test_collision_degenerate_north(){
test_collision(Body::new( test_collision(Body::new(
Planar64Vec3::int(0,5,-3), int3(0,5,-3),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Planar64Vec3::ZERO, vec3::ZERO,
Time::ZERO Time::ZERO
),Some(Time::from_secs(2))); ),Some(Time::from_secs(2)));
} }
#[test] #[test]
fn test_collision_parabola_edge_east_from_west(){ fn test_collision_parabola_edge_east_from_west(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(3,3,0), int3(3,3,0),
Planar64Vec3::int(100,-1,0), int3(100,-1,0),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_parabola_edge_south_from_north(){ fn test_collision_parabola_edge_south_from_north(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(0,3,3), int3(0,3,3),
Planar64Vec3::int(0,-1,100), int3(0,-1,100),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_parabola_edge_west_from_east(){ fn test_collision_parabola_edge_west_from_east(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(-3,3,0), int3(-3,3,0),
Planar64Vec3::int(-100,-1,0), int3(-100,-1,0),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_parabola_edge_north_from_south(){ fn test_collision_parabola_edge_north_from_south(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(0,3,-3), int3(0,3,-3),
Planar64Vec3::int(0,-1,-100), int3(0,-1,-100),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_parabola_edge_north_from_ne(){ fn test_collision_parabola_edge_north_from_ne(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(0,6,-7)/2, int3(0,6,-7)>>1,
Planar64Vec3::int(-10,-1,1), int3(-10,-1,1),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_parabola_edge_north_from_nw(){ fn test_collision_parabola_edge_north_from_nw(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(0,6,-7)/2, int3(0,6,-7)>>1,
Planar64Vec3::int(10,-1,1), int3(10,-1,1),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_parabola_edge_east_from_se(){ fn test_collision_parabola_edge_east_from_se(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(7,6,0)/2, int3(7,6,0)>>1,
Planar64Vec3::int(-1,-1,-10), int3(-1,-1,-10),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_parabola_edge_east_from_ne(){ fn test_collision_parabola_edge_east_from_ne(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(7,6,0)/2, int3(7,6,0)>>1,
Planar64Vec3::int(-1,-1,10), int3(-1,-1,10),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_parabola_edge_south_from_se(){ fn test_collision_parabola_edge_south_from_se(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(0,6,7)/2, int3(0,6,7)>>1,
Planar64Vec3::int(-10,-1,-1), int3(-10,-1,-1),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_parabola_edge_south_from_sw(){ fn test_collision_parabola_edge_south_from_sw(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(0,6,7)/2, int3(0,6,7)>>1,
Planar64Vec3::int(10,-1,-1), int3(10,-1,-1),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_parabola_edge_west_from_se(){ fn test_collision_parabola_edge_west_from_se(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(-7,6,0)/2, int3(-7,6,0)>>1,
Planar64Vec3::int(1,-1,-10), int3(1,-1,-10),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_parabola_edge_west_from_ne(){ fn test_collision_parabola_edge_west_from_ne(){
test_collision(VirtualBody::relative(&Body::default(),&Body::new( test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
Planar64Vec3::int(-7,6,0)/2, int3(-7,6,0)>>1,
Planar64Vec3::int(1,-1,10), int3(1,-1,10),
Planar64Vec3::int(0,-1,0), int3(0,-1,0),
Time::ZERO Time::ZERO
)).body(Time::from_secs(-1)),Some(Time::from_secs(0))); )).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
} }
#[test] #[test]
fn test_collision_oblique(){ fn test_collision_oblique(){
test_collision(Body::new( test_collision(Body::new(
Planar64Vec3::int(0,5,0), int3(0,5,0),
Planar64Vec3::int(1,-64,2)/64, int3(1,-64,2)>>6,// /64
Planar64Vec3::ZERO, vec3::ZERO,
Time::ZERO Time::ZERO
),Some(Time::from_secs(2))); ),Some(Time::from_secs(2)));
} }
#[test] #[test]
fn zoom_hit_nothing(){ fn zoom_hit_nothing(){
test_collision(Body::new( test_collision(Body::new(
Planar64Vec3::int(0,10,0), int3(0,10,0),
Planar64Vec3::int(1,0,0), int3(1,0,0),
Planar64Vec3::int(0,1,0), int3(0,1,0),
Time::ZERO Time::ZERO
),None); ),None);
} }
#[test] #[test]
fn already_inside_hit_nothing(){ fn already_inside_hit_nothing(){
test_collision(Body::new( test_collision(Body::new(
Planar64Vec3::ZERO, vec3::ZERO,
Planar64Vec3::int(1,0,0), int3(1,0,0),
Planar64Vec3::int(0,1,0), int3(0,1,0),
Time::ZERO Time::ZERO
),None); ),None);
} }