bevy_debug_grid/
lib.rs

1use bevy::{color::palettes::tailwind, prelude::*};
2
3mod plugin;
4pub mod rendering;
5pub mod systems;
6
7pub use plugin::*;
8use rendering::*;
9use systems::*;
10
11pub mod prelude {
12    pub use crate::plugin::*;
13    pub use super::{
14        Grid,
15        SubGrid,
16        GridAlignment,
17        GridAxis,
18        TrackedGrid,
19    };
20}
21
22/// The main grid component
23#[derive(Component, Clone, Debug)]
24pub struct Grid {
25    /// Spacing between lines
26    pub spacing: f32,
27    /// Line count on one axis
28    pub count: usize,
29    /// Line color
30    pub color: Color,
31    /// Alpha mode
32    pub alpha_mode: AlphaMode,
33}
34
35impl Grid {
36    pub const DEFAULT_SRGBA: Srgba = tailwind::GRAY_400;
37    pub const DEFAULT_ALPHA: f32 = 0.5_f32;
38}
39
40impl Default for Grid {
41    fn default() -> Self {
42        Self {
43            spacing: 0.25_f32,
44            count: 8,
45            color: Color::Srgba(Self::DEFAULT_SRGBA.with_alpha(Self::DEFAULT_ALPHA)),
46            alpha_mode: AlphaMode::Blend,
47        }
48    }
49}
50
51/// Marker component to determine children spawned by a `Grid`
52#[derive(Component)]
53pub struct GridChild;
54
55/// The sub-grid component, adds lines between the lines of a grid.
56/// Spawn it next to a grid for it to have effect.
57#[derive(Component, Clone, Debug)]
58pub struct SubGrid {
59    /// Line count between the main grid's lines
60    pub count: usize,
61    /// Line color
62    pub color: Color,
63}
64
65impl SubGrid {
66    pub const DEFAULT_SRGBA: Srgba = tailwind::GRAY_500;
67}
68
69impl Default for SubGrid {
70    fn default() -> Self {
71        Self {
72            count: 9,
73            color: Color::Srgba(Self::DEFAULT_SRGBA.with_alpha(Grid::DEFAULT_ALPHA)),
74        }
75    }
76}
77
78/// Marker component to determine children spawned by a `SubGrid`
79#[derive(Component)]
80pub struct SubGridChild;
81
82/// The tracking axis for a grid. *Ex:* `GridAlignment::Y` will result in a floor.
83#[derive(Component, Default, Debug, Copy, Clone, PartialEq, Eq)]
84pub enum GridAlignment {
85    X,
86    #[default]
87    Y,
88    Z,
89}
90
91impl GridAlignment {
92    pub const fn to_axis_vec3(&self) -> Vec3 {
93        match self {
94            Self::X => Vec3::X,
95            Self::Y => Vec3::Y,
96            Self::Z => Vec3::Z,
97        }
98    }
99
100    pub fn to_inverted_axis_vec3(&self) -> Vec3 {
101        Vec3::ONE - self.to_axis_vec3()
102    }
103
104    /// Shifts/rotates a `Vec3`'s values. Default `Y` alignment does nothing.
105    pub const fn shift_vec3(&self, input: Vec3) -> Vec3 {
106        match self {
107            Self::X => Vec3::new(input.y, input.z, input.x),
108            Self::Y => input,
109            Self::Z => Vec3::new(input.z, input.x, input.y),
110        }
111    }
112}
113
114impl From<GridAlignment> for Vec3 {
115    fn from(val: GridAlignment) -> Self {
116        val.to_inverted_axis_vec3()
117    }
118}
119
120/// Custom color overrides for axis of a grid.
121/// Spawn it next to a grid for it to have effect.
122#[derive(Component, Clone, Debug)]
123pub struct GridAxis {
124    /// Color of the X axis
125    pub x: Option<Color>,
126    /// Color of the Y axis
127    pub y: Option<Color>,
128    /// Color of the Z axis
129    pub z: Option<Color>,
130}
131
132impl GridAxis {
133    /// An empty grid axis, does nothing.
134    /// Use for later mutation or debug.
135    pub const fn new_empty() -> Self {
136        Self {
137            x: None,
138            y: None,
139            z: None,
140        }
141    }
142
143    /// Creates a grid axis with each axis having a color.
144    /// Red for X, green for Y, and blue for Z.
145    pub const fn new_rgb() -> Self {
146        Self {
147            x: Some(Color::Srgba(tailwind::RED_500)),
148            y: Some(Color::Srgba(tailwind::GREEN_500)),
149            z: Some(Color::Srgba(tailwind::BLUE_500)),
150        }
151    }
152
153    /// Creates a single axis mesh consisting of two `Vec3`s
154    pub fn create_single_axis(size: f32, alignment: GridAlignment) -> [Vec3; 2] {
155        [
156            alignment.shift_vec3(Vec3::new(0.0_f32, size, 0.0_f32)),
157            alignment.shift_vec3(Vec3::new(0.0_f32, -size, 0.0_f32)),
158        ]
159    }
160
161    /// Creates grid axis from the configured colors.
162    /// Returns a vector of used axis with their corresponding color, as well as a vector of unused axis, `(used, unused)`.
163    pub fn create_axis(&self) -> (Vec<(GridAlignment, Color)>, Vec<GridAlignment>) {
164        let mut axis = Vec::new();
165        let mut unused = Vec::new();
166
167        if let Some(color) = self.x {
168            axis.push((GridAlignment::X, color));
169        } else {
170            unused.push(GridAlignment::X);
171        }
172        // Y axis does not create a default
173        if let Some(color) = self.y {
174            axis.push((GridAlignment::Y, color));
175        }
176        if let Some(color) = self.z {
177            axis.push((GridAlignment::Z, color));
178        } else {
179            unused.push(GridAlignment::Z);
180        }
181
182        (axis, unused)
183    }
184
185    /// Returns the default axis for a grid
186    pub const fn default_axis() -> [GridAlignment; 2] {
187        [GridAlignment::X, GridAlignment::Z]
188    }
189
190    /// Returns an axis color by grid alignment, if such a color is configured per that axis
191    pub const fn get_by_alignment(&self, alignment: &GridAlignment) -> Option<Color> {
192        match alignment {
193            GridAlignment::X => self.x,
194            GridAlignment::Y => self.y,
195            GridAlignment::Z => self.z,
196        }
197    }
198}
199
200impl Default for GridAxis {
201    fn default() -> Self {
202        Self::new_empty()
203    }
204}
205
206/// Marker component to determine children spawned by a `GridAxis`
207#[derive(Component)]
208pub struct GridAxisChild;
209
210/// Marks a grid as "tracked", meaning it will move with the main camera
211///
212/// Note: A tracked grid should not be parented to a moving entity.
213#[derive(Component, Clone, Debug, Default)]
214pub struct TrackedGrid {
215    /// The axis on which the grid will be tracked
216    pub alignment: GridAlignment,
217    /// The offset the grid has in relation to its tracking axis
218    pub offset: f32,
219    /// Entity to be tracked instead of the plugin's generic component
220    pub tracking_override: Option<Entity>,
221}