goud_engine/ecs/systems/
physics_sync_3d.rs1use std::collections::HashMap;
24
25use crate::core::providers::physics3d::PhysicsProvider3D;
26use crate::core::providers::types::BodyHandle;
27use crate::ecs::entity::Entity;
28use crate::ecs::query::Access;
29use crate::ecs::system::System;
30use crate::ecs::World;
31
32#[derive(Debug, Default)]
34pub struct PhysicsHandleMap3D {
35 pub entity_to_body: HashMap<Entity, BodyHandle>,
37}
38
39pub struct PhysicsStepSystem3D {
47 provider: Box<dyn PhysicsProvider3D>,
48}
49
50impl PhysicsStepSystem3D {
51 pub fn new(provider: Box<dyn PhysicsProvider3D>) -> Self {
53 Self { provider }
54 }
55
56 pub fn provider(&self) -> &dyn PhysicsProvider3D {
58 &*self.provider
59 }
60
61 pub fn provider_mut(&mut self) -> &mut dyn PhysicsProvider3D {
63 &mut *self.provider
64 }
65}
66
67impl System for PhysicsStepSystem3D {
68 fn name(&self) -> &'static str {
69 "PhysicsStepSystem3D"
70 }
71
72 fn component_access(&self) -> Access {
73 Access::new()
74 }
75
76 fn run(&mut self, world: &mut World) {
77 const FIXED_DT: f32 = 1.0 / 60.0;
78 if let Err(e) = self.provider.step(FIXED_DT) {
79 log::error!("PhysicsStepSystem3D: step failed: {e}");
80 return;
81 }
82
83 let handle_map = match world.get_resource_mut::<PhysicsHandleMap3D>() {
84 Some(map) => map
85 .entity_to_body
86 .iter()
87 .map(|(&entity, &handle)| (entity, handle))
88 .collect::<Vec<_>>(),
89 None => return,
90 };
91
92 for (entity, body_handle) in handle_map {
93 if let Ok(pos) = self.provider.body_position(body_handle) {
94 use crate::core::math::Vec3;
95 use crate::ecs::components::transform::Transform;
96 if let Some(transform) = world.get_mut::<Transform>(entity) {
97 transform.set_position(Vec3::new(pos[0], pos[1], pos[2]));
98 }
99 }
100 }
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use crate::core::providers::impls::NullPhysicsProvider3D;
108
109 #[test]
110 fn test_handle_map_3d_default() {
111 let map = PhysicsHandleMap3D::default();
112 assert!(map.entity_to_body.is_empty());
113 }
114
115 #[test]
116 fn test_system_3d_construction() {
117 let provider = NullPhysicsProvider3D::new();
118 let system = PhysicsStepSystem3D::new(Box::new(provider));
119 assert_eq!(system.name(), "PhysicsStepSystem3D");
120 }
121
122 #[test]
123 fn test_system_3d_run_empty_world() {
124 let provider = NullPhysicsProvider3D::new();
125 let mut system = PhysicsStepSystem3D::new(Box::new(provider));
126 let mut world = World::new();
127 system.run(&mut world);
128 }
129
130 #[test]
131 fn test_system_3d_run_with_empty_handle_map() {
132 let provider = NullPhysicsProvider3D::new();
133 let mut system = PhysicsStepSystem3D::new(Box::new(provider));
134 let mut world = World::new();
135 world.insert_resource(PhysicsHandleMap3D::default());
136 system.run(&mut world);
137 }
138
139 #[test]
140 fn test_system_3d_provider_accessors() {
141 let provider = NullPhysicsProvider3D::new();
142 let mut system = PhysicsStepSystem3D::new(Box::new(provider));
143 assert_eq!(system.provider().name(), "null");
144 assert_eq!(system.provider_mut().gravity(), [0.0, 0.0, 0.0]);
145 }
146
147 #[test]
148 fn test_system_3d_should_run() {
149 let provider = NullPhysicsProvider3D::new();
150 let system = PhysicsStepSystem3D::new(Box::new(provider));
151 let world = World::new();
152 assert!(system.should_run(&world));
153 }
154}