roast2d_physics/
collision_map.rs1use 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#[derive(Resource)]
23pub struct CollisionMap {
24 pub name: String,
25 pub size: UVec2,
26 pub tile_size: f32,
27 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}