Skip to main content

roast2d_physics/
collision_map.rs

1use roast2d::{derive::Resource, prelude::*};
2use std::fmt::Debug;
3
4use glam::{IVec2, UVec2, Vec2};
5
6pub const COLLISION_MAP: &str = "Collision";
7
8pub trait CollisionRule {
9    fn is_collide(&self, map: &CollisionMap, pos: IVec2) -> bool;
10}
11
12#[derive(Default)]
13pub struct DefaultCollisionRule;
14
15impl CollisionRule for DefaultCollisionRule {
16    fn is_collide(&self, map: &CollisionMap, pos: IVec2) -> bool {
17        map.get(pos).is_some_and(|t| t != 0)
18    }
19}
20
21/// Game map
22#[derive(Resource)]
23pub struct CollisionMap {
24    pub name: String,
25    pub size: UVec2,
26    pub tile_size: f32,
27    // The tile indices with a length of size.x * size.y
28    pub data: Vec<u16>,
29    pub collision_rule: Box<dyn CollisionRule>,
30}
31
32impl Debug for CollisionMap {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        f.debug_struct("CollisionMap")
35            .field("name", &self.name)
36            .field("size", &self.size)
37            .field("tile_size", &self.tile_size)
38            .finish()
39    }
40}
41
42impl Default for CollisionMap {
43    fn default() -> Self {
44        Self {
45            name: "Collision".to_string(),
46            size: UVec2::default(),
47            tile_size: 0.0,
48            data: Default::default(),
49            collision_rule: Box::new(DefaultCollisionRule),
50        }
51    }
52}
53
54impl CollisionMap {
55    pub fn get(&self, pos: IVec2) -> Option<u16> {
56        if pos.x < 0 || pos.y < 0 || pos.x >= self.size.x as i32 || pos.y >= self.size.y as i32 {
57            return None;
58        }
59        let index = (pos.y * self.size.x as i32 + pos.x) as usize;
60        self.data.get(index).cloned()
61    }
62
63    pub fn set_collision_rule<CR: CollisionRule + 'static>(&mut self, rule: CR) {
64        self.collision_rule = Box::new(rule);
65    }
66
67    pub fn is_collide(&self, pos: IVec2) -> bool {
68        self.collision_rule.is_collide(self, pos)
69    }
70
71    pub fn bounds(&self) -> Vec2 {
72        Vec2::new(
73            self.tile_size * self.size.x as f32,
74            self.tile_size * self.size.y as f32,
75        )
76    }
77}