summaryrefslogtreecommitdiff
path: root/2026/games_submissions/rpc2dot0/src/collision.rs
blob: aaae9a7c48f232912a622a2168d3b282bef50103 (plain)
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);
    }
}