|
1 pub mod collision; |
|
2 pub mod common; |
|
3 mod grid; |
|
4 pub mod physics; |
|
5 pub mod time; |
|
6 |
|
7 use fpnum::FPNum; |
|
8 use integral_geometry::Size; |
|
9 use land2d::Land2D; |
|
10 |
|
11 use crate::{ |
|
12 collision::{CollisionData, CollisionProcessor, ContactData}, |
|
13 common::{GearAllocator, GearData, GearDataAggregator, GearDataProcessor, GearId, Millis}, |
|
14 physics::{PhysicsData, PhysicsProcessor}, |
|
15 time::TimeProcessor, |
|
16 }; |
|
17 |
|
18 pub struct JoinedData { |
|
19 gear_id: GearId, |
|
20 physics: PhysicsData, |
|
21 collision: CollisionData, |
|
22 contact: ContactData, |
|
23 } |
|
24 |
|
25 pub struct World { |
|
26 allocator: GearAllocator, |
|
27 physics: PhysicsProcessor, |
|
28 collision: CollisionProcessor, |
|
29 time: TimeProcessor, |
|
30 } |
|
31 |
|
32 macro_rules! processor_map { |
|
33 ( $data_type: ident => $field: ident ) => { |
|
34 impl GearDataAggregator<$data_type> for World { |
|
35 fn find_processor(&mut self) -> &mut GearDataProcessor<$data_type> { |
|
36 &mut self.$field |
|
37 } |
|
38 } |
|
39 }; |
|
40 } |
|
41 |
|
42 processor_map!(PhysicsData => physics); |
|
43 processor_map!(CollisionData => collision); |
|
44 |
|
45 impl World { |
|
46 pub fn new(world_size: Size) -> Self { |
|
47 Self { |
|
48 allocator: GearAllocator::new(), |
|
49 physics: PhysicsProcessor::new(), |
|
50 collision: CollisionProcessor::new(world_size), |
|
51 time: TimeProcessor::new(), |
|
52 } |
|
53 } |
|
54 |
|
55 #[inline] |
|
56 pub fn new_gear(&mut self) -> Option<GearId> { |
|
57 self.allocator.alloc() |
|
58 } |
|
59 |
|
60 #[inline] |
|
61 pub fn delete_gear(&mut self, gear_id: GearId) { |
|
62 self.physics.remove(gear_id); |
|
63 self.collision.remove(gear_id); |
|
64 self.time.cancel(gear_id); |
|
65 self.allocator.free(gear_id) |
|
66 } |
|
67 |
|
68 pub fn step(&mut self, time_step: Millis, land: &Land2D<u32>) { |
|
69 let updates = self.physics.process(time_step); |
|
70 let collision = self.collision.process(land, &updates); |
|
71 let events = self.time.process(time_step); |
|
72 } |
|
73 |
|
74 pub fn add_gear_data<T>(&mut self, gear_id: GearId, data: T) |
|
75 where |
|
76 T: GearData, |
|
77 Self: GearDataAggregator<T>, |
|
78 { |
|
79 self.find_processor().add(gear_id, data); |
|
80 } |
|
81 } |
|
82 |
|
83 #[cfg(test)] |
|
84 mod tests { |
|
85 use crate::{ |
|
86 collision::{CircleBounds, CollisionData}, |
|
87 physics::PhysicsData, |
|
88 World, |
|
89 }; |
|
90 use fpnum::{fp, FPNum, FPPoint}; |
|
91 use integral_geometry::Size; |
|
92 use land2d::Land2D; |
|
93 |
|
94 #[test] |
|
95 fn data_flow() { |
|
96 let world_size = Size::new(2048, 2048); |
|
97 |
|
98 let mut world = World::new(world_size); |
|
99 let gear_id = 46631; |
|
100 |
|
101 world.add_gear_data( |
|
102 gear_id, |
|
103 PhysicsData { |
|
104 position: FPPoint::zero(), |
|
105 velocity: FPPoint::unit_y(), |
|
106 }, |
|
107 ); |
|
108 |
|
109 world.add_gear_data( |
|
110 gear_id, |
|
111 CollisionData { |
|
112 bounds: CircleBounds { |
|
113 center: FPPoint::zero(), |
|
114 radius: fp!(10), |
|
115 }, |
|
116 }, |
|
117 ); |
|
118 |
|
119 let land = Land2D::new(Size::new(world_size.width - 2, world_size.height - 2), 0); |
|
120 |
|
121 world.step(fp!(1), &land); |
|
122 } |
|
123 } |