mirror of
https://github.com/kristoferssolo/maze-ascension.git
synced 2025-10-21 19:20:34 +00:00
feat(grid): generate maze
This commit is contained in:
parent
0ee94c826a
commit
f16fd51090
14
src/hex.rs
Normal file
14
src/hex.rs
Normal 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);
|
||||
}
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(¤t_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(¤t_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
|
||||
}
|
||||
|
||||
@ -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
24
src/hexgrid/tile.rs
Normal 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 }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user