Skip to content

Commit 723bfdf

Browse files
grid + dir utilities
1 parent ed333f8 commit 723bfdf

File tree

7 files changed

+179
-5
lines changed

7 files changed

+179
-5
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ repository = "https://github.com/HalfPixelStudios/bevy_bobs"
1111
[dependencies]
1212
bevy = { version = "0.7" }
1313
rand = { version = "0.8.5" }
14+
anyhow = "1.0.58"
15+
thiserror = "1"
1416

1517
ron = "0.7.1"
1618
serde = { version = "1", features = ["derive"] }
@@ -20,7 +22,7 @@ bevy_kira_audio = { version = "0.10.0", default-features = false, features = [ "
2022

2123
[features]
2224
default = ["all"]
23-
all = ["prefab", "physics_2d", "spawn_wave", "attack_pattern", "health_bar", "sfx", "cursor"]
25+
all = ["prefab", "physics_2d", "spawn_wave", "attack_pattern", "health_bar", "sfx", "cursor", "grid"]
2426

2527
prefab = []
2628
physics_2d = []
@@ -29,6 +31,7 @@ attack_pattern = []
2931
health_bar = []
3032
sfx = ["dep:bevy_kira_audio"]
3133
cursor = []
34+
grid = []
3235

3336
egui = ["dep:bevy-inspector-egui"]
3437
serde = []

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ Bits and Bobs for [Bevy](https://bevyengine.org/) Projects
88

99
## Included utilities
1010

11-
- **attack_pattern** - utilities to generate attack patterns (straight, shotgun, around)
12-
- **health_bar** - health bar ui component
13-
- **physics_2d** - dead simple 2d components
14-
- **prefab** - utilities for loading prefabs from ron files
11+
general
1512
- **spawn_wave** - spawn wave system
13+
- **prefab** - utilities for loading prefabs from ron files
14+
- **physics_2d** - dead simple 2d components
15+
- **sfx** sound player
1616

17+
ui
18+
- **attack_pattern** - utilities to generate attack patterns (straight, shotgun, around)
19+
- **health_bar** - health bar ui component
20+
- **cursor** - in game coords of mouse cursor

src/grid.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//! Grid related utilities
2+
3+
use anyhow::{anyhow, Result};
4+
use bevy::prelude::*;
5+
use thiserror::Error;
6+
7+
#[derive(Error, Debug)]
8+
pub enum GridError {
9+
#[error("tried to access position outside of grid {0}")]
10+
OutOfBounds(IVec2),
11+
}
12+
13+
/// Collection of grid positions that can be queried and manipulated
14+
///
15+
/// The grid is a read-only structure. It is not a source of truth. GridPositions are the actual
16+
/// source of truth. The grid is just a visual representation of where all the GridPosition objects
17+
/// are relative to each other.
18+
pub struct Grid<T: PartialEq> {
19+
width: i32,
20+
height: i32,
21+
grid: Vec<Vec<T>>,
22+
}
23+
24+
impl<T: PartialEq> Grid<T> {
25+
/// Construct a new grid
26+
pub fn new(width: i32, height: i32) -> Self {
27+
// TODO this is sorta stupid lol (maybe just force T to derive Clone)
28+
let grid_vec = (0..width * height).into_iter().map(|_| vec![]).collect();
29+
30+
Grid {
31+
width,
32+
height,
33+
grid: grid_vec,
34+
}
35+
}
36+
37+
/// Check if position is within the grid
38+
pub fn bounds_check(&self, pos: &IVec2) -> bool {
39+
0 <= pos.x && pos.x < self.width && 0 <= pos.y && pos.y < self.height
40+
}
41+
42+
pub fn pos_to_index(&self, pos: &IVec2) -> Result<usize> {
43+
if self.bounds_check(pos) {
44+
Ok((pos.y * self.width + pos.x) as usize)
45+
} else {
46+
Err(anyhow!(GridError::OutOfBounds(pos.to_owned())))
47+
}
48+
}
49+
50+
/// Get reference to cell at position
51+
pub fn get_cell(&self, pos: &IVec2) -> Result<&Vec<T>> {
52+
let ind = self.pos_to_index(pos)?;
53+
// shouldn't panic (since already bounds checked)?
54+
Ok(self.grid.get(ind).unwrap())
55+
}
56+
57+
/// Get mutable reference to cell at position
58+
pub fn get_cell_mut(&mut self, pos: &IVec2) -> Result<&mut Vec<T>> {
59+
let ind = self.pos_to_index(pos)?;
60+
Ok(self.grid.get_mut(ind).unwrap())
61+
}
62+
63+
/// Insert a cell entity at position
64+
pub fn insert_at(&mut self, pos: &IVec2, val: T) -> Result<()> {
65+
self.get_cell_mut(pos)?.push(val);
66+
Ok(())
67+
}
68+
69+
/// Query if cell contains a given entity
70+
pub fn contains_at(&self, pos: &IVec2, val: T) -> Result<bool> {
71+
Ok(self.get_cell(pos)?.contains(&val))
72+
}
73+
74+
/// Query if a cell at position is empty
75+
pub fn empty_at(&self, pos: &IVec2) -> Result<bool> {
76+
Ok(self.get_cell(pos)?.is_empty())
77+
}
78+
79+
/// Wipe the entire map
80+
pub fn clear(&mut self) {
81+
for cell in self.grid.iter_mut() {
82+
cell.clear();
83+
}
84+
}
85+
86+
/// Get grid width
87+
pub fn width(&self) -> i32 {
88+
self.width
89+
}
90+
91+
/// Get grid height
92+
pub fn height(&self) -> i32 {
93+
self.height
94+
}
95+
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ pub mod attack_pattern;
1717
pub mod component;
1818
#[cfg(feature = "cursor")]
1919
pub mod cursor;
20+
#[cfg(feature = "grid")]
21+
pub mod grid;
2022
#[cfg(feature = "health_bar")]
2123
pub mod health_bar;
2224
pub mod misc;

src/misc/dir.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/// 2d enum for directions
2+
use bevy::prelude::*;
3+
4+
#[derive(Debug, Copy, Clone)]
5+
pub enum Dir {
6+
None,
7+
8+
North,
9+
East,
10+
South,
11+
West,
12+
}
13+
14+
impl From<IVec2> for Dir {
15+
fn from(v: IVec2) -> Self {
16+
let clamped = v.clamp(-IVec2::ONE, IVec2::ONE);
17+
18+
// TODO can match directly in bevy 0.8
19+
match clamped.to_array() {
20+
[0, 1] => Dir::North,
21+
[1, 0] => Dir::East,
22+
[0, -1] => Dir::South,
23+
[-1, 0] => Dir::West,
24+
_ => Dir::None,
25+
}
26+
}
27+
}
28+
29+
impl From<Dir> for IVec2 {
30+
fn from(d: Dir) -> Self {
31+
match d {
32+
Dir::North => IVec2::new(0, 1),
33+
Dir::East => IVec2::new(1, 0),
34+
Dir::South => IVec2::new(0, -1),
35+
Dir::West => IVec2::new(-1, 0),
36+
Dir::None => IVec2::new(0, 0),
37+
}
38+
}
39+
}
40+
41+
impl From<String> for Dir {
42+
fn from(s: String) -> Self {
43+
match s.to_lowercase().as_str() {
44+
"north" => Dir::North,
45+
"south" => Dir::South,
46+
"east" => Dir::East,
47+
"west" => Dir::West,
48+
_ => Dir::None,
49+
}
50+
}
51+
}
52+
53+
pub fn to_rotation(dir: Dir) -> f32 {
54+
use std::f32::consts::PI;
55+
56+
match dir {
57+
Dir::East => 0.,
58+
Dir::North => PI / 2.,
59+
Dir::West => PI,
60+
Dir::South => 3. * PI / 2.,
61+
_ => unreachable!(),
62+
}
63+
}
64+
65+
pub fn cardinal_dirs() -> Vec<Dir> {
66+
vec![Dir::North, Dir::South, Dir::East, Dir::West]
67+
}

src/misc/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
//! Miscellenous utilities
22
3+
pub mod dir;
34
pub mod displacement;

0 commit comments

Comments
 (0)