physics_simulation/
physics_simulation.rs1use lotus_engine::*;
6use rand::{RngExt, rng, rngs::ThreadRng};
7
8#[derive(Clone, Component)]
9struct Object();
10
11#[derive(Clone, Component)]
12struct Border();
13
14your_game!(
15 WindowConfiguration::default(),
16 setup,
17 update
18);
19
20fn setup(context: &mut Context) {
21 let circle: Circle = Circle::new(64, 0.5);
22 let red_object: Shape = Shape::new(Orientation::Horizontal, GeometryType::Circle(circle.clone()), Color::by_option(ColorOption::Red));
23 let blue_object: Shape = Shape::new(Orientation::Horizontal, GeometryType::Circle(circle.clone()), Color::by_option(ColorOption::Blue));
24
25 context.commands.spawn(
26 vec![
27 Box::new(red_object),
28 Box::new(Object()),
29 Box::new(Transform::new(
30 Position::new(Vector2::new(0.0, 0.0), Strategy::Normalized),
31 0.0,
32 Vector2::new(0.30, 0.30)
33 )),
34 Box::new(Velocity::new(Vector2::new(0.45, 0.45))),
35 Box::new(Collision::new(Collider::new_simple(GeometryType::Square)))
36 ]
37 );
38
39 context.commands.spawn(
40 vec![
41 Box::new(blue_object),
42 Box::new(Object()),
43 Box::new(Transform::new(
44 Position::new(Vector2::new(-0.45, 0.0), Strategy::Normalized),
45 0.0,
46 Vector2::new(0.30, 0.30)
47 )),
48 Box::new(Velocity::new(Vector2::new(0.45, 0.45))),
49 Box::new(Collision::new(Collider::new_simple(GeometryType::Square)))
50 ]
51 );
52
53 spawn_border(context, Orientation::Horizontal, Vector2::new(0.0, -1.), Vector2::new(context.window_configuration.width as f32, 0.01));
54 spawn_border(context, Orientation::Horizontal, Vector2::new(0.0, 1.), Vector2::new(context.window_configuration.width as f32, 0.01));
55 spawn_border(context, Orientation::Vertical, Vector2::new(1.35, 0.), Vector2::new(0.01, context.window_configuration.height as f32));
56 spawn_border(context, Orientation::Vertical, Vector2::new(-1.35, 0.), Vector2::new(0.01, context.window_configuration.height as f32));
57}
58
59fn update(context: &mut Context) {
60 let mut query: Query = Query::new(&context.world).with::<Object>();
61 let entities: Vec<Entity> = query.entities_with_components().unwrap();
62
63 check_border_collision(context, &entities);
64 check_object_collision(context, &entities);
65 move_objects(context, &entities);
66}
67
68fn spawn_border(context: &mut Context, orientation: Orientation, position: Vector2<f32>, scale: Vector2<f32>) {
69 let border: Shape = Shape::new(orientation, GeometryType::Rectangle, Color::by_option(ColorOption::White));
70
71 context.commands.spawn(
72 vec![
73 Box::new(border),
74 Box::new(Border()),
75 Box::new(Transform::new(
76 Position::new(position, Strategy::Normalized),
77 0.0,
78 scale
79 )),
80 Box::new(Collision::new(Collider::new_simple(GeometryType::Rectangle)))
81 ]
82 );
83}
84
85fn check_border_collision(context: &mut Context, entities: &Vec<Entity>) {
86 let mut border_query: Query = Query::new(&context.world).with::<Border>();
87 let borders: Vec<Entity> = border_query.entities_with_components().unwrap();
88
89 for entity in entities {
90 let mut velocity: ComponentRefMut<'_, Velocity> = context.world.get_entity_component_mut::<Velocity>(entity).unwrap();
91 let collision: ComponentRef<'_, Collision> = context.world.get_entity_component::<Collision>(entity).unwrap();
92
93 for border in &borders {
94 let border_collision: ComponentRef<'_, Collision> = context.world.get_entity_component::<Collision>(&border).unwrap();
95
96 if Collision::check(CollisionAlgorithm::Aabb, &collision, &border_collision) {
97 let border_transform: ComponentRef<'_, Transform> = context.world.get_entity_component::<Transform>(&border).unwrap();
98
99 if border_transform.position.x.abs() < border_transform.position.y.abs() {
100 velocity.y *= -1.0;
101 } else {
102 velocity.x *= -1.0;
103 }
104 break;
105 }
106 }
107 }
108}
109
110fn check_object_collision(context: &mut Context, entities: &Vec<Entity>) {
111 for (index, entity) in entities.iter().enumerate() {
112 let mut velocity: ComponentRefMut<'_, Velocity> = context.world.get_entity_component_mut::<Velocity>(entity).unwrap();
113 let collision: ComponentRef<'_, Collision> = context.world.get_entity_component::<Collision>(entity).unwrap();
114
115 if let Some(next_entity) = entities.get(index + 1) {
116 let mut next_entity_velocity: ComponentRefMut<'_, Velocity> = context.world.get_entity_component_mut::<Velocity>(next_entity).unwrap();
117 let next_entity_collision: ComponentRef<'_, Collision> = context.world.get_entity_component::<Collision>(next_entity).unwrap();
118
119 if Collision::check(CollisionAlgorithm::Aabb, &collision, &next_entity_collision) {
120 let mut thread_rng: ThreadRng = rng();
121 let random_angle: f32 = thread_rng.random_range(0.0..std::f32::consts::TAU);
122 let new_direction: Vector2<f32> = Vector2::new(random_angle.cos(), random_angle.sin());
123 let collision_impulse: f32 = 1.5;
124
125 velocity.update_values(new_direction * collision_impulse);
126 next_entity_velocity.update_values(-new_direction * collision_impulse);
127 }
128 }
129 }
130}
131
132fn move_objects(context: &mut Context, entities: &Vec<Entity>) {
133 for entity in entities {
134 let mut transform: ComponentRefMut<'_, Transform> = context.world.get_entity_component_mut::<Transform>(entity).unwrap();
135 let velocity: ComponentRef<'_, Velocity> = context.world.get_entity_component::<Velocity>(entity).unwrap();
136
137 let new_position: Vector2<f32> = transform.position.to_vec() + velocity.to_vec() * context.delta;
138 transform.set_position(&context.render_state, new_position);
139 }
140}