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) {}
|
pub(super) fn plugin(_app: &mut App) {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)]
|
||||||
pub enum HexDirection {
|
pub enum Direction {
|
||||||
Top,
|
Top,
|
||||||
TopRight,
|
TopRight,
|
||||||
BottomRight,
|
BottomRight,
|
||||||
@ -13,12 +13,8 @@ pub enum HexDirection {
|
|||||||
TopLeft,
|
TopLeft,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HexDirection {
|
impl Direction {
|
||||||
pub fn to_hexx_direction(self) -> EdgeDirection {
|
pub const ALL: [Direction; 6] = [
|
||||||
self.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const ALL: [HexDirection; 6] = [
|
|
||||||
Self::Top,
|
Self::Top,
|
||||||
Self::TopRight,
|
Self::TopRight,
|
||||||
Self::BottomRight,
|
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::{
|
use bevy_prototype_lyon::{
|
||||||
draw::{Fill, Stroke},
|
draw::{Fill, Stroke},
|
||||||
@ -6,7 +10,18 @@ use bevy_prototype_lyon::{
|
|||||||
path::PathBuilder,
|
path::PathBuilder,
|
||||||
plugin::ShapePlugin,
|
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;
|
pub struct HexGrid;
|
||||||
|
|
||||||
@ -18,45 +33,45 @@ impl Plugin for HexGrid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn setup_system(mut commands: Commands) {
|
pub(super) fn setup_system(mut commands: Commands) {
|
||||||
let radius = 5;
|
let radius = 7;
|
||||||
let hex_positions = generate_hex_grix(radius);
|
let mut grid = generate_hex_grix(radius);
|
||||||
|
|
||||||
let hex_size = 30.;
|
let start_coord = AxialCoord::new(-radius, 0);
|
||||||
let hex_height = hex_size * 2.;
|
let end_coord = AxialCoord::new(radius, 0);
|
||||||
let hex_width = (3.0_f32).sqrt() * hex_size;
|
|
||||||
|
|
||||||
for (q, r) in hex_positions {
|
let mut rng = thread_rng();
|
||||||
let x = hex_width * (q as f32 + r as f32 / 2.);
|
generate_maze(&mut grid, start_coord, &mut rng);
|
||||||
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(),
|
|
||||||
];
|
|
||||||
|
|
||||||
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)> {
|
fn generate_hex_grix(radius: i32) -> HashMap<AxialCoord, Tile> {
|
||||||
let mut positions = Vec::new();
|
let mut grid = HashMap::new();
|
||||||
|
|
||||||
for q in -radius..=radius {
|
for q in -radius..=radius {
|
||||||
let r1 = (-radius).max(-q - radius);
|
let r1 = (-radius).max(-q - radius);
|
||||||
let r2 = radius.min(-q + radius);
|
let r2 = radius.min(-q + radius);
|
||||||
|
|
||||||
for r in r1..=r2 {
|
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)
|
let hex_points = (0..6)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let angle_deg = 60. * i as f32 - 30.;
|
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();
|
path_builder.close();
|
||||||
let hexagon = path_builder.build();
|
let hexagon = path_builder.build();
|
||||||
|
|
||||||
|
// Create the hexagon fill
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
ShapeBundle {
|
ShapeBundle {
|
||||||
path: hexagon,
|
path: hexagon,
|
||||||
@ -82,9 +98,10 @@ fn add_hex_tile(commands: &mut Commands, position: Vec2, size: f32, walls: [bool
|
|||||||
},
|
},
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
Fill::color(Color::srgb(0.8, 0.8, 0.8)),
|
Fill::color(fill_color),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// Draw walls
|
||||||
for i in 0..6 {
|
for i in 0..6 {
|
||||||
if walls[i] {
|
if walls[i] {
|
||||||
let start = hex_points[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 bevy_prototype_lyon::plugin::ShapePlugin;
|
||||||
use grid::setup_system;
|
use grid::setup_system;
|
||||||
|
pub mod direction;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
|
pub mod tile;
|
||||||
|
|
||||||
pub struct HexGrid;
|
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