feat(grid): generate maze

This commit is contained in:
Kristofers Solo 2024-09-22 15:28:07 +03:00
parent 0ee94c826a
commit f16fd51090
5 changed files with 154 additions and 47 deletions

14
src/hex.rs Normal file
View File

@ -0,0 +1,14 @@
use bevy::{color::palettes::css::BLACK, prelude::*};
use bevy_prototype_lyon::{
draw::{Fill, Stroke},
entity::ShapeBundle,
path::PathBuilder,
plugin::ShapePlugin,
};
use rand::{thread_rng, Rng};
pub(super) fn plugin(app: &mut App) {
app.add_plugins(ShapePlugin);
app.add_systems(Startup, setup_system);
}

View File

@ -4,7 +4,7 @@ use hexx::EdgeDirection;
pub(super) fn plugin(_app: &mut App) {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)]
pub enum HexDirection {
pub enum Direction {
Top,
TopRight,
BottomRight,
@ -13,12 +13,8 @@ pub enum HexDirection {
TopLeft,
}
impl HexDirection {
pub fn to_hexx_direction(self) -> EdgeDirection {
self.into()
}
pub const ALL: [HexDirection; 6] = [
impl Direction {
pub const ALL: [Direction; 6] = [
Self::Top,
Self::TopRight,
Self::BottomRight,
@ -38,16 +34,3 @@ impl HexDirection {
}
}
}
impl From<HexDirection> for EdgeDirection {
fn from(value: HexDirection) -> Self {
match value {
HexDirection::Top => Self::FLAT_NORTH,
HexDirection::TopRight => Self::FLAT_NORTH_EAST,
HexDirection::BottomRight => Self::FLAT_SOUTH_EAST,
HexDirection::Bottom => Self::FLAT_SOUTH,
HexDirection::BottomLeft => Self::FLAT_SOUTH_WEST,
HexDirection::TopLeft => Self::FLAT_NORTH_WEST,
}
}
}

View File

@ -1,4 +1,8 @@
use bevy::{color::palettes::css::BLACK, prelude::*};
use bevy::{
color::palettes::css::{BLACK, GREEN, RED},
prelude::*,
utils::hashbrown::HashMap,
};
use bevy_prototype_lyon::{
draw::{Fill, Stroke},
@ -6,7 +10,18 @@ use bevy_prototype_lyon::{
path::PathBuilder,
plugin::ShapePlugin,
};
use rand::{thread_rng, Rng};
use rand::{prelude::SliceRandom, rngs::ThreadRng, thread_rng};
use super::tile::{AxialCoord, Tile};
const DIRECTIONS: [AxialCoord; 6] = [
AxialCoord { q: 1, r: 0 }, // Right
AxialCoord { q: 1, r: -1 }, // Top-right
AxialCoord { q: 0, r: -1 }, // Top-left
AxialCoord { q: -1, r: 0 }, // Left
AxialCoord { q: -1, r: 1 }, // Bottom-left
AxialCoord { q: 0, r: 1 }, // Bottom-right
];
pub struct HexGrid;
@ -18,45 +33,45 @@ impl Plugin for HexGrid {
}
pub(super) fn setup_system(mut commands: Commands) {
let radius = 5;
let hex_positions = generate_hex_grix(radius);
let radius = 7;
let mut grid = generate_hex_grix(radius);
let hex_size = 30.;
let hex_height = hex_size * 2.;
let hex_width = (3.0_f32).sqrt() * hex_size;
let start_coord = AxialCoord::new(-radius, 0);
let end_coord = AxialCoord::new(radius, 0);
for (q, r) in hex_positions {
let x = hex_width * (q as f32 + r as f32 / 2.);
let y = hex_height * (r as f32 * 3. / 4.);
let mut rng = thread_rng();
let walls: [bool; 6] = [
rng.gen(),
rng.gen(),
rng.gen(),
rng.gen(),
rng.gen(),
rng.gen(),
];
generate_maze(&mut grid, start_coord, &mut rng);
add_hex_tile(&mut commands, Vec2::new(x, y), hex_size, walls);
}
render_maze(&mut commands, &mut grid, radius, start_coord, end_coord);
}
fn generate_hex_grix(radius: i32) -> Vec<(i32, i32)> {
let mut positions = Vec::new();
fn generate_hex_grix(radius: i32) -> HashMap<AxialCoord, Tile> {
let mut grid = HashMap::new();
for q in -radius..=radius {
let r1 = (-radius).max(-q - radius);
let r2 = radius.min(-q + radius);
for r in r1..=r2 {
positions.push((q, r));
let coord = AxialCoord::new(q, r);
let tile = Tile {
position: coord,
walls: [true; 6],
visited: false,
};
grid.insert(coord, tile);
}
}
positions
grid
}
fn add_hex_tile(commands: &mut Commands, position: Vec2, size: f32, walls: [bool; 6]) {
fn add_hex_tile(
commands: &mut Commands,
position: Vec2,
size: f32,
walls: [bool; 6],
fill_color: Color,
) {
let hex_points = (0..6)
.map(|i| {
let angle_deg = 60. * i as f32 - 30.;
@ -73,6 +88,7 @@ fn add_hex_tile(commands: &mut Commands, position: Vec2, size: f32, walls: [bool
path_builder.close();
let hexagon = path_builder.build();
// Create the hexagon fill
commands.spawn((
ShapeBundle {
path: hexagon,
@ -82,9 +98,10 @@ fn add_hex_tile(commands: &mut Commands, position: Vec2, size: f32, walls: [bool
},
..default()
},
Fill::color(Color::srgb(0.8, 0.8, 0.8)),
Fill::color(fill_color),
));
// Draw walls
for i in 0..6 {
if walls[i] {
let start = hex_points[i];
@ -108,3 +125,70 @@ fn add_hex_tile(commands: &mut Commands, position: Vec2, size: f32, walls: [bool
}
}
}
fn generate_maze(
grid: &mut HashMap<AxialCoord, Tile>,
current_coord: AxialCoord,
rng: &mut ThreadRng,
) {
{
let current_tile = grid.get_mut(&current_coord).unwrap();
current_tile.visit();
}
let mut directions = DIRECTIONS.clone();
directions.shuffle(rng);
for (i, direction) in directions.iter().enumerate() {
let neightbor_coord = AxialCoord {
q: current_coord.q + direction.q,
r: current_coord.r + direction.r,
};
if let Some(neightbor_tile) = grid.get(&neightbor_coord) {
if !neightbor_tile.visited {
// Remove the wall between current_tile and neighbor_tile
{
let current_tile = grid.get_mut(&current_coord).unwrap();
current_tile.walls[i] = false;
}
{
let neightbor_tile = grid.get_mut(&neightbor_coord).unwrap();
neightbor_tile.walls[opposite_wall(i)] = false;
}
// Recurse with the neighbor tile
generate_maze(grid, neightbor_coord, rng);
}
}
}
}
fn render_maze(
commands: &mut Commands,
grid: &mut HashMap<AxialCoord, Tile>,
radius: i32,
start_coord: AxialCoord,
end_coord: AxialCoord,
) {
let hex_size = 30.;
let hex_height = hex_size * 2.;
let hex_width = (3.0_f32).sqrt() * hex_size;
for tile in grid.values() {
let (q, r) = (tile.position.q, tile.position.r);
let x = hex_width * (q as f32 + r as f32 / 2.);
let y = hex_height * (r as f32 * 3. / 4.);
let mut fill_color = Color::srgb(0.8, 0.8, 0.8);
if tile.position == start_coord {
fill_color = GREEN.into();
} else if tile.position == end_coord {
fill_color = RED.into();
}
add_hex_tile(commands, Vec2::new(x, y), hex_size, tile.walls, fill_color);
}
}
fn opposite_wall(index: usize) -> usize {
(index + 3) % 6
}

View File

@ -4,7 +4,9 @@ use bevy::{
};
use bevy_prototype_lyon::plugin::ShapePlugin;
use grid::setup_system;
pub mod direction;
pub mod grid;
pub mod tile;
pub struct HexGrid;

24
src/hexgrid/tile.rs Normal file
View File

@ -0,0 +1,24 @@
#[derive(Debug, Clone)]
pub struct Tile {
pub position: AxialCoord,
pub walls: [bool; 6],
pub visited: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AxialCoord {
pub q: i32,
pub r: i32,
}
impl Tile {
pub fn visit(&mut self) {
self.visited = true
}
}
impl AxialCoord {
pub fn new(q: i32, r: i32) -> Self {
Self { q, r }
}
}