goud_engine/ecs/systems/
physics_sync_2d.rs1use std::collections::HashMap;
23
24use crate::core::providers::physics::PhysicsProvider;
25use crate::core::providers::types::BodyHandle;
26use crate::ecs::entity::Entity;
27use crate::ecs::query::Access;
28use crate::ecs::system::System;
29use crate::ecs::World;
30
31#[derive(Debug, Default)]
45pub struct PhysicsHandleMap2D {
46 pub entity_to_body: HashMap<Entity, BodyHandle>,
48}
49
50pub struct PhysicsStepSystem2D {
60 provider: Box<dyn PhysicsProvider>,
61}
62
63impl PhysicsStepSystem2D {
64 pub fn new(provider: Box<dyn PhysicsProvider>) -> Self {
66 Self { provider }
67 }
68
69 pub fn provider(&self) -> &dyn PhysicsProvider {
71 &*self.provider
72 }
73
74 pub fn provider_mut(&mut self) -> &mut dyn PhysicsProvider {
76 &mut *self.provider
77 }
78}
79
80impl System for PhysicsStepSystem2D {
81 fn name(&self) -> &'static str {
82 "PhysicsStepSystem2D"
83 }
84
85 fn component_access(&self) -> Access {
86 Access::new()
90 }
91
92 fn run(&mut self, world: &mut World) {
93 const FIXED_DT: f32 = 1.0 / 60.0;
95 if let Err(e) = self.provider.step(FIXED_DT) {
96 log::error!("PhysicsStepSystem2D: step failed: {e}");
97 return;
98 }
99
100 let handle_map = match world.get_resource_mut::<PhysicsHandleMap2D>() {
104 Some(map) => {
105 map.entity_to_body
107 .iter()
108 .map(|(&entity, &handle)| (entity, handle))
109 .collect::<Vec<_>>()
110 }
111 None => return,
112 };
113
114 for (entity, body_handle) in handle_map {
115 if let Ok(pos) = self.provider.body_position(body_handle) {
116 use crate::core::math::Vec2;
117 use crate::ecs::components::transform2d::Transform2D;
118 if let Some(transform) = world.get_mut::<Transform2D>(entity) {
119 transform.set_position(Vec2::new(pos[0], pos[1]));
120 }
121 }
122 }
123 }
124}
125
126#[cfg(test)]
131mod tests {
132 use super::*;
133 use crate::core::providers::impls::NullPhysicsProvider;
134
135 #[test]
136 fn test_handle_map_default() {
137 let map = PhysicsHandleMap2D::default();
138 assert!(map.entity_to_body.is_empty());
139 }
140
141 #[test]
142 fn test_system_construction() {
143 let provider = NullPhysicsProvider::new();
144 let system = PhysicsStepSystem2D::new(Box::new(provider));
145 assert_eq!(system.name(), "PhysicsStepSystem2D");
146 }
147
148 #[test]
149 fn test_system_run_empty_world() {
150 let provider = NullPhysicsProvider::new();
151 let mut system = PhysicsStepSystem2D::new(Box::new(provider));
152 let mut world = World::new();
153 system.run(&mut world);
155 }
156
157 #[test]
158 fn test_system_run_with_empty_handle_map() {
159 let provider = NullPhysicsProvider::new();
160 let mut system = PhysicsStepSystem2D::new(Box::new(provider));
161 let mut world = World::new();
162 world.insert_resource(PhysicsHandleMap2D::default());
163 system.run(&mut world);
165 }
166
167 #[test]
168 fn test_provider_accessors() {
169 let provider = NullPhysicsProvider::new();
170 let mut system = PhysicsStepSystem2D::new(Box::new(provider));
171 assert_eq!(system.provider().name(), "null");
172 assert_eq!(system.provider_mut().gravity(), [0.0, 0.0]);
173 }
174
175 #[test]
176 fn test_system_should_run() {
177 let provider = NullPhysicsProvider::new();
178 let system = PhysicsStepSystem2D::new(Box::new(provider));
179 let world = World::new();
180 assert!(system.should_run(&world));
181 }
182
183 #[test]
184 fn test_system_component_access_is_empty() {
185 let provider = NullPhysicsProvider::new();
186 let system = PhysicsStepSystem2D::new(Box::new(provider));
187 assert!(system.component_access().is_empty());
188 }
189}