commit e70b07560de2dc0c8ab9f4ea3981341b4d24f008
parent 7fae74c61e3b79da7e8afcd1ed862f408f48d424
Author: Joël Lupien (Jojolepro) <jojolepromain@gmail.com>
Date: Fri, 7 Dec 2018 21:01:42 -0500
Fix Collider bugs and update example.
Diffstat:
6 files changed, 207 insertions(+), 105 deletions(-)
diff --git a/examples/amethyst.rs b/examples/amethyst.rs
@@ -8,9 +8,13 @@ use amethyst::renderer::{
Stage, Texture,
};
use amethyst::{Application, GameData, GameDataBuilder, SimpleState, StateData};
-use nphysics_ecs_dumb::bodies::DynamicBody;
+use nalgebra::Isometry3;
+use nphysics_ecs_dumb::ncollide::shape::{Ball, Cuboid, ShapeHandle};
use nphysics_ecs_dumb::nphysics::math::{Point, Velocity};
-use nphysics_ecs_dumb::systems::PhysicsBundle;
+use nphysics_ecs_dumb::nphysics::object::BodyHandle;
+use nphysics_ecs_dumb::nphysics::object::Material as PhysicsMaterial;
+use nphysics_ecs_dumb::nphysics::volumetric::Volumetric;
+use nphysics_ecs_dumb::*;
use num_traits::identities::One;
struct GameState;
@@ -52,11 +56,11 @@ impl SimpleState for GameState {
.build();
// Add Light
- data.world.add_resource(AmbientColor(Rgba::from([0.5; 3])));
+ data.world.add_resource(AmbientColor(Rgba::from([0.2; 3])));
data.world
.create_entity()
.with(Light::Point(PointLight {
- intensity: 3.0,
+ intensity: 50.0,
color: Rgba::white(),
radius: 5.0,
smoothness: 4.0,
@@ -71,20 +75,79 @@ impl SimpleState for GameState {
&data.world.read_resource(),
);
+ let ball = ShapeHandle::new(Ball::new(1.0));
+
// Add Sphere (todo: add many, add rigidbodies and colliders)
data.world
.create_entity()
- .with(sphere_handle)
- .with(material)
- .with(Transform::from(Vector3::new(0.0, 0.0, -10.0)))
+ .with(sphere_handle.clone())
+ .with(material.clone())
+ .with(Transform::from(Vector3::new(0.0, 3.0, -10.0)))
.with(GlobalTransform::default())
.with(DynamicBody::new_rigidbody_with_velocity(
- Velocity::linear(0.0, 10.0, 0.0),
+ Velocity::linear(0.0, 1.0, 0.0),
10.0,
Matrix3::one(),
- Point::new(0.0, 0.0, 0.0),
+ ball.center_of_mass(),
))
+ .with(
+ ColliderBuilder::from(ball.clone())
+ .collision_group(0)
+ .physics_material(PhysicsMaterial::default())
+ .build()
+ .unwrap(),
+ )
.build();
+
+ // Add ground
+ data.world
+ .create_entity()
+ .with(sphere_handle)
+ .with(material)
+ .with(Transform::from(Vector3::new(0.0, 0.0, -10.0)))
+ .with(GlobalTransform::default())
+ .with(
+ //ColliderBuilder::from(ShapeHandle::new(Cuboid::new(Vector3::new(5.0, 1.0, 5.0))))
+ ColliderBuilder::from(ball)
+ .collision_group(0)
+ .physics_material(PhysicsMaterial::default())
+ .build()
+ .unwrap(),
+ )
+ .build();
+
+ //---------------------------------------------------- nphysics's ball3.rs adapted
+
+ /*let mut physics_world = data.world.write_resource::<PhysicsWorld>();
+ physics_world.set_gravity(Vector3::new(0.0, -9.81, 0.0));
+
+ // Material for all objects.
+ let material = PhysicsMaterial::default();
+ let ground_shape =
+ ShapeHandle::new(Cuboid::new(Vector3::repeat(1.0 - 0.01)));
+ let ground_pos = Isometry3::new(Vector3::new(0.0, -0.5, -15.0), nalgebra::zero());
+
+ physics_world.add_collider(
+ 0.01,
+ ground_shape,
+ BodyHandle::ground(),
+ ground_pos,
+ material.clone(),
+ );
+ let geom = ShapeHandle::new(Ball::new(1.0 - 0.01));
+ let inertia = geom.inertia(1.0);
+ let center_of_mass = geom.center_of_mass();
+
+
+ let pos = Isometry3::new(Vector3::new(0.0, 5.0, -15.0), nalgebra::zero());
+ let handle = physics_world.add_rigid_body(pos, inertia, center_of_mass);
+ physics_world.add_collider(
+ 0.01,
+ geom.clone(),
+ handle,
+ Isometry3::identity(),
+ material.clone(),
+ );*/
}
}
diff --git a/src/colliders.rs b/src/colliders.rs
@@ -31,11 +31,12 @@ impl ColliderType {
}
}
-#[derive(new, Clone, Builder)]
+#[derive(new, Clone, Builder, Debug)]
#[builder(pattern = "owned")]
pub struct Collider {
#[new(default)]
//#[serde(skip)]
+ #[builder(default)]
pub(crate) handle: Option<ColliderHandle>,
/// Warning: Changing the margin after inserting the entity will have no effect.
pub margin: f32,
diff --git a/src/systems/mod.rs b/src/systems/mod.rs
@@ -51,7 +51,7 @@ impl<'a, 'b, 'c> SystemBundle<'a, 'b> for PhysicsBundle<'c> {
builder.add(
SyncCollidersToPhysicsSystem::new(),
SYNC_COLLIDERS_TO_PHYSICS_SYSTEM,
- &[],
+ &[SYNC_BODIES_TO_PHYSICS_SYSTEM],
);
builder.add(
diff --git a/src/systems/sync_bodies_from_physics.rs b/src/systems/sync_bodies_from_physics.rs
@@ -31,7 +31,7 @@ impl<'a> System<'a> for SyncBodiesFromPhysicsSystem {
Write<'a, EventChannel<EntityProximityEvent>>,
WriteStorage<'a, GlobalTransform>,
WriteStorage<'a, DynamicBody>,
- ReadStorage<'a, Transform>,
+ WriteStorage<'a, Transform>,
ReadStorage<'a, Collider>,
);
@@ -43,7 +43,7 @@ impl<'a> System<'a> for SyncBodiesFromPhysicsSystem {
mut proximity_events,
mut global_transforms,
mut physics_bodies,
- local_transforms,
+ mut local_transforms,
colliders,
) = data;
@@ -51,55 +51,83 @@ impl<'a> System<'a> for SyncBodiesFromPhysicsSystem {
// Apply the updated values of the simulated world to our Components
#[allow(unused_mut)]
- for (mut global_transform, mut body, local_transform) in (
+ for (mut global_transform, mut body, mut local_transform) in (
&mut global_transforms,
&mut physics_bodies,
- local_transforms.maybe(),
+ (&mut local_transforms).maybe(),
)
.join()
{
- let updated_body = physical_world.body(body.handle().unwrap());
+ if let Some(updated_body_handle) = body.handle() {
+ let updated_body = physical_world.body(updated_body_handle);
+
+ if updated_body.is_ground() || !updated_body.is_active() || updated_body.is_static()
+ {
+ trace!(
+ "Skipping synchronizing data from non-dynamic body: {:?}",
+ updated_body.handle()
+ );
+ continue;
+ }
- if updated_body.is_ground() || !updated_body.is_active() || updated_body.is_static() {
- trace!("Skipping synchronizing data from non-dynamic body: {:?}", updated_body.handle());
- continue;
- }
+ match (body, updated_body) {
+ (
+ DynamicBody::RigidBody(ref mut rigid_body),
+ Body::RigidBody(ref updated_rigid_body),
+ ) => {
+ trace!(
+ "Synchronizing RigidBody from handle: {:?}",
+ updated_rigid_body.handle()
+ );
- match (body, updated_body) {
- (
- DynamicBody::RigidBody(ref mut rigid_body),
- Body::RigidBody(ref updated_rigid_body),
- ) => {
- trace!("Synchronizing RigidBody from handle: {:?}", updated_rigid_body.handle());
-
- trace!("Synchronized RigidBody's updated position: {}", updated_rigid_body.position());
- // TODO: Might get rid of the scale!!!
- global_transform.0 = updated_rigid_body
- .position()
- .to_homogeneous()
- .prepend_nonuniform_scaling(
- local_transform
- .map(|tr| tr.scale())
- .unwrap_or(&Vector3::new(1.0, 1.0, 1.0)),
+ trace!(
+ "Synchronized RigidBody's updated position: {:?}",
+ updated_rigid_body.position()
);
- trace!("Synchronized RigidBody's updated velocity: {:?}", updated_rigid_body.velocity());
- rigid_body.velocity = *updated_rigid_body.velocity();
+ global_transform.0 = updated_rigid_body
+ .position()
+ .to_homogeneous()
+ .prepend_nonuniform_scaling(
+ &local_transform
+ .as_ref()
+ .map(|tr| *tr.scale())
+ .unwrap_or_else(|| Vector3::new(1.0, 1.0, 1.0)),
+ );
+
+ if let Some(ref mut local_transform) = local_transform {
+ *local_transform.isometry_mut() = updated_rigid_body.position();
+ }
+
+ trace!(
+ "Synchronized RigidBody's updated velocity: {:?}",
+ updated_rigid_body.velocity()
+ );
+ rigid_body.velocity = *updated_rigid_body.velocity();
- trace!("Synchronized RigidBody's updated inertia: {:?}", updated_rigid_body.inertia());
- let inertia = updated_rigid_body.inertia();
- rigid_body.mass = inertia.linear;
- rigid_body.angular_mass = inertia.angular;
+ trace!(
+ "Synchronized RigidBody's updated inertia: {:?}",
+ updated_rigid_body.inertia()
+ );
+ let inertia = updated_rigid_body.inertia();
+ rigid_body.mass = inertia.linear;
+ rigid_body.angular_mass = inertia.angular;
- trace!("Synchronized RigidBody's updated center of mass: {}", updated_rigid_body.center_of_mass());
- rigid_body.center_of_mass = updated_rigid_body.center_of_mass();
- }
- (DynamicBody::Multibody(_multibody), Body::Multibody(_updated_multibody)) => {
- error!("Multibody found; not implemented currently, sorry!")
- }
- // TODO: Add data to unexpected pair message. Not straightforward.
- _ => error!("Unexpected dynamics body pair!"),
- };
+ trace!(
+ "Synchronized RigidBody's updated center of mass: {:?}",
+ updated_rigid_body.center_of_mass()
+ );
+ rigid_body.center_of_mass = updated_rigid_body.center_of_mass();
+ }
+ (DynamicBody::Multibody(_multibody), Body::Multibody(_updated_multibody)) => {
+ error!("Multibody found; not implemented currently, sorry!")
+ }
+ // TODO: Add data to unexpected pair message. Not straightforward.
+ _ => error!("Unexpected dynamics body pair!"),
+ };
+ } else {
+ warn!("Found body in physics world not registered in the ECS world!");
+ }
}
trace!("Iterating collision events.");
@@ -107,16 +135,16 @@ impl<'a> System<'a> for SyncBodiesFromPhysicsSystem {
let collision_world = physical_world.collision_world();
contact_events.iter_write(collision_world.contact_events().iter().cloned().map(|ev| {
- trace!("Emitting contact event: {}", ev);
+ trace!("Emitting contact event: {:?}", ev);
let (handle1, handle2) = match ev {
ContactEvent::Started(h1, h2) => (h1, h2),
ContactEvent::Stopped(h1, h2) => (h1, h2),
};
- let e1 = entity_from_handle(&entities, &colliders, &handle1)
+ let e1 = entity_from_handle(&entities, &colliders, handle1)
.expect("Failed to find entity for collider.");
- let e2 = entity_from_handle(&entities, &colliders, &handle2)
+ let e2 = entity_from_handle(&entities, &colliders, handle2)
.expect("Failed to find entity for collider.");
(e1, e2, ev)
}));
@@ -127,40 +155,29 @@ impl<'a> System<'a> for SyncBodiesFromPhysicsSystem {
.iter()
.cloned()
.map(|ev| {
- trace!("Emitting proximity event: {}", ev);
+ trace!("Emitting proximity event: {:?}", ev);
- let e1 = entity_from_handle(&entities, &colliders, &ev.collider1)
+ let e1 = entity_from_handle(&entities, &colliders, ev.collider1)
.expect("Failed to find entity for collider.");
- let e2 = entity_from_handle(&entities, &colliders, &ev.collider2)
+ let e2 = entity_from_handle(&entities, &colliders, ev.collider2)
.expect("Failed to find entity for collider.");
(e1, e2, ev)
}),
);
-
- // TODO: reader id from other system?
- // Now that we changed them all, let's remove all those pesky events that were generated.
- // global_transforms
- // .channel()
- // .read(&mut self.transforms_reader_id.as_mut().unwrap())
- // .for_each(|_| ());
- // physics_bodies
- // .channel()
- // .read(&mut self.physics_bodies_reader_id.as_mut().unwrap())
- // .for_each(|_| ());
}
}
pub fn entity_from_handle(
entities: &EntitiesRes,
colliders: &ReadStorage<Collider>,
- handle: &ColliderHandle,
+ handle: ColliderHandle,
) -> Option<Entity> {
(&*entities, colliders)
.join()
.find(|(_, c)| {
c.handle
.expect("Collider has no handle and wasn't removed.")
- == *handle
+ == handle
})
.map(|(e, _)| e)
}
diff --git a/src/systems/sync_bodies_to_physics.rs b/src/systems/sync_bodies_to_physics.rs
@@ -8,7 +8,7 @@ use amethyst::ecs::{
};
use core::ops::Deref;
use nalgebra::try_convert;
-use nphysics3d::math::{Inertia, Force, Isometry};
+use nphysics3d::math::{Force, Inertia, Isometry};
#[derive(Default)]
pub struct SyncBodiesToPhysicsSystem {
@@ -115,19 +115,17 @@ impl<'a> System<'a> for SyncBodiesToPhysicsSystem {
trace!("Detected changed dynamics body with id {}", id);
match body {
DynamicBody::RigidBody(ref mut rigid_body) => {
- match physical_world.rigid_body_mut(rigid_body.handle.unwrap()) {
- Some(physical_body) => {
+ if let Some(physical_body) = physical_world.rigid_body_mut(rigid_body.handle.unwrap()) {
let position: Isometry<f32> = try_convert(transform.0).unwrap();
- trace!("Updating rigid body in physics world with isometry: {}", position);
+ trace!(
+ "Updating rigid body in physics world with isometry: {}",
+ position
+ );
physical_body.set_position(position);
physical_body.set_velocity(rigid_body.velocity);
physical_body.apply_force(&rigid_body.external_forces);
// if you changed the mass properties at all... too bad!
- },
- None => {
-
- }
}
}
DynamicBody::Multibody(_) => {
@@ -150,7 +148,7 @@ impl<'a> System<'a> for SyncBodiesToPhysicsSystem {
}
}
-fn iterate_events<'a, T, D, S>(
+fn iterate_events<T, D, S>(
tracked_storage: &Storage<T, D>,
reader: &mut ReaderId<ComponentEvent>,
inserted: &mut BitSet,
diff --git a/src/systems/sync_colliders_to_physics.rs b/src/systems/sync_colliders_to_physics.rs
@@ -1,7 +1,7 @@
use crate::bodies::DynamicBody;
use crate::Collider;
use crate::PhysicsWorld;
-use amethyst::core::GlobalTransform;
+use amethyst::core::Transform;
use amethyst::ecs::storage::{ComponentEvent, GenericReadStorage, MaskedStorage};
use amethyst::ecs::{
BitSet, Component, Entities, Join, ReadStorage, ReaderId, Resources, Storage, System,
@@ -20,7 +20,7 @@ impl<'a> System<'a> for SyncCollidersToPhysicsSystem {
type SystemData = (
WriteExpect<'a, PhysicsWorld>,
Entities<'a>,
- ReadStorage<'a, GlobalTransform>,
+ ReadStorage<'a, Transform>,
ReadStorage<'a, DynamicBody>,
WriteStorage<'a, Collider>,
);
@@ -32,7 +32,7 @@ impl<'a> System<'a> for SyncCollidersToPhysicsSystem {
let mut modified_colliders = BitSet::new();
iterate_events(
- &transforms,
+ &colliders,
self.colliders_reader_id.as_mut().unwrap(),
&mut inserted_colliders,
&mut modified_colliders,
@@ -41,46 +41,47 @@ impl<'a> System<'a> for SyncCollidersToPhysicsSystem {
&colliders,
);
- for (entity, mut collider, id) in (
+ for (entity, mut collider, id, tr) in (
&entities,
&mut colliders,
&inserted_colliders | &modified_colliders,
+ &transforms,
)
.join()
{
if inserted_colliders.contains(id) {
- trace!("Detected inserted collider with id {}", id);
-
+ println!("Detected inserted collider with id {:?}", id);
// Just inserted. Remove old one and insert new.
- if let Some(handle) = collider.handle {
- if physical_world.collider(handle).is_some() {
- trace!("Removing collider marked as inserted that already exists with handle: {:?}", handle);
-
- physical_world.remove_colliders(&[handle]);
- }
+ if collider.handle.is_some()
+ && physical_world.collider(collider.handle.unwrap()).is_some()
+ {
+ physical_world.remove_colliders(&[collider.handle.unwrap()]);
}
let parent = if let Some(rb) = rigid_bodies.get(entity) {
- trace!("Attaching inserted collider to rigid body: {}", entity);
+ trace!("Attaching inserted collider to rigid body: {:?}", entity);
rb.handle().expect(
"You should normally have a body handle at this point. This is a bug.",
)
} else {
- trace!("Attaching inserted collider to ground.");
-
BodyHandle::ground()
};
+ let position = if parent.is_ground() {
+ tr.isometry() * collider.offset_from_parent
+ } else {
+ collider.offset_from_parent
+ };
collider.handle = Some(physical_world.add_collider(
collider.margin,
collider.shape.clone(),
parent,
- collider.offset_from_parent,
+ position,
collider.physics_material.clone(),
));
- trace!("Inserted collider to world with values: {}", collider);
+ trace!("Inserted collider to world with values: {:?}", collider);
let prediction = physical_world.prediction();
let angular_prediction = physical_world.angular_prediction();
@@ -91,15 +92,15 @@ impl<'a> System<'a> for SyncCollidersToPhysicsSystem {
.collision_object_mut(collider.handle.unwrap())
.unwrap();
- let collider_handle = collider_object.handle().clone();
-
- collision_world.set_collision_group(collider_handle, collider.collision_group);
-
collider_object.set_query_type(collider.query_type.to_geometric_query_type(
collider.margin,
prediction,
angular_prediction,
));
+
+ let collider_handle = collider_object.handle();
+
+ collision_world.set_collision_group(collider_handle, collider.collision_group);
} else if modified_colliders.contains(id) || modified_colliders.contains(id) {
println!("Detected changed collider with id {:?}", id);
@@ -110,8 +111,7 @@ impl<'a> System<'a> for SyncCollidersToPhysicsSystem {
let collider_handle = collision_world
.collision_object(collider.handle.unwrap())
.unwrap()
- .handle()
- .clone();
+ .handle();
collision_world.set_collision_group(collider_handle, collider.collision_group);
collision_world.set_shape(collider_handle, collider.shape.clone());
@@ -119,8 +119,26 @@ impl<'a> System<'a> for SyncCollidersToPhysicsSystem {
let collider_object = collision_world
.collision_object_mut(collider.handle.unwrap())
.unwrap();
- //collider_handle.set_shape(collider_handle.shape);
- collider_object.set_position(collider.offset_from_parent.clone());
+
+ let parent = if let Some(rb) = rigid_bodies.get(entity) {
+ trace!("Updating collider to rigid body: {:?}", entity);
+
+ rb.handle().expect(
+ "You should normally have a body handle at this point. This is a bug.",
+ )
+ } else {
+ trace!("Updating collider to ground.");
+
+ BodyHandle::ground()
+ };
+
+ let position = if parent.is_ground() {
+ tr.isometry() * collider.offset_from_parent
+ } else {
+ collider.offset_from_parent
+ };
+
+ collider_object.set_position(position);
collider_object.set_query_type(collider.query_type.to_geometric_query_type(
collider.margin,
prediction,
@@ -131,6 +149,11 @@ impl<'a> System<'a> for SyncCollidersToPhysicsSystem {
.set_material(collider.physics_material.clone());
}
}
+
+ colliders
+ .channel()
+ .read(&mut self.colliders_reader_id.as_mut().unwrap())
+ .for_each(|_| ());
}
fn setup(&mut self, res: &mut Resources) {
@@ -141,7 +164,7 @@ impl<'a> System<'a> for SyncCollidersToPhysicsSystem {
}
}
-fn iterate_events<'a, T, D, S>(
+fn iterate_events<T, D, S>(
tracked_storage: &Storage<T, D>,
reader: &mut ReaderId<ComponentEvent>,
inserted: &mut BitSet,