forked from StrafesNET/strafe-client
physics: refactor models and attributes with type safety
make invalid states unrepresentable!!!
This commit is contained in:
parent
5e45753756
commit
d3f84c2dbd
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -1900,9 +1900,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strafesnet_bsp_loader"
|
name = "strafesnet_bsp_loader"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||||
checksum = "b6b3e1324034abfd648e339580989f8f2c30ac2009296229349d88b8fcb4eedd"
|
checksum = "35ee2c534efa039ad17ca41893ba1d75fafff014076353ac676c73fc808b9e44"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glam",
|
"glam",
|
||||||
"strafesnet_common",
|
"strafesnet_common",
|
||||||
@ -1912,9 +1912,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strafesnet_common"
|
name = "strafesnet_common"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||||
checksum = "1077d45a0b064964906a57de765a5a2bfe47b41f2f807d13b18c70765e76d3dd"
|
checksum = "ea4126f6fbf9aecf89c9e319290f0221d177dcaa8659b4b9e3d82acc37829f12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
@ -1924,9 +1924,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strafesnet_deferred_loader"
|
name = "strafesnet_deferred_loader"
|
||||||
version = "0.3.2"
|
version = "0.3.3"
|
||||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||||
checksum = "9d5ad437524fb201fd5be68f76c53dd831e81ccad4655e19e3d1ca201863b566"
|
checksum = "596aba6d2747818781336ad95a1ee496e37f70052fd625a299fc7a555a6938d4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy-regex",
|
"lazy-regex",
|
||||||
"strafesnet_common",
|
"strafesnet_common",
|
||||||
@ -1935,9 +1935,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strafesnet_rbx_loader"
|
name = "strafesnet_rbx_loader"
|
||||||
version = "0.3.3"
|
version = "0.3.4"
|
||||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||||
checksum = "3a910867e1f5ab2d9cc9c178973aee7fa029547e27465e47fea2eb99b860bb81"
|
checksum = "6cd7fb0eca01ccd382067924e5fad15844f55a6bcc7c14c0e57a171298263a3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"glam",
|
"glam",
|
||||||
@ -1952,9 +1952,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strafesnet_snf"
|
name = "strafesnet_snf"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||||
checksum = "d12fc351b2af5fd7a8183175d55ac43e21eb8fd1f76cc70cd4713c0d1a556c96"
|
checksum = "a9ae481152d0389be29967e1d5f0377498df8ff9638175d56cd8e2c2e6982bfa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"binrw 0.14.0",
|
"binrw 0.14.0",
|
||||||
"id",
|
"id",
|
||||||
|
@ -23,7 +23,7 @@ id = { version = "0.1.0", registry = "strafesnet" }
|
|||||||
parking_lot = "0.12.1"
|
parking_lot = "0.12.1"
|
||||||
pollster = "0.3.0"
|
pollster = "0.3.0"
|
||||||
strafesnet_bsp_loader = { version = "0.1.3", registry = "strafesnet", optional = true }
|
strafesnet_bsp_loader = { version = "0.1.3", registry = "strafesnet", optional = true }
|
||||||
strafesnet_common = { version = "0.3.0", registry = "strafesnet" }
|
strafesnet_common = { version = "0.4.0", registry = "strafesnet" }
|
||||||
strafesnet_deferred_loader = { version = "0.3.1", features = ["legacy"], registry = "strafesnet", optional = true }
|
strafesnet_deferred_loader = { version = "0.3.1", features = ["legacy"], registry = "strafesnet", optional = true }
|
||||||
strafesnet_rbx_loader = { version = "0.3.2", registry = "strafesnet", optional = true }
|
strafesnet_rbx_loader = { version = "0.3.2", registry = "strafesnet", optional = true }
|
||||||
strafesnet_snf = { version = "0.1.2", registry = "strafesnet", optional = true }
|
strafesnet_snf = { version = "0.1.2", registry = "strafesnet", optional = true }
|
||||||
|
426
src/physics.rs
426
src/physics.rs
@ -189,33 +189,69 @@ fn ladder_things(ladder_settings:&gameplay_style::LadderSettings,contact:&Contac
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct PhysicsModels{
|
struct PhysicsModels{
|
||||||
meshes:HashMap<PhysicsMeshId,PhysicsMesh>,
|
meshes:HashMap<PhysicsMeshId,PhysicsMesh>,
|
||||||
models:HashMap<PhysicsModelId,PhysicsModel>,
|
contact_models:HashMap<ContactModelId,ContactModel>,
|
||||||
//separate models into Contacting and Intersecting?
|
intersect_models:HashMap<IntersectModelId,IntersectModel>,
|
||||||
//wrap model id with ContactingModelId and IntersectingModelId
|
contact_attributes:HashMap<ContactAttributesId,gameplay_attributes::ContactAttributes>,
|
||||||
//attributes can be split into contacting and intersecting (this also saves a bit of memory)
|
intersect_attributes:HashMap<IntersectAttributesId,gameplay_attributes::IntersectAttributes>,
|
||||||
//can go even further and deduplicate General attributes separately, reconstructing it when queried
|
|
||||||
attributes:HashMap<PhysicsAttributesId,PhysicsCollisionAttributes>,
|
|
||||||
}
|
}
|
||||||
impl PhysicsModels{
|
impl PhysicsModels{
|
||||||
fn clear(&mut self){
|
fn clear(&mut self){
|
||||||
self.meshes.clear();
|
self.meshes.clear();
|
||||||
self.models.clear();
|
self.contact_models.clear();
|
||||||
self.attributes.clear();
|
self.intersect_models.clear();
|
||||||
|
self.contact_attributes.clear();
|
||||||
|
self.intersect_attributes.clear();
|
||||||
}
|
}
|
||||||
//TODO: "statically" verify the maps don't refer to any nonexistant data, if they do delete the references.
|
|
||||||
//then I can make these getter functions unchecked.
|
|
||||||
fn mesh(&self,convex_mesh_id:ConvexMeshId)->TransformedMesh{
|
fn mesh(&self,convex_mesh_id:ConvexMeshId)->TransformedMesh{
|
||||||
let model=&self.models[&convex_mesh_id.model_id];
|
let (mesh_id,transform)=match convex_mesh_id.model_id{
|
||||||
|
PhysicsModelId::Contact(model_id)=>{
|
||||||
|
let model=&self.contact_models[&model_id];
|
||||||
|
(&model.mesh_id,&model.transform)
|
||||||
|
},
|
||||||
|
PhysicsModelId::Intersect(model_id)=>{
|
||||||
|
let model=&self.intersect_models[&model_id];
|
||||||
|
(&model.mesh_id,&model.transform)
|
||||||
|
},
|
||||||
|
};
|
||||||
TransformedMesh::new(
|
TransformedMesh::new(
|
||||||
self.meshes[&model.mesh_id].submesh_view(convex_mesh_id.submesh_id),
|
self.meshes[mesh_id].submesh_view(convex_mesh_id.submesh_id),
|
||||||
|
transform
|
||||||
|
)
|
||||||
|
}
|
||||||
|
//it's a bit weird to have three functions, but it's always going to be one of these
|
||||||
|
fn contact_mesh(&self,contact:&ContactCollision)->TransformedMesh{
|
||||||
|
let model=&self.contact_models[&contact.model_id];
|
||||||
|
TransformedMesh::new(
|
||||||
|
self.meshes[&model.mesh_id].submesh_view(contact.submesh_id),
|
||||||
&model.transform
|
&model.transform
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn model(&self,model_id:PhysicsModelId)->&PhysicsModel{
|
fn intersect_mesh(&self,intersect:&IntersectCollision)->TransformedMesh{
|
||||||
&self.models[&model_id]
|
let model=&self.intersect_models[&intersect.model_id];
|
||||||
|
TransformedMesh::new(
|
||||||
|
self.meshes[&model.mesh_id].submesh_view(intersect.submesh_id),
|
||||||
|
&model.transform
|
||||||
|
)
|
||||||
}
|
}
|
||||||
fn attr(&self,model_id:PhysicsModelId)->&PhysicsCollisionAttributes{
|
fn get_model_transform(&self,model_id:ModelId)->Option<&PhysicsMeshTransform>{
|
||||||
&self.attributes[&self.models[&model_id].attr_id]
|
//ModelId can possibly be a decoration
|
||||||
|
self.contact_models.get(&ContactModelId::new(model_id.get())).map_or_else(
|
||||||
|
||self.intersect_models.get(&IntersectModelId::new(model_id.get()))
|
||||||
|
.map(|model|&model.transform),
|
||||||
|
|model|Some(&model.transform)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn contact_model(&self,model_id:ContactModelId)->&ContactModel{
|
||||||
|
&self.contact_models[&model_id]
|
||||||
|
}
|
||||||
|
fn intersect_model(&self,model_id:IntersectModelId)->&IntersectModel{
|
||||||
|
&self.intersect_models[&model_id]
|
||||||
|
}
|
||||||
|
fn contact_attr(&self,model_id:ContactModelId)->&gameplay_attributes::ContactAttributes{
|
||||||
|
&self.contact_attributes[&self.contact_models[&model_id].attr_id]
|
||||||
|
}
|
||||||
|
fn intersect_attr(&self,model_id:IntersectModelId)->&gameplay_attributes::IntersectAttributes{
|
||||||
|
&self.intersect_attributes[&self.intersect_models[&model_id].attr_id]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,14 +596,8 @@ impl PhysicsOutputState{
|
|||||||
|
|
||||||
#[derive(Clone,Hash,Eq,PartialEq)]
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
||||||
enum PhysicsCollisionAttributes{
|
enum PhysicsCollisionAttributes{
|
||||||
Contact{//track whether you are contacting the object
|
Contact(gameplay_attributes::ContactAttributes),
|
||||||
contacting:gameplay_attributes::ContactingAttributes,
|
Intersect(gameplay_attributes::IntersectAttributes),
|
||||||
general:gameplay_attributes::GeneralAttributes,
|
|
||||||
},
|
|
||||||
Intersect{//track whether you are intersecting the object
|
|
||||||
intersecting:gameplay_attributes::IntersectingAttributes,
|
|
||||||
general:gameplay_attributes::GeneralAttributes,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
struct NonPhysicsError;
|
struct NonPhysicsError;
|
||||||
impl TryFrom<&gameplay_attributes::CollisionAttributes> for PhysicsCollisionAttributes{
|
impl TryFrom<&gameplay_attributes::CollisionAttributes> for PhysicsCollisionAttributes{
|
||||||
@ -575,85 +605,100 @@ impl TryFrom<&gameplay_attributes::CollisionAttributes> for PhysicsCollisionAttr
|
|||||||
fn try_from(value:&gameplay_attributes::CollisionAttributes)->Result<Self,Self::Error>{
|
fn try_from(value:&gameplay_attributes::CollisionAttributes)->Result<Self,Self::Error>{
|
||||||
match value{
|
match value{
|
||||||
gameplay_attributes::CollisionAttributes::Decoration=>Err(NonPhysicsError),
|
gameplay_attributes::CollisionAttributes::Decoration=>Err(NonPhysicsError),
|
||||||
gameplay_attributes::CollisionAttributes::Contact{contacting,general}=>Ok(Self::Contact{contacting:contacting.clone(),general:general.clone()}),
|
gameplay_attributes::CollisionAttributes::Contact(attr)=>Ok(Self::Contact(attr.clone())),
|
||||||
gameplay_attributes::CollisionAttributes::Intersect{intersecting,general}=>Ok(Self::Intersect{intersecting:intersecting.clone(),general:general.clone()}),
|
gameplay_attributes::CollisionAttributes::Intersect(attr)=>Ok(Self::Intersect(attr.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||||
struct PhysicsAttributesId(u32);
|
struct ContactAttributesId(u32);
|
||||||
impl Into<CollisionAttributesId> for PhysicsAttributesId{
|
impl Into<CollisionAttributesId> for ContactAttributesId{
|
||||||
fn into(self)->CollisionAttributesId{
|
fn into(self)->CollisionAttributesId{
|
||||||
CollisionAttributesId::new(self.0)
|
CollisionAttributesId::new(self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<CollisionAttributesId> for PhysicsAttributesId{
|
impl From<CollisionAttributesId> for ContactAttributesId{
|
||||||
fn from(value:CollisionAttributesId)->Self{
|
fn from(value:CollisionAttributesId)->Self{
|
||||||
Self::new(value.get())
|
Self::new(value.get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||||
|
struct IntersectAttributesId(u32);
|
||||||
|
impl Into<CollisionAttributesId> for IntersectAttributesId{
|
||||||
|
fn into(self)->CollisionAttributesId{
|
||||||
|
CollisionAttributesId::new(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<CollisionAttributesId> for IntersectAttributesId{
|
||||||
|
fn from(value:CollisionAttributesId)->Self{
|
||||||
|
Self::new(value.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||||
|
struct ContactModelId(u32);
|
||||||
|
impl Into<ModelId> for ContactModelId{
|
||||||
|
fn into(self)->ModelId{
|
||||||
|
ModelId::new(self.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||||
|
struct IntersectModelId(u32);
|
||||||
|
impl Into<ModelId> for IntersectModelId{
|
||||||
|
fn into(self)->ModelId{
|
||||||
|
ModelId::new(self.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
|
||||||
|
enum PhysicsModelId{
|
||||||
|
Contact(ContactModelId),
|
||||||
|
Intersect(IntersectModelId),
|
||||||
|
}
|
||||||
|
impl Into<ModelId> for PhysicsModelId{
|
||||||
|
fn into(self)->ModelId{
|
||||||
|
ModelId::new(match self{
|
||||||
|
PhysicsModelId::Contact(model_id)=>model_id.get(),
|
||||||
|
PhysicsModelId::Intersect(model_id)=>model_id.get(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
//unique physics meshes indexed by this
|
//unique physics meshes indexed by this
|
||||||
#[derive(Debug,Default,Clone,Copy,Eq,Hash,PartialEq)]
|
#[derive(Debug,Clone,Copy,Eq,Hash,PartialEq)]
|
||||||
struct ConvexMeshId{
|
struct ConvexMeshId{
|
||||||
model_id:PhysicsModelId,
|
model_id:PhysicsModelId,
|
||||||
submesh_id:PhysicsSubmeshId,
|
submesh_id:PhysicsSubmeshId,
|
||||||
}
|
}
|
||||||
#[derive(Debug,Default,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
struct ContactModel{
|
||||||
struct PhysicsModelId(u32);
|
|
||||||
impl Into<ModelId> for PhysicsModelId{
|
|
||||||
fn into(self)->ModelId{
|
|
||||||
ModelId::new(self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<ModelId> for PhysicsModelId{
|
|
||||||
fn from(value:ModelId)->Self{
|
|
||||||
Self::new(value.get())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct PhysicsModel{
|
|
||||||
//A model is a thing that has a hitbox. can be represented by a list of TreyMesh-es
|
|
||||||
//in this iteration, all it needs is extents.
|
|
||||||
mesh_id:PhysicsMeshId,
|
mesh_id:PhysicsMeshId,
|
||||||
//put these up on the Model (data normalization)
|
attr_id:ContactAttributesId,
|
||||||
attr_id:PhysicsAttributesId,
|
transform:PhysicsMeshTransform,
|
||||||
|
}
|
||||||
|
struct IntersectModel{
|
||||||
|
mesh_id:PhysicsMeshId,
|
||||||
|
attr_id:IntersectAttributesId,
|
||||||
transform:PhysicsMeshTransform,
|
transform:PhysicsMeshTransform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PhysicsModel{
|
|
||||||
const fn new(mesh_id:PhysicsMeshId,attr_id:PhysicsAttributesId,transform:PhysicsMeshTransform)->Self{
|
|
||||||
Self{
|
|
||||||
mesh_id,
|
|
||||||
attr_id,
|
|
||||||
transform,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug,Clone,Copy,Eq,Hash,PartialEq)]
|
#[derive(Debug,Clone,Copy,Eq,Hash,PartialEq)]
|
||||||
pub struct ContactCollision{
|
struct ContactCollision{
|
||||||
face_id:model_physics::MinkowskiFace,
|
face_id:model_physics::MinkowskiFace,
|
||||||
convex_mesh_id:ConvexMeshId,
|
model_id:ContactModelId,
|
||||||
|
submesh_id:PhysicsSubmeshId,
|
||||||
}
|
}
|
||||||
#[derive(Debug,Clone,Copy,Eq,Hash,PartialEq)]
|
#[derive(Debug,Clone,Copy,Eq,Hash,PartialEq)]
|
||||||
pub struct IntersectCollision{
|
struct IntersectCollision{
|
||||||
convex_mesh_id:ConvexMeshId,
|
model_id:IntersectModelId,
|
||||||
|
submesh_id:PhysicsSubmeshId,
|
||||||
}
|
}
|
||||||
#[derive(Debug,Clone,Eq,Hash,PartialEq)]
|
#[derive(Debug,Clone,Eq,Hash,PartialEq)]
|
||||||
pub enum Collision{
|
enum Collision{
|
||||||
Contact(ContactCollision),
|
Contact(ContactCollision),
|
||||||
Intersect(IntersectCollision),
|
Intersect(IntersectCollision),
|
||||||
}
|
}
|
||||||
impl Collision{
|
impl Collision{
|
||||||
const fn convex_mesh_id(&self)->ConvexMeshId{
|
const fn new(convex_mesh_id:ConvexMeshId,face_id:model_physics::MinkowskiFace)->Self{
|
||||||
match self{
|
match convex_mesh_id.model_id{
|
||||||
&Collision::Contact(ContactCollision{convex_mesh_id,face_id:_})
|
PhysicsModelId::Contact(model_id)=>Collision::Contact(ContactCollision{model_id,submesh_id:convex_mesh_id.submesh_id,face_id}),
|
||||||
|&Collision::Intersect(IntersectCollision{convex_mesh_id})=>convex_mesh_id,
|
PhysicsModelId::Intersect(model_id)=>Collision::Intersect(IntersectCollision{model_id,submesh_id:convex_mesh_id.submesh_id}),
|
||||||
}
|
|
||||||
}
|
|
||||||
const fn face_id(&self)->Option<model_physics::MinkowskiFace>{
|
|
||||||
match self{
|
|
||||||
&Collision::Contact(ContactCollision{convex_mesh_id:_,face_id})=>Some(face_id),
|
|
||||||
&Collision::Intersect(IntersectCollision{convex_mesh_id:_})=>None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -686,25 +731,13 @@ impl TouchingState{
|
|||||||
}
|
}
|
||||||
//add accelerators
|
//add accelerators
|
||||||
for contact in &self.contacts{
|
for contact in &self.contacts{
|
||||||
match models.attr(contact.convex_mesh_id.model_id){
|
if let Some(accelerator)=&models.contact_attr(contact.model_id).general.accelerator{
|
||||||
PhysicsCollisionAttributes::Contact{contacting:_,general}=>{
|
a+=accelerator.acceleration;
|
||||||
match &general.accelerator{
|
|
||||||
Some(accelerator)=>a+=accelerator.acceleration,
|
|
||||||
None=>(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_=>panic!("impossible touching state"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for intersect in &self.intersects{
|
for intersect in &self.intersects{
|
||||||
match models.attr(intersect.convex_mesh_id.model_id){
|
if let Some(accelerator)=&models.intersect_attr(intersect.model_id).general.accelerator{
|
||||||
PhysicsCollisionAttributes::Intersect{intersecting:_,general}=>{
|
a+=accelerator.acceleration;
|
||||||
match &general.accelerator{
|
|
||||||
Some(accelerator)=>a+=accelerator.acceleration,
|
|
||||||
None=>(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_=>panic!("impossible touching state"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: add water
|
//TODO: add water
|
||||||
@ -734,26 +767,26 @@ impl TouchingState{
|
|||||||
let relative_body=VirtualBody::relative(&Body::default(),body).body(time);
|
let relative_body=VirtualBody::relative(&Body::default(),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.mesh(contact.convex_mesh_id);
|
let model_mesh=models.contact_mesh(contact);
|
||||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
||||||
collector.collect(minkowski.predict_collision_face_out(&relative_body,collector.time(),contact.face_id).map(|(_face,time)|{
|
collector.collect(minkowski.predict_collision_face_out(&relative_body,collector.time(),contact.face_id).map(|(_face,time)|{
|
||||||
TimedInstruction{
|
TimedInstruction{
|
||||||
time,
|
time,
|
||||||
instruction:PhysicsInternalInstruction::CollisionEnd(
|
instruction:PhysicsInternalInstruction::CollisionEnd(
|
||||||
Collision::Contact(ContactCollision{convex_mesh_id:contact.convex_mesh_id,face_id:contact.face_id})
|
Collision::Contact(*contact)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
for intersect in &self.intersects{
|
for intersect in &self.intersects{
|
||||||
//detect model collision in reverse
|
//detect model collision in reverse
|
||||||
let model_mesh=models.mesh(intersect.convex_mesh_id);
|
let model_mesh=models.intersect_mesh(intersect);
|
||||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
||||||
collector.collect(minkowski.predict_collision_out(&relative_body,collector.time()).map(|(_face,time)|{
|
collector.collect(minkowski.predict_collision_out(&relative_body,collector.time()).map(|(_face,time)|{
|
||||||
TimedInstruction{
|
TimedInstruction{
|
||||||
time,
|
time,
|
||||||
instruction:PhysicsInternalInstruction::CollisionEnd(
|
instruction:PhysicsInternalInstruction::CollisionEnd(
|
||||||
Collision::Intersect(IntersectCollision{convex_mesh_id:intersect.convex_mesh_id})
|
Collision::Intersect(*intersect)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@ -1020,15 +1053,27 @@ impl PhysicsContext{
|
|||||||
/// use with caution, this is the only non-instruction way to mess with physics
|
/// use with caution, this is the only non-instruction way to mess with physics
|
||||||
pub fn generate_models(&mut self,map:&map::CompleteMap){
|
pub fn generate_models(&mut self,map:&map::CompleteMap){
|
||||||
self.state.clear();
|
self.state.clear();
|
||||||
self.data.modes=map.modes.clone();
|
let mut modes=map.modes.clone();
|
||||||
for mode in &mut self.data.modes.modes{
|
for mode in &mut modes.modes{
|
||||||
mode.denormalize_data();
|
mode.denormalize_data();
|
||||||
}
|
}
|
||||||
let mut used_attributes=Vec::new();
|
let mut used_contact_attributes=Vec::new();
|
||||||
|
let mut used_intersect_attributes=Vec::new();
|
||||||
|
|
||||||
|
//temporary type for type safety lol
|
||||||
|
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||||
|
enum PhysicsAttributesId{
|
||||||
|
Contact(ContactAttributesId),
|
||||||
|
Intersect(IntersectAttributesId),
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut contact_models=HashMap::new();
|
||||||
|
let mut intersect_models=HashMap::new();
|
||||||
|
|
||||||
let mut physics_attr_id_from_model_attr_id=HashMap::<CollisionAttributesId,PhysicsAttributesId>::new();
|
let mut physics_attr_id_from_model_attr_id=HashMap::<CollisionAttributesId,PhysicsAttributesId>::new();
|
||||||
let mut used_meshes=Vec::new();
|
let mut used_meshes=Vec::new();
|
||||||
let mut physics_mesh_id_from_model_mesh_id=HashMap::<MeshId,PhysicsMeshId>::new();
|
let mut physics_mesh_id_from_model_mesh_id=HashMap::<MeshId,PhysicsMeshId>::new();
|
||||||
self.data.models.models=map.models.iter().enumerate().filter_map(|(model_id,model)|{
|
for (model_id,model) in map.models.iter().enumerate(){
|
||||||
//TODO: use .entry().or_insert_with(||{
|
//TODO: use .entry().or_insert_with(||{
|
||||||
let attr_id=if let Some(&attr_id)=physics_attr_id_from_model_attr_id.get(&model.attributes){
|
let attr_id=if let Some(&attr_id)=physics_attr_id_from_model_attr_id.get(&model.attributes){
|
||||||
attr_id
|
attr_id
|
||||||
@ -1036,14 +1081,24 @@ impl PhysicsContext{
|
|||||||
//check if it's real
|
//check if it's real
|
||||||
match map.attributes.get(model.attributes.get() as usize).and_then(|m_attr|{
|
match map.attributes.get(model.attributes.get() as usize).and_then(|m_attr|{
|
||||||
PhysicsCollisionAttributes::try_from(m_attr).map_or(None,|p_attr|{
|
PhysicsCollisionAttributes::try_from(m_attr).map_or(None,|p_attr|{
|
||||||
let attr_id=PhysicsAttributesId::new(used_attributes.len() as u32);
|
let attr_id=match p_attr{
|
||||||
used_attributes.push(p_attr);
|
PhysicsCollisionAttributes::Contact(attr)=>{
|
||||||
|
let attr_id=ContactAttributesId::new(used_contact_attributes.len() as u32);
|
||||||
|
used_contact_attributes.push(attr);
|
||||||
|
PhysicsAttributesId::Contact(attr_id)
|
||||||
|
},
|
||||||
|
PhysicsCollisionAttributes::Intersect(attr)=>{
|
||||||
|
let attr_id=IntersectAttributesId::new(used_intersect_attributes.len() as u32);
|
||||||
|
used_intersect_attributes.push(attr);
|
||||||
|
PhysicsAttributesId::Intersect(attr_id)
|
||||||
|
},
|
||||||
|
};
|
||||||
physics_attr_id_from_model_attr_id.insert(model.attributes,attr_id);
|
physics_attr_id_from_model_attr_id.insert(model.attributes,attr_id);
|
||||||
Some(attr_id)
|
Some(attr_id)
|
||||||
})
|
})
|
||||||
}){
|
}){
|
||||||
Some(attr_id)=>attr_id,
|
Some(attr_id)=>attr_id,
|
||||||
None=>return None,
|
None=>continue,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mesh_id=if let Some(&mesh_id)=physics_mesh_id_from_model_mesh_id.get(&model.mesh){
|
let mesh_id=if let Some(&mesh_id)=physics_mesh_id_from_model_mesh_id.get(&model.mesh){
|
||||||
@ -1064,19 +1119,44 @@ impl PhysicsContext{
|
|||||||
}
|
}
|
||||||
}){
|
}){
|
||||||
Some(mesh_id)=>mesh_id,
|
Some(mesh_id)=>mesh_id,
|
||||||
None=>return None,
|
None=>continue,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some((PhysicsModelId::new(model_id as u32),PhysicsModel::new(mesh_id,attr_id,PhysicsMeshTransform::new(model.transform))))
|
let transform=PhysicsMeshTransform::new(model.transform);
|
||||||
}).collect();
|
match attr_id{
|
||||||
self.data.models.attributes=used_attributes.into_iter().enumerate().map(|(attr_id,attr)|(PhysicsAttributesId::new(attr_id as u32),attr)).collect();
|
PhysicsAttributesId::Contact(attr_id)=>{
|
||||||
self.data.models.meshes=used_meshes.into_iter().enumerate().map(|(mesh_id,mesh)|(PhysicsMeshId::new(mesh_id as u32),mesh)).collect();
|
contact_models.insert(ContactModelId::new(model_id as u32),ContactModel{
|
||||||
let convex_mesh_aabb_list=self.data.models.models.iter()
|
mesh_id,
|
||||||
.flat_map(|(&model_id,model)|{
|
attr_id,
|
||||||
self.data.models.meshes[&model.mesh_id].submesh_views()
|
transform,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
PhysicsAttributesId::Intersect(attr_id)=>{
|
||||||
|
intersect_models.insert(IntersectModelId::new(model_id as u32),IntersectModel{
|
||||||
|
mesh_id,
|
||||||
|
attr_id,
|
||||||
|
transform,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let meshes:HashMap<PhysicsMeshId,PhysicsMesh>=used_meshes.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(mesh_id,mesh)|
|
||||||
|
(PhysicsMeshId::new(mesh_id as u32),mesh)
|
||||||
|
).collect();
|
||||||
|
let convex_mesh_aabb_list=
|
||||||
|
//map the two lists into a single type so they can be processed with one closure
|
||||||
|
contact_models.iter().map(|(&model_id,model)|
|
||||||
|
(PhysicsModelId::Contact(model_id),&model.mesh_id,&model.transform)
|
||||||
|
).chain(intersect_models.iter().map(|(&model_id,model)|
|
||||||
|
(PhysicsModelId::Intersect(model_id),&model.mesh_id,&model.transform)
|
||||||
|
))
|
||||||
|
.flat_map(|(model_id,mesh_id,transform)|{
|
||||||
|
meshes[mesh_id].submesh_views()
|
||||||
.enumerate().map(move|(submesh_id,view)|{
|
.enumerate().map(move|(submesh_id,view)|{
|
||||||
let mut aabb=aabb::Aabb::default();
|
let mut aabb=aabb::Aabb::default();
|
||||||
let transformed_mesh=TransformedMesh::new(view,&model.transform);
|
let transformed_mesh=TransformedMesh::new(view,transform);
|
||||||
for v in transformed_mesh.verts(){
|
for v in transformed_mesh.verts(){
|
||||||
aabb.grow(v);
|
aabb.grow(v);
|
||||||
}
|
}
|
||||||
@ -1086,8 +1166,28 @@ impl PhysicsContext{
|
|||||||
},aabb)
|
},aabb)
|
||||||
})
|
})
|
||||||
}).collect();
|
}).collect();
|
||||||
self.data.bvh=bvh::generate_bvh(convex_mesh_aabb_list);
|
let bvh=bvh::generate_bvh(convex_mesh_aabb_list);
|
||||||
println!("Physics Objects: {}",self.data.models.models.len());
|
let model_count=contact_models.len()+intersect_models.len();
|
||||||
|
let models=PhysicsModels{
|
||||||
|
meshes,
|
||||||
|
contact_models,
|
||||||
|
intersect_models,
|
||||||
|
contact_attributes:used_contact_attributes.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(attr_id,attr)|
|
||||||
|
(ContactAttributesId::new(attr_id as u32),attr)
|
||||||
|
).collect(),
|
||||||
|
intersect_attributes:used_intersect_attributes.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(attr_id,attr)|
|
||||||
|
(IntersectAttributesId::new(attr_id as u32),attr)
|
||||||
|
).collect(),
|
||||||
|
};
|
||||||
|
self.data.bvh=bvh;
|
||||||
|
self.data.models=models;
|
||||||
|
self.data.modes=modes;
|
||||||
|
//hitbox_mesh is unchanged
|
||||||
|
println!("Physics Objects: {}",model_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
//tickless gaming
|
//tickless gaming
|
||||||
@ -1134,19 +1234,22 @@ impl PhysicsContext{
|
|||||||
collector.collect(minkowski.predict_collision_in(relative_body,collector.time())
|
collector.collect(minkowski.predict_collision_in(relative_body,collector.time())
|
||||||
//temp (?) code to avoid collision loops
|
//temp (?) code to avoid collision loops
|
||||||
.map_or(None,|(face,time)|if time<=state.time{None}else{Some((face,time))})
|
.map_or(None,|(face,time)|if time<=state.time{None}else{Some((face,time))})
|
||||||
.map(|(face,time)|{
|
.map(|(face,time)|
|
||||||
TimedInstruction{time,instruction:PhysicsInternalInstruction::CollisionStart(match data.models.attr(convex_mesh_id.model_id){
|
TimedInstruction{
|
||||||
PhysicsCollisionAttributes::Contact{contacting:_,general:_}=>Collision::Contact(ContactCollision{convex_mesh_id,face_id:face}),
|
time,
|
||||||
PhysicsCollisionAttributes::Intersect{intersecting:_,general:_}=>Collision::Intersect(IntersectCollision{convex_mesh_id}),
|
instruction:PhysicsInternalInstruction::CollisionStart(
|
||||||
})}
|
Collision::new(convex_mesh_id,face)
|
||||||
}));
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
collector.instruction()
|
collector.instruction()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn contact_normal(models:&PhysicsModels,hitbox_mesh:&HitboxMesh,contact:&ContactCollision)->Planar64Vec3{
|
fn contact_normal(models:&PhysicsModels,hitbox_mesh:&HitboxMesh,contact:&ContactCollision)->Planar64Vec3{
|
||||||
let model_mesh=models.mesh(contact.convex_mesh_id);
|
let model_mesh=models.contact_mesh(contact);
|
||||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
||||||
minkowski.face_nd(contact.face_id).0
|
minkowski.face_nd(contact.face_id).0
|
||||||
}
|
}
|
||||||
@ -1206,16 +1309,26 @@ fn teleport(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,sty
|
|||||||
MoveState::Air
|
MoveState::Air
|
||||||
}
|
}
|
||||||
fn teleport_to_spawn(body:&mut Body,touching:&mut TouchingState,style:&StyleModifiers,hitbox_mesh:&HitboxMesh,mode:&gameplay_modes::Mode,models:&PhysicsModels,stage_id:gameplay_modes::StageId)->Option<MoveState>{
|
fn teleport_to_spawn(body:&mut Body,touching:&mut TouchingState,style:&StyleModifiers,hitbox_mesh:&HitboxMesh,mode:&gameplay_modes::Mode,models:&PhysicsModels,stage_id:gameplay_modes::StageId)->Option<MoveState>{
|
||||||
let model=models.model(mode.get_spawn_model_id(stage_id)?.into());
|
let transform=models.get_model_transform(mode.get_spawn_model_id(stage_id)?)?;
|
||||||
let point=model.transform.vertex.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(style.hitbox.halfsize.y()+Planar64::ONE/16);
|
let point=transform.vertex.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(style.hitbox.halfsize.y()+Planar64::ONE/16);
|
||||||
Some(teleport(body,touching,models,style,hitbox_mesh,point))
|
Some(teleport(body,touching,models,style,hitbox_mesh,point))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_teleport_behaviour(wormhole:&Option<gameplay_attributes::Wormhole>,models:&PhysicsModels,mode:&gameplay_modes::Mode,style:&StyleModifiers,hitbox_mesh:&HitboxMesh,mode_state:&mut ModeState,touching:&mut TouchingState,body:&mut Body,convex_mesh_id:ConvexMeshId)->Option<MoveState>{
|
fn run_teleport_behaviour(
|
||||||
|
wormhole:&Option<gameplay_attributes::Wormhole>,
|
||||||
|
models:&PhysicsModels,
|
||||||
|
mode:&gameplay_modes::Mode,
|
||||||
|
style:&StyleModifiers,
|
||||||
|
hitbox_mesh:&HitboxMesh,
|
||||||
|
mode_state:&mut ModeState,
|
||||||
|
touching:&mut TouchingState,
|
||||||
|
body:&mut Body,
|
||||||
|
model_id:ModelId,
|
||||||
|
)->Option<MoveState>{
|
||||||
//TODO: jump count and checkpoints are always reset on teleport.
|
//TODO: jump count and checkpoints are always reset on teleport.
|
||||||
//Map makers are expected to use tools to prevent
|
//Map makers are expected to use tools to prevent
|
||||||
//multi-boosting on JumpLimit boosters such as spawning into a SetVelocity
|
//multi-boosting on JumpLimit boosters such as spawning into a SetVelocity
|
||||||
if let Some(stage_element)=mode.get_element(convex_mesh_id.model_id.into()){
|
if let Some(stage_element)=mode.get_element(model_id){
|
||||||
if let Some(stage)=mode.get_stage(stage_element.stage_id()){
|
if let Some(stage)=mode.get_stage(stage_element.stage_id()){
|
||||||
if mode_state.get_stage_id()<stage_element.stage_id(){
|
if mode_state.get_stage_id()<stage_element.stage_id(){
|
||||||
//checkpoint check
|
//checkpoint check
|
||||||
@ -1253,19 +1366,19 @@ fn run_teleport_behaviour(wormhole:&Option<gameplay_attributes::Wormhole>,models
|
|||||||
gameplay_modes::StageElementBehaviour::Checkpoint=>{
|
gameplay_modes::StageElementBehaviour::Checkpoint=>{
|
||||||
//each of these checks if the model is actually a valid respective checkpoint object
|
//each of these checks if the model is actually a valid respective checkpoint object
|
||||||
//accumulate sequential ordered checkpoints
|
//accumulate sequential ordered checkpoints
|
||||||
mode_state.accumulate_ordered_checkpoint(&stage,convex_mesh_id.model_id.into());
|
mode_state.accumulate_ordered_checkpoint(&stage,model_id);
|
||||||
//insert model id in accumulated unordered checkpoints
|
//insert model id in accumulated unordered checkpoints
|
||||||
mode_state.accumulate_unordered_checkpoint(&stage,convex_mesh_id.model_id.into());
|
mode_state.accumulate_unordered_checkpoint(&stage,model_id);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match wormhole{
|
match wormhole{
|
||||||
&Some(gameplay_attributes::Wormhole{destination_model})=>{
|
&Some(gameplay_attributes::Wormhole{destination_model})=>{
|
||||||
let origin_model=models.model(convex_mesh_id.model_id);
|
let origin=models.get_model_transform(model_id)?;
|
||||||
let destination_model=models.model(destination_model.into());
|
let destination=models.get_model_transform(destination_model)?;
|
||||||
//ignore the transform for now
|
//ignore the transform for now
|
||||||
Some(teleport(body,touching,models,style,hitbox_mesh,body.position-origin_model.transform.vertex.translation+destination_model.transform.vertex.translation))
|
Some(teleport(body,touching,models,style,hitbox_mesh,body.position-origin.vertex.translation+destination.vertex.translation))
|
||||||
}
|
}
|
||||||
None=>None,
|
None=>None,
|
||||||
}
|
}
|
||||||
@ -1274,8 +1387,7 @@ fn run_teleport_behaviour(wormhole:&Option<gameplay_attributes::Wormhole>,models
|
|||||||
fn collision_start_contact(
|
fn collision_start_contact(
|
||||||
state:&mut PhysicsState,
|
state:&mut PhysicsState,
|
||||||
data:&PhysicsData,
|
data:&PhysicsData,
|
||||||
contacting:&gameplay_attributes::ContactingAttributes,
|
attr:&gameplay_attributes::ContactAttributes,
|
||||||
general:&gameplay_attributes::GeneralAttributes,
|
|
||||||
contact:ContactCollision,
|
contact:ContactCollision,
|
||||||
){
|
){
|
||||||
let incident_velocity=state.body.velocity;
|
let incident_velocity=state.body.velocity;
|
||||||
@ -1283,7 +1395,7 @@ fn collision_start_contact(
|
|||||||
state.touching.insert(Collision::Contact(contact));
|
state.touching.insert(Collision::Contact(contact));
|
||||||
//clip v
|
//clip v
|
||||||
set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,incident_velocity);
|
set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,incident_velocity);
|
||||||
match &contacting.contact_behaviour{
|
match &attr.contacting.contact_behaviour{
|
||||||
Some(gameplay_attributes::ContactingBehaviour::Surf)=>println!("I'm surfing!"),
|
Some(gameplay_attributes::ContactingBehaviour::Surf)=>println!("I'm surfing!"),
|
||||||
Some(gameplay_attributes::ContactingBehaviour::Cling)=>println!("Unimplemented!"),
|
Some(gameplay_attributes::ContactingBehaviour::Cling)=>println!("Unimplemented!"),
|
||||||
&Some(gameplay_attributes::ContactingBehaviour::Elastic(elasticity))=>{
|
&Some(gameplay_attributes::ContactingBehaviour::Elastic(elasticity))=>{
|
||||||
@ -1315,16 +1427,16 @@ fn collision_start_contact(
|
|||||||
}
|
}
|
||||||
//I love making functions with 10 arguments to dodge the borrow checker
|
//I love making functions with 10 arguments to dodge the borrow checker
|
||||||
if let Some(mode)=data.modes.get_mode(state.mode_state.get_mode_id()){
|
if let Some(mode)=data.modes.get_mode(state.mode_state.get_mode_id()){
|
||||||
run_teleport_behaviour(&general.wormhole,&data.models,mode,&state.style,&data.hitbox_mesh,&mut state.mode_state,&mut state.touching,&mut state.body,contact.convex_mesh_id);
|
run_teleport_behaviour(&attr.general.wormhole,&data.models,mode,&state.style,&data.hitbox_mesh,&mut state.mode_state,&mut state.touching,&mut state.body,contact.model_id.into());
|
||||||
}
|
}
|
||||||
if state.style.get_control(Controls::Jump,state.input_state.controls){
|
if state.style.get_control(Controls::Jump,state.input_state.controls){
|
||||||
if let (Some(jump_settings),Some(walk_state))=(&state.style.jump,state.move_state.get_walk_state()){
|
if let (Some(jump_settings),Some(walk_state))=(&state.style.jump,state.move_state.get_walk_state()){
|
||||||
let jump_dir=walk_state.jump_direction.direction(&data.models,&data.hitbox_mesh,&walk_state.contact);
|
let jump_dir=walk_state.jump_direction.direction(&data.models,&data.hitbox_mesh,&walk_state.contact);
|
||||||
let jumped_velocity=jump_settings.jumped_velocity(&state.style,jump_dir,state.body.velocity,general.booster.as_ref());
|
let jumped_velocity=jump_settings.jumped_velocity(&state.style,jump_dir,state.body.velocity,attr.general.booster.as_ref());
|
||||||
state.cull_velocity(data,jumped_velocity);
|
state.cull_velocity(data,jumped_velocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match &general.trajectory{
|
match &attr.general.trajectory{
|
||||||
Some(trajectory)=>{
|
Some(trajectory)=>{
|
||||||
match trajectory{
|
match trajectory{
|
||||||
gameplay_attributes::SetTrajectory::AirTime(_)=>todo!(),
|
gameplay_attributes::SetTrajectory::AirTime(_)=>todo!(),
|
||||||
@ -1347,18 +1459,17 @@ fn collision_start_contact(
|
|||||||
fn collision_start_intersect(
|
fn collision_start_intersect(
|
||||||
state:&mut PhysicsState,
|
state:&mut PhysicsState,
|
||||||
data:&PhysicsData,
|
data:&PhysicsData,
|
||||||
intersecting:&gameplay_attributes::IntersectingAttributes,
|
attr:&gameplay_attributes::IntersectAttributes,
|
||||||
general:&gameplay_attributes::GeneralAttributes,
|
|
||||||
intersect:IntersectCollision,
|
intersect:IntersectCollision,
|
||||||
){
|
){
|
||||||
//I think that setting the velocity to 0 was preventing surface contacts from entering an infinite loop
|
//I think that setting the velocity to 0 was preventing surface contacts from entering an infinite loop
|
||||||
state.touching.insert(Collision::Intersect(intersect));
|
state.touching.insert(Collision::Intersect(intersect));
|
||||||
//insta booster!
|
//insta booster!
|
||||||
if let Some(booster)=&general.booster{
|
if let Some(booster)=&attr.general.booster{
|
||||||
state.cull_velocity(data,booster.boost(state.body.velocity));
|
state.cull_velocity(data,booster.boost(state.body.velocity));
|
||||||
}
|
}
|
||||||
if let Some(mode)=data.modes.get_mode(state.mode_state.get_mode_id()){
|
if let Some(mode)=data.modes.get_mode(state.mode_state.get_mode_id()){
|
||||||
let zone=mode.get_zone(intersect.convex_mesh_id.model_id.into());
|
let zone=mode.get_zone(intersect.model_id.into());
|
||||||
match zone{
|
match zone{
|
||||||
Some(gameplay_modes::Zone::Start)=>{
|
Some(gameplay_modes::Zone::Start)=>{
|
||||||
println!("@@@@ Starting new run!");
|
println!("@@@@ Starting new run!");
|
||||||
@ -1373,15 +1484,14 @@ fn collision_start_intersect(
|
|||||||
Some(gameplay_modes::Zone::Anticheat)=>state.run.flag(run::FlagReason::Anticheat),
|
Some(gameplay_modes::Zone::Anticheat)=>state.run.flag(run::FlagReason::Anticheat),
|
||||||
None=>(),
|
None=>(),
|
||||||
}
|
}
|
||||||
run_teleport_behaviour(&general.wormhole,&data.models,mode,&state.style,&data.hitbox_mesh,&mut state.mode_state,&mut state.touching,&mut state.body,intersect.convex_mesh_id);
|
run_teleport_behaviour(&attr.general.wormhole,&data.models,mode,&state.style,&data.hitbox_mesh,&mut state.mode_state,&mut state.touching,&mut state.body,intersect.model_id.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collision_end_contact(
|
fn collision_end_contact(
|
||||||
state:&mut PhysicsState,
|
state:&mut PhysicsState,
|
||||||
data:&PhysicsData,
|
data:&PhysicsData,
|
||||||
_contacting:&gameplay_attributes::ContactingAttributes,
|
_attr:&gameplay_attributes::ContactAttributes,
|
||||||
_general:&gameplay_attributes::GeneralAttributes,
|
|
||||||
contact:ContactCollision,
|
contact:ContactCollision,
|
||||||
){
|
){
|
||||||
state.touching.remove(&Collision::Contact(contact));//remove contact before calling contact_constrain_acceleration
|
state.touching.remove(&Collision::Contact(contact));//remove contact before calling contact_constrain_acceleration
|
||||||
@ -1399,13 +1509,12 @@ fn collision_end_contact(
|
|||||||
fn collision_end_intersect(
|
fn collision_end_intersect(
|
||||||
state:&mut PhysicsState,
|
state:&mut PhysicsState,
|
||||||
data:&PhysicsData,
|
data:&PhysicsData,
|
||||||
_intersecting:&gameplay_attributes::IntersectingAttributes,
|
_attr:&gameplay_attributes::IntersectAttributes,
|
||||||
_general:&gameplay_attributes::GeneralAttributes,
|
|
||||||
intersect:IntersectCollision,
|
intersect:IntersectCollision,
|
||||||
){
|
){
|
||||||
state.touching.remove(&Collision::Intersect(intersect));
|
state.touching.remove(&Collision::Intersect(intersect));
|
||||||
if let Some(mode)=data.modes.get_mode(state.mode_state.get_mode_id()){
|
if let Some(mode)=data.modes.get_mode(state.mode_state.get_mode_id()){
|
||||||
let zone=mode.get_zone(intersect.convex_mesh_id.model_id.into());
|
let zone=mode.get_zone(intersect.model_id.into());
|
||||||
match zone{
|
match zone{
|
||||||
Some(gameplay_modes::Zone::Start)=>{
|
Some(gameplay_modes::Zone::Start)=>{
|
||||||
match state.run.start(state.time){
|
match state.run.start(state.time){
|
||||||
@ -1429,23 +1538,13 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim
|
|||||||
state.body.advance_time(state.time);
|
state.body.advance_time(state.time);
|
||||||
}
|
}
|
||||||
match ins.instruction{
|
match ins.instruction{
|
||||||
PhysicsInternalInstruction::CollisionStart(collision)=>{
|
PhysicsInternalInstruction::CollisionStart(collision)=>match collision{
|
||||||
match (data.models.attr(collision.convex_mesh_id().model_id),&collision){
|
Collision::Contact(contact)=>collision_start_contact(state,data,data.models.contact_attr(contact.model_id),contact),
|
||||||
(PhysicsCollisionAttributes::Contact{contacting,general},&Collision::Contact(contact))=>
|
Collision::Intersect(intersect)=>collision_start_intersect(state,data,data.models.intersect_attr(intersect.model_id),intersect),
|
||||||
collision_start_contact(state,data,contacting,general,contact),
|
|
||||||
(PhysicsCollisionAttributes::Intersect{intersecting,general},&Collision::Intersect(intersect))=>
|
|
||||||
collision_start_intersect(state,data,intersecting,general,intersect),
|
|
||||||
_=>panic!("invalid pair"),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
PhysicsInternalInstruction::CollisionEnd(collision)=>{
|
PhysicsInternalInstruction::CollisionEnd(collision)=>match collision{
|
||||||
match (data.models.attr(collision.convex_mesh_id().model_id),&collision){
|
Collision::Contact(contact)=>collision_end_contact(state,data,data.models.contact_attr(contact.model_id),contact),
|
||||||
(PhysicsCollisionAttributes::Contact{contacting,general},&Collision::Contact(contact))=>
|
Collision::Intersect(intersect)=>collision_end_intersect(state,data,data.models.intersect_attr(intersect.model_id),intersect),
|
||||||
collision_end_contact(state,data,contacting,general,contact),
|
|
||||||
(PhysicsCollisionAttributes::Intersect{intersecting,general},&Collision::Intersect(intersect))=>
|
|
||||||
collision_end_intersect(state,data,intersecting,general,intersect),
|
|
||||||
_=>panic!("invalid pair"),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
PhysicsInternalInstruction::StrafeTick=>{
|
PhysicsInternalInstruction::StrafeTick=>{
|
||||||
//TODO make this less huge
|
//TODO make this less huge
|
||||||
@ -1550,10 +1649,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
|
|||||||
if let Some(walk_state)=state.move_state.get_walk_state(){
|
if let Some(walk_state)=state.move_state.get_walk_state(){
|
||||||
if let Some(jump_settings)=&state.style.jump{
|
if let Some(jump_settings)=&state.style.jump{
|
||||||
let jump_dir=walk_state.jump_direction.direction(&data.models,&data.hitbox_mesh,&walk_state.contact);
|
let jump_dir=walk_state.jump_direction.direction(&data.models,&data.hitbox_mesh,&walk_state.contact);
|
||||||
let booster_option=match data.models.attr(walk_state.contact.convex_mesh_id.model_id){
|
let booster_option=data.models.contact_attr(walk_state.contact.model_id).general.booster.as_ref();
|
||||||
PhysicsCollisionAttributes::Contact{contacting:_,general}=>general.booster.as_ref(),
|
|
||||||
PhysicsCollisionAttributes::Intersect{..}=>None,
|
|
||||||
};
|
|
||||||
let jumped_velocity=jump_settings.jumped_velocity(&state.style,jump_dir,state.body.velocity,booster_option);
|
let jumped_velocity=jump_settings.jumped_velocity(&state.style,jump_dir,state.body.velocity,booster_option);
|
||||||
state.cull_velocity(&data,jumped_velocity);
|
state.cull_velocity(&data,jumped_velocity);
|
||||||
}
|
}
|
||||||
@ -1571,10 +1667,12 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
|
|||||||
},
|
},
|
||||||
PhysicsInputInstruction::Restart=>{
|
PhysicsInputInstruction::Restart=>{
|
||||||
//teleport to start zone
|
//teleport to start zone
|
||||||
let spawn_point=data.modes.get_mode(state.mode_state.get_mode_id()).map(|mode|
|
let spawn_point=data.modes.get_mode(state.mode_state.get_mode_id()).and_then(|mode|
|
||||||
//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.model(mode.get_start().into()).transform.vertex.translation
|
data.models.get_model_transform(mode.get_start().into()).map(|transform|
|
||||||
|
transform.vertex.translation
|
||||||
|
)
|
||||||
).unwrap_or(Planar64Vec3::ZERO);
|
).unwrap_or(Planar64Vec3::ZERO);
|
||||||
set_position(&mut state.body,&mut state.touching,spawn_point);
|
set_position(&mut state.body,&mut state.touching,spawn_point);
|
||||||
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,Planar64Vec3::ZERO);
|
||||||
|
Loading…
Reference in New Issue
Block a user