bones_framework/render/
tilemap.rs

1//! Tile map rendering components.
2
3use crate::prelude::*;
4
5/// A tilemap layer component.
6#[derive(Clone, Debug, HasSchema, Default)]
7pub struct TileLayer {
8    /// The vector of tile slots in this layer.
9    pub tiles: Vec<Option<Entity>>,
10    /// The size of the layer in tiles.
11    pub grid_size: UVec2,
12    /// The size of each tile in the layer.
13    pub tile_size: Vec2,
14    /// The texture atlas to use for the layer
15    pub atlas: Handle<Atlas>,
16}
17
18/// A tilemap tile component.
19#[derive(Clone, Debug, HasSchema, Default)]
20#[repr(C)]
21pub struct Tile {
22    /// The tile index in the tilemap texture.
23    pub idx: u32,
24    /// Whether or not to flip the tile horizontally.
25    pub flip_x: bool,
26    /// Whether or not to flip tile vertically.
27    pub flip_y: bool,
28}
29
30impl TileLayer {
31    /// Create a new tile layer
32    pub fn new(grid_size: UVec2, tile_size: Vec2, atlas: Handle<Atlas>) -> Self {
33        let mut out = Self {
34            tiles: Vec::new(),
35            grid_size,
36            tile_size,
37            atlas,
38        };
39        out.ensure_space();
40        out
41    }
42
43    /// Makes sure the tiles vector has space for all of our tiles.
44    fn ensure_space(&mut self) {
45        let tile_count = (self.grid_size.x * self.grid_size.y) as usize;
46
47        if unlikely(self.tiles.len() < tile_count) {
48            self.tiles
49                .extend((0..(tile_count - self.tiles.len())).map(|_| None));
50        }
51    }
52
53    /// Get the index of the tile at the given position.
54    #[inline]
55    pub fn idx(&self, pos: UVec2) -> u32 {
56        self.grid_size.x * pos.y + pos.x
57    }
58
59    /// Get the position of the tile at the given index.
60    pub fn pos(&self, idx: u32) -> UVec2 {
61        let y = idx / self.grid_size.x;
62        let x = idx - (y * self.grid_size.x);
63
64        UVec2::new(x, y)
65    }
66
67    /// Get's the tile at the given position in the layer, indexed with the bottom-left of the layer
68    /// being (0, 0).
69    pub fn get(&self, pos: UVec2) -> Option<Entity> {
70        let idx = self.idx(pos);
71        self.tiles.get(idx as usize).cloned().flatten()
72    }
73
74    /// Set the tile at the given position, to a certain entity.
75    pub fn set(&mut self, pos: UVec2, entity: Option<Entity>) {
76        self.ensure_space();
77
78        let idx = self.idx(pos);
79        *self.tiles.get_mut(idx as usize).unwrap_or_else(|| {
80            panic!(
81                "Tile pos out of range of tile size: pos {:?} size {:?}",
82                pos, self.grid_size
83            )
84        }) = entity;
85    }
86}