1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
use crate::color::EntityColor;
use crate::constants::{MAX_SPEED, MIN_SPEED, SPEED_COLLIDE_MULT};
use crate::entity::Entity;
use crate::math::BoundingCircle;
use crate::random::RandomState;
pub fn detect_collisions(entities: &[Entity], buffer: &mut Vec<(usize, usize)>) {
buffer.clear();
let len = entities.len();
for i in 0..len {
if !entities[i].alive {
continue;
}
for j in (i + 1)..len {
if !entities[j].alive {
continue;
}
if entities[i].overlaps_with(&entities[j]) {
buffer.push((i, j));
}
}
}
}
pub fn process_collisions(
entities: &mut Vec<Entity>,
rng: &mut RandomState,
_next_entity_id: &mut u32,
collision_buffer: &mut Vec<(usize, usize)>,
elapsed_ms: f32,
_events: &mut Vec<String>,
) {
detect_collisions(entities, collision_buffer);
let new_entities = Vec::new();
for &(i, j) in collision_buffer.iter() {
if i >= entities.len() || j >= entities.len() {
continue;
}
if !entities[i].alive || !entities[j].alive {
continue;
}
let color_a = entities[i].color;
let color_b = entities[j].color;
match (color_a, color_b) {
(EntityColor::Green, EntityColor::Green) => {
if (rng.next_u32() & 1) == 0 {
entities[i].color = EntityColor::Yellow;
entities[j].color = EntityColor::Red;
entities[j].spawn_time_ms = Some(elapsed_ms);
} else {
entities[i].color = EntityColor::Red;
entities[i].spawn_time_ms = Some(elapsed_ms);
entities[j].color = EntityColor::Yellow;
}
}
(EntityColor::Red, EntityColor::Red) => {
let a = &entities[i];
let b = &entities[j];
let collision_point = (a.pos + b.pos) * 0.5;
entities[i].alive = false;
entities[j].alive = false;
let best_green_idx = entities
.iter()
.enumerate()
.filter(|(_, e)| e.alive && e.color == EntityColor::Green)
.min_by(|(_, e1), (_, e2)| {
e1.pos
.distance_squared(collision_point)
.partial_cmp(&e2.pos.distance_squared(collision_point))
.unwrap_or(std::cmp::Ordering::Equal)
})
.map(|(idx, _)| idx);
if let Some(idx) = best_green_idx {
entities[idx].alive = false;
}
}
_ => {
let a_speed = (entities[i].speed * SPEED_COLLIDE_MULT).clamp(MIN_SPEED, MAX_SPEED);
let b_speed = (entities[j].speed * SPEED_COLLIDE_MULT).clamp(MIN_SPEED, MAX_SPEED);
entities[i].speed = a_speed;
entities[j].speed = b_speed;
entities[i].normalize_velocity();
entities[j].normalize_velocity();
}
}
}
if !new_entities.is_empty() {
entities.extend(new_entities);
}
}
|