use crate::physics::{
ColliderHandleComponent, EventQueue, UserPhysicsHooks, JointBuilderComponent,
JointHandleComponent, PhysicsInterpolationComponent, RapierConfiguration,
RigidBodyHandleComponent, SimulationToRenderTime,
};
use crate::rapier::pipeline::QueryPipeline;
use rapier::dynamics::{IntegrationParameters, JointSet, RigidBodyBuilder, RigidBodySet};
use rapier::geometry::{BroadPhase, ColliderBuilder, ColliderSet, NarrowPhase};
use rapier::pipeline::PhysicsPipeline;
use shipyard::{
AllStoragesViewMut, EntitiesView, Get, IntoIter, IntoWithId, UniqueView, UniqueViewMut, View,
ViewMut,
};
pub fn setup_physics(all_storages: AllStoragesViewMut) {
all_storages.add_unique(PhysicsPipeline::new());
all_storages.add_unique(QueryPipeline::new());
all_storages.add_unique(RapierConfiguration::default());
all_storages.add_unique(IntegrationParameters::default());
all_storages.add_unique(BroadPhase::new());
all_storages.add_unique(NarrowPhase::new());
all_storages.add_unique(RigidBodySet::new());
all_storages.add_unique(ColliderSet::new());
all_storages.add_unique(JointSet::new());
all_storages.add_unique(UserPhysicsHooks::new());
all_storages.add_unique(EventQueue::new(true));
all_storages.add_unique(SimulationToRenderTime::default());
all_storages
.borrow::<ViewMut<RigidBodyHandleComponent>>()
.unwrap()
.track_deletion();
all_storages
.borrow::<ViewMut<ColliderHandleComponent>>()
.unwrap()
.track_deletion();
all_storages
.borrow::<ViewMut<JointHandleComponent>>()
.unwrap()
.track_deletion();
}
pub fn create_body_and_collider_system(
entities: EntitiesView,
mut bodies: UniqueViewMut<RigidBodySet>,
mut colliders: UniqueViewMut<ColliderSet>,
mut rigid_body_builders: ViewMut<RigidBodyBuilder>,
mut rigid_body_handles: ViewMut<RigidBodyHandleComponent>,
mut collider_builders: ViewMut<ColliderBuilder>,
mut collider_handles: ViewMut<ColliderHandleComponent>,
) {
for (entity_id, body_builder) in rigid_body_builders.iter().with_id() {
let handle = bodies.insert(body_builder.build());
entities.add_component(entity_id, &mut rigid_body_handles, handle.into());
if let Ok(collider_builder) = collider_builders.get(entity_id) {
let collider = collider_builder.build();
let handle = colliders.insert(collider, handle, &mut bodies);
entities.add_component(entity_id, &mut collider_handles, handle.into());
collider_builders.delete(entity_id);
}
}
rigid_body_builders.clear();
}
#[test]
fn test_create_body_and_collider_system() {
use shipyard::*;
let mut world = World::new();
world.add_unique(RigidBodySet::new()).unwrap();
world.add_unique(ColliderSet::new()).unwrap();
let body_and_collider_entity =
world.add_entity((RigidBodyBuilder::new_dynamic(), ColliderBuilder::ball(1.0)));
let body_only_entity = world.add_entity((RigidBodyBuilder::new_static(),));
world.run(create_body_and_collider_system).unwrap();
let body_set = world.borrow::<UniqueView<RigidBodySet>>().unwrap();
let collider_set = world.borrow::<UniqueView<ColliderSet>>().unwrap();
let rigid_bodies_handles = world.borrow::<ViewMut<RigidBodyHandleComponent>>().unwrap();
let colliders_handles = world.borrow::<ViewMut<ColliderHandleComponent>>().unwrap();
let attached_body_handle = rigid_bodies_handles
.get(body_and_collider_entity)
.unwrap()
.handle();
assert!(body_set.get(attached_body_handle).unwrap().is_dynamic());
let collider_handle = colliders_handles
.get(body_and_collider_entity)
.unwrap()
.handle();
let collider = collider_set.get(collider_handle).unwrap();
assert_eq!(attached_body_handle, collider.parent());
assert_eq!(collider.shape().as_ball().unwrap().radius, 1.0);
let standalone_body_handle = rigid_bodies_handles.get(body_only_entity).unwrap().handle();
assert!(body_set.get(standalone_body_handle).unwrap().is_static());
}
pub fn create_joints_system(
entities: EntitiesView,
mut bodies: UniqueViewMut<RigidBodySet>,
mut joints: UniqueViewMut<JointSet>,
mut joint_builders: ViewMut<JointBuilderComponent>,
mut joint_handles: ViewMut<JointHandleComponent>,
bodies_handles: View<RigidBodyHandleComponent>,
) {
for (entity_id, joint_builder) in joint_builders.iter().with_id() {
let body1 = bodies_handles.get(joint_builder.entity1);
let body2 = bodies_handles.get(joint_builder.entity2);
if let (Ok(body1), Ok(body2)) = (body1, body2) {
let handle = joints.insert(
&mut bodies,
body1.handle(),
body2.handle(),
joint_builder.params,
);
entities.add_component(
entity_id,
&mut joint_handles,
JointHandleComponent::new(handle, joint_builder.entity1, joint_builder.entity2),
);
}
}
joint_builders.clear();
}
pub fn step_world_system(
delta_seconds: f32,
mut sim_to_render_time: UniqueViewMut<SimulationToRenderTime>,
(configuration, integration_parameters): (
UniqueView<RapierConfiguration>,
UniqueView<IntegrationParameters>,
),
user_hooks: UniqueView<UserPhysicsHooks>,
(mut pipeline, mut query_pipeline): (
UniqueViewMut<PhysicsPipeline>,
UniqueViewMut<QueryPipeline>,
),
(mut broad_phase, mut narrow_phase): (UniqueViewMut<BroadPhase>, UniqueViewMut<NarrowPhase>),
(mut bodies, mut colliders): (UniqueViewMut<RigidBodySet>, UniqueViewMut<ColliderSet>),
mut joints: UniqueViewMut<JointSet>,
events: UniqueViewMut<EventQueue>,
(rigid_bodies_handles, mut physics_interpolation): (
View<RigidBodyHandleComponent>,
ViewMut<PhysicsInterpolationComponent>,
),
) {
if events.auto_clear {
events.clear();
}
if configuration.time_dependent_number_of_timesteps {
sim_to_render_time.diff += delta_seconds;
let sim_dt = integration_parameters.dt;
while sim_to_render_time.diff >= sim_dt {
if configuration.physics_pipeline_active {
if sim_to_render_time.diff - sim_dt < sim_dt {
for (body_handle, mut previous_state) in
(&rigid_bodies_handles, &mut physics_interpolation).iter()
{
if let Some(body) = bodies.get(body_handle.handle()) {
previous_state.0 = Some(*body.position());
}
}
}
pipeline.step(
&configuration.gravity,
&integration_parameters,
&mut broad_phase,
&mut narrow_phase,
&mut bodies,
&mut colliders,
&mut joints,
&*user_hooks.hooks,
&*events,
);
}
sim_to_render_time.diff -= sim_dt;
}
} else if configuration.physics_pipeline_active {
pipeline.step(
&configuration.gravity,
&integration_parameters,
&mut broad_phase,
&mut narrow_phase,
&mut bodies,
&mut colliders,
&mut joints,
&*user_hooks.hooks,
&*events,
);
}
if configuration.query_pipeline_active {
query_pipeline.update(&mut bodies, &colliders);
}
}
pub fn destroy_body_and_collider_system(
mut bodies: UniqueViewMut<RigidBodySet>,
mut colliders: UniqueViewMut<ColliderSet>,
mut joints: UniqueViewMut<JointSet>,
mut collider_handles: ViewMut<ColliderHandleComponent>,
mut joint_handles: ViewMut<JointHandleComponent>,
mut body_handles: ViewMut<RigidBodyHandleComponent>,
) {
for (entity, body_handle) in body_handles.take_deleted().iter() {
bodies.remove(body_handle.handle(), &mut colliders, &mut joints);
joint_handles.delete(*entity);
collider_handles.delete(*entity);
}
for (_, collider_handle) in collider_handles.take_deleted().iter() {
colliders.remove(collider_handle.handle(), &mut bodies, true);
}
for (_, joint_handle) in joint_handles.take_deleted().iter() {
joints.remove(joint_handle.handle, &mut bodies, true);
}
}