mirror of
https://github.com/kristoferssolo/maze-ascension.git
synced 2025-10-21 19:20:34 +00:00
feat(grid): add precidualy generated maze grid
This commit is contained in:
parent
f16fd51090
commit
c5f8dede6d
@ -17,7 +17,7 @@ tracing = { version = "0.1", features = [
|
|||||||
"max_level_debug",
|
"max_level_debug",
|
||||||
"release_max_level_warn",
|
"release_max_level_warn",
|
||||||
] }
|
] }
|
||||||
hexx = { version = "0.18", features = ["bevy_reflect"] }
|
hexx = { version = "0.18", features = ["bevy_reflect", "grid"] }
|
||||||
bevy_prototype_lyon = "0.12"
|
bevy_prototype_lyon = "0.12"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
use bevy::prelude::*;
|
|
||||||
use hexx::EdgeDirection;
|
|
||||||
|
|
||||||
pub(super) fn plugin(_app: &mut App) {}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)]
|
|
||||||
pub enum Direction {
|
|
||||||
Top,
|
|
||||||
TopRight,
|
|
||||||
BottomRight,
|
|
||||||
Bottom,
|
|
||||||
BottomLeft,
|
|
||||||
TopLeft,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Direction {
|
|
||||||
pub const ALL: [Direction; 6] = [
|
|
||||||
Self::Top,
|
|
||||||
Self::TopRight,
|
|
||||||
Self::BottomRight,
|
|
||||||
Self::Bottom,
|
|
||||||
Self::BottomLeft,
|
|
||||||
Self::TopLeft,
|
|
||||||
];
|
|
||||||
|
|
||||||
pub fn opposite(&self) -> Self {
|
|
||||||
match self {
|
|
||||||
Self::Top => Self::Bottom,
|
|
||||||
Self::TopRight => Self::BottomLeft,
|
|
||||||
Self::BottomRight => Self::TopLeft,
|
|
||||||
Self::Bottom => Self::Top,
|
|
||||||
Self::BottomLeft => Self::TopRight,
|
|
||||||
Self::TopLeft => Self::BottomRight,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,194 +0,0 @@
|
|||||||
use bevy::{
|
|
||||||
color::palettes::css::{BLACK, GREEN, RED},
|
|
||||||
prelude::*,
|
|
||||||
utils::hashbrown::HashMap,
|
|
||||||
};
|
|
||||||
|
|
||||||
use bevy_prototype_lyon::{
|
|
||||||
draw::{Fill, Stroke},
|
|
||||||
entity::ShapeBundle,
|
|
||||||
path::PathBuilder,
|
|
||||||
plugin::ShapePlugin,
|
|
||||||
};
|
|
||||||
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;
|
|
||||||
|
|
||||||
impl Plugin for HexGrid {
|
|
||||||
fn build(&self, app: &mut App) {
|
|
||||||
app.add_plugins(ShapePlugin);
|
|
||||||
app.add_systems(Startup, setup_system);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn setup_system(mut commands: Commands) {
|
|
||||||
let radius = 7;
|
|
||||||
let mut grid = generate_hex_grix(radius);
|
|
||||||
|
|
||||||
let start_coord = AxialCoord::new(-radius, 0);
|
|
||||||
let end_coord = AxialCoord::new(radius, 0);
|
|
||||||
|
|
||||||
let mut rng = thread_rng();
|
|
||||||
generate_maze(&mut grid, start_coord, &mut rng);
|
|
||||||
|
|
||||||
render_maze(&mut commands, &mut grid, radius, start_coord, end_coord);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
let coord = AxialCoord::new(q, r);
|
|
||||||
let tile = Tile {
|
|
||||||
position: coord,
|
|
||||||
walls: [true; 6],
|
|
||||||
visited: false,
|
|
||||||
};
|
|
||||||
grid.insert(coord, tile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
grid
|
|
||||||
}
|
|
||||||
|
|
||||||
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.;
|
|
||||||
let angle_rad = angle_deg.to_radians();
|
|
||||||
Vec2::new(size * angle_rad.cos(), size * angle_rad.sin())
|
|
||||||
})
|
|
||||||
.collect::<Vec<Vec2>>();
|
|
||||||
|
|
||||||
let mut path_builder = PathBuilder::new();
|
|
||||||
path_builder.move_to(hex_points[0]);
|
|
||||||
for point in &hex_points[1..] {
|
|
||||||
path_builder.line_to(*point);
|
|
||||||
}
|
|
||||||
path_builder.close();
|
|
||||||
let hexagon = path_builder.build();
|
|
||||||
|
|
||||||
// Create the hexagon fill
|
|
||||||
commands.spawn((
|
|
||||||
ShapeBundle {
|
|
||||||
path: hexagon,
|
|
||||||
spatial: SpatialBundle {
|
|
||||||
transform: Transform::from_xyz(position.x, position.y, 0.),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
Fill::color(fill_color),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Draw walls
|
|
||||||
for i in 0..6 {
|
|
||||||
if walls[i] {
|
|
||||||
let start = hex_points[i];
|
|
||||||
let end = hex_points[(i + 1) % 6];
|
|
||||||
let mut line_builder = PathBuilder::new();
|
|
||||||
line_builder.move_to(start);
|
|
||||||
line_builder.line_to(end);
|
|
||||||
let line = line_builder.build();
|
|
||||||
|
|
||||||
commands.spawn((
|
|
||||||
ShapeBundle {
|
|
||||||
path: line,
|
|
||||||
spatial: SpatialBundle {
|
|
||||||
transform: Transform::from_xyz(position.x, position.y, 1.),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
Stroke::new(BLACK, 2.),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
use bevy::{
|
|
||||||
ecs::{system::RunSystemOnce, world::Command},
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
use bevy_prototype_lyon::plugin::ShapePlugin;
|
|
||||||
use grid::setup_system;
|
|
||||||
pub mod direction;
|
|
||||||
pub mod grid;
|
|
||||||
pub mod tile;
|
|
||||||
|
|
||||||
pub struct HexGrid;
|
|
||||||
|
|
||||||
impl Plugin for HexGrid {
|
|
||||||
fn build(&self, app: &mut App) {
|
|
||||||
app.add_plugins(ShapePlugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for HexGrid {
|
|
||||||
fn apply(self, world: &mut World) {
|
|
||||||
world.run_system_once(setup_system);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spawn_grid(world: &mut World) {
|
|
||||||
HexGrid.apply(world);
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
#[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 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,7 +5,7 @@ mod demo;
|
|||||||
#[cfg(feature = "dev")]
|
#[cfg(feature = "dev")]
|
||||||
mod dev_tools;
|
mod dev_tools;
|
||||||
#[cfg(not(feature = "demo"))]
|
#[cfg(not(feature = "demo"))]
|
||||||
mod hexgrid;
|
mod maze;
|
||||||
mod screens;
|
mod screens;
|
||||||
mod theme;
|
mod theme;
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ impl Plugin for AppPlugin {
|
|||||||
#[cfg(feature = "demo")]
|
#[cfg(feature = "demo")]
|
||||||
demo::plugin,
|
demo::plugin,
|
||||||
#[cfg(not(feature = "demo"))]
|
#[cfg(not(feature = "demo"))]
|
||||||
hexgrid::HexGrid,
|
maze::MazePlugin,
|
||||||
screens::plugin,
|
screens::plugin,
|
||||||
theme::plugin,
|
theme::plugin,
|
||||||
));
|
));
|
||||||
|
|||||||
218
src/maze/grid.rs
Normal file
218
src/maze/grid.rs
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
use std::usize;
|
||||||
|
|
||||||
|
use bevy::{
|
||||||
|
color::palettes::css::{BLACK, GREEN, RED},
|
||||||
|
prelude::*,
|
||||||
|
utils::hashbrown::HashMap,
|
||||||
|
};
|
||||||
|
|
||||||
|
use bevy_prototype_lyon::{
|
||||||
|
draw::{Fill, Stroke},
|
||||||
|
entity::ShapeBundle,
|
||||||
|
path::PathBuilder,
|
||||||
|
plugin::ShapePlugin,
|
||||||
|
};
|
||||||
|
use hexx::{EdgeDirection, Hex};
|
||||||
|
use log::info;
|
||||||
|
use rand::{prelude::SliceRandom, rngs::ThreadRng, thread_rng};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
resource::{Layout, MazeConfig},
|
||||||
|
tile::{Tile, TileBundle, Walls},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(super) fn plugin(app: &mut App) {
|
||||||
|
app.add_plugins(ShapePlugin);
|
||||||
|
app.init_resource::<MazeConfig>();
|
||||||
|
app.init_resource::<Layout>();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn spawn_hex_grid(mut commands: Commands, config: Res<MazeConfig>) {
|
||||||
|
let radius = config.radius as i32;
|
||||||
|
|
||||||
|
for q in -radius..=radius {
|
||||||
|
let r1 = (-radius).max(-q - radius);
|
||||||
|
let r2 = radius.min(-q + radius);
|
||||||
|
for r in r1..=r2 {
|
||||||
|
let tile = Tile::new(q, r);
|
||||||
|
commands.spawn((
|
||||||
|
Name::new(format!("Tile {}", &tile.to_string())),
|
||||||
|
TileBundle {
|
||||||
|
hex: tile,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn generate_maze(
|
||||||
|
mut commands: Commands,
|
||||||
|
query: Query<(Entity, &Tile, &Walls)>,
|
||||||
|
config: Res<MazeConfig>,
|
||||||
|
) {
|
||||||
|
let mut tiles = query
|
||||||
|
.into_iter()
|
||||||
|
.map(|(entity, tile, walls)| (tile.hex, (entity, tile.clone(), walls.clone())))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
recursive_maze(&mut tiles, config.start_pos, &mut rng);
|
||||||
|
|
||||||
|
for (entity, tile, walls) in tiles.values() {
|
||||||
|
commands
|
||||||
|
.entity(*entity)
|
||||||
|
.insert(tile.clone())
|
||||||
|
.insert(walls.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recursive_maze(
|
||||||
|
tiles: &mut HashMap<Hex, (Entity, Tile, Walls)>,
|
||||||
|
current_hex: Hex,
|
||||||
|
rng: &mut ThreadRng,
|
||||||
|
) {
|
||||||
|
{
|
||||||
|
let (_, tile, _) = tiles.get_mut(¤t_hex).unwrap();
|
||||||
|
tile.visit();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut directions = EdgeDirection::ALL_DIRECTIONS;
|
||||||
|
directions.shuffle(rng);
|
||||||
|
|
||||||
|
for direction in directions.into_iter() {
|
||||||
|
let neighbor_hex = current_hex + direction;
|
||||||
|
if let Some((_, neighbor_tile, _)) = tiles.get(&neighbor_hex) {
|
||||||
|
if !neighbor_tile.visited {
|
||||||
|
remove_wall_between(tiles, current_hex, neighbor_hex, direction);
|
||||||
|
recursive_maze(tiles, neighbor_hex, rng);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_wall_between(
|
||||||
|
tiles: &mut HashMap<Hex, (Entity, Tile, Walls)>,
|
||||||
|
current_hex: Hex,
|
||||||
|
neighbor_hex: Hex,
|
||||||
|
direction: EdgeDirection,
|
||||||
|
) {
|
||||||
|
{
|
||||||
|
let (_, _, walls) = tiles.get_mut(¤t_hex).unwrap();
|
||||||
|
walls.0[direction.index() as usize] = false;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let (_, _, walls) = tiles.get_mut(&neighbor_hex).unwrap();
|
||||||
|
walls.0[direction.const_neg().index() as usize] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_hex_tile(
|
||||||
|
commands: &mut Commands,
|
||||||
|
position: Vec2,
|
||||||
|
size: f32,
|
||||||
|
tile: &Tile,
|
||||||
|
walls: &Walls,
|
||||||
|
fill_color: Color,
|
||||||
|
layout: &Layout,
|
||||||
|
) {
|
||||||
|
let hex_points = tile
|
||||||
|
.hex
|
||||||
|
.all_vertices()
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| {
|
||||||
|
let mut layout = layout.clone();
|
||||||
|
layout.origin = position;
|
||||||
|
layout.hex_size = Vec2::splat(size);
|
||||||
|
layout.hex_to_world_pos(v.origin + v.direction)
|
||||||
|
})
|
||||||
|
.collect::<Vec<Vec2>>();
|
||||||
|
|
||||||
|
let mut path_builder = PathBuilder::new();
|
||||||
|
path_builder.move_to(hex_points[0]);
|
||||||
|
for point in &hex_points[1..] {
|
||||||
|
path_builder.line_to(*point);
|
||||||
|
}
|
||||||
|
path_builder.close();
|
||||||
|
let hexagon = path_builder.build();
|
||||||
|
|
||||||
|
// Create the hexagon fill
|
||||||
|
commands.spawn((
|
||||||
|
ShapeBundle {
|
||||||
|
path: hexagon,
|
||||||
|
spatial: SpatialBundle {
|
||||||
|
transform: Transform::from_xyz(position.x, position.y, 0.),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
Fill::color(fill_color),
|
||||||
|
));
|
||||||
|
// .with_children(|p| {
|
||||||
|
// p.spawn(Text2dBundle {
|
||||||
|
// text: Text {
|
||||||
|
// sections: vec![TextSection {
|
||||||
|
// value: tile.to_string(),
|
||||||
|
// style: TextStyle {
|
||||||
|
// font_size: 16.,
|
||||||
|
// color: Color::BLACK,
|
||||||
|
// ..default()
|
||||||
|
// },
|
||||||
|
// }],
|
||||||
|
// ..default()
|
||||||
|
// },
|
||||||
|
// transform: Transform::from_xyz(position.x * 2., position.y * 2., 1.),
|
||||||
|
// ..default()
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Draw walls
|
||||||
|
for direction in EdgeDirection::iter() {
|
||||||
|
let idx = direction.index() as usize;
|
||||||
|
if walls[idx] {
|
||||||
|
let start = hex_points[idx];
|
||||||
|
let end = hex_points[(idx + 1) % 6];
|
||||||
|
let mut line_builder = PathBuilder::new();
|
||||||
|
line_builder.move_to(start);
|
||||||
|
line_builder.line_to(end);
|
||||||
|
let line = line_builder.build();
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
ShapeBundle {
|
||||||
|
path: line,
|
||||||
|
spatial: SpatialBundle {
|
||||||
|
transform: Transform::from_xyz(position.x, position.y, 1.),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
Stroke::new(BLACK, 2.),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn render_maze(
|
||||||
|
mut commands: Commands,
|
||||||
|
query: Query<(&Tile, &mut Walls)>,
|
||||||
|
layout: Res<Layout>,
|
||||||
|
config: Res<MazeConfig>,
|
||||||
|
) {
|
||||||
|
for (tile, walls) in query.iter() {
|
||||||
|
let world_pos = layout.hex_to_world_pos(tile.hex);
|
||||||
|
let fill_color = match tile.hex {
|
||||||
|
pos if pos == config.start_pos => GREEN.into(),
|
||||||
|
pos if pos == config.end_pos => RED.into(),
|
||||||
|
_ => Color::srgb(0.8, 0.8, 0.8),
|
||||||
|
};
|
||||||
|
add_hex_tile(
|
||||||
|
&mut commands,
|
||||||
|
world_pos,
|
||||||
|
config.size,
|
||||||
|
tile,
|
||||||
|
walls,
|
||||||
|
fill_color,
|
||||||
|
&layout,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/maze/mod.rs
Normal file
28
src/maze/mod.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
use bevy::{
|
||||||
|
ecs::{system::RunSystemOnce, world::Command},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
use grid::{generate_maze, plugin, render_maze, spawn_hex_grid};
|
||||||
|
pub mod grid;
|
||||||
|
pub mod resource;
|
||||||
|
pub mod tile;
|
||||||
|
|
||||||
|
pub struct MazePlugin;
|
||||||
|
|
||||||
|
impl Plugin for MazePlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_plugins(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for MazePlugin {
|
||||||
|
fn apply(self, world: &mut World) {
|
||||||
|
world.run_system_once(spawn_hex_grid);
|
||||||
|
world.run_system_once(generate_maze);
|
||||||
|
world.run_system_once(render_maze);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_grid(world: &mut World) {
|
||||||
|
MazePlugin.apply(world);
|
||||||
|
}
|
||||||
53
src/maze/resource.rs
Normal file
53
src/maze/resource.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use hexx::{Hex, HexLayout, HexOrientation};
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
|
#[derive(Debug, Reflect, Resource)]
|
||||||
|
#[reflect(Resource)]
|
||||||
|
pub struct MazeConfig {
|
||||||
|
pub radius: u32,
|
||||||
|
pub size: f32,
|
||||||
|
pub start_pos: Hex,
|
||||||
|
pub end_pos: Hex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MazeConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
let radius = 5;
|
||||||
|
let start_pos = Hex::new(
|
||||||
|
rng.gen_range(-radius..radius),
|
||||||
|
rng.gen_range(-radius..radius),
|
||||||
|
);
|
||||||
|
let end_pos = Hex::new(
|
||||||
|
rng.gen_range(-radius..radius),
|
||||||
|
rng.gen_range(-radius..radius),
|
||||||
|
);
|
||||||
|
debug!("Start pos: ({},{})", start_pos.x, start_pos.y);
|
||||||
|
debug!("End pos: ({},{})", end_pos.x, end_pos.y);
|
||||||
|
Self {
|
||||||
|
radius: radius as u32,
|
||||||
|
size: 10.,
|
||||||
|
start_pos,
|
||||||
|
end_pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Reflect, Resource, Deref, DerefMut, Clone)]
|
||||||
|
#[reflect(Resource)]
|
||||||
|
pub struct Layout(pub HexLayout);
|
||||||
|
|
||||||
|
impl FromWorld for Layout {
|
||||||
|
fn from_world(world: &mut World) -> Self {
|
||||||
|
let size = world
|
||||||
|
.get_resource::<MazeConfig>()
|
||||||
|
.unwrap_or(&MazeConfig::default())
|
||||||
|
.size;
|
||||||
|
Self(HexLayout {
|
||||||
|
orientation: HexOrientation::Pointy,
|
||||||
|
hex_size: Vec2::splat(size),
|
||||||
|
..default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/maze/tile.rs
Normal file
46
src/maze/tile.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use hexx::Hex;
|
||||||
|
|
||||||
|
#[derive(Debug, Reflect, Component, Default, PartialEq, Eq, Hash, Clone)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct Tile {
|
||||||
|
pub hex: Hex,
|
||||||
|
pub visited: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Reflect, Component, Deref, DerefMut, Clone)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct Walls(pub [bool; 6]);
|
||||||
|
|
||||||
|
#[derive(Debug, Reflect, Bundle, Default)]
|
||||||
|
pub struct TileBundle {
|
||||||
|
pub hex: Tile,
|
||||||
|
pub walls: Walls,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tile {
|
||||||
|
pub fn new(q: i32, r: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
hex: Hex::new(q, r),
|
||||||
|
visited: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit(&mut self) {
|
||||||
|
self.visited = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Tile {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "({},{})", self.hex.x, self.hex.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Walls {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self([true; 6])
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,7 @@ use bevy::{input::common_conditions::input_just_pressed, prelude::*};
|
|||||||
#[cfg(feature = "demo")]
|
#[cfg(feature = "demo")]
|
||||||
use crate::demo::level::spawn_level as spawn_level_command;
|
use crate::demo::level::spawn_level as spawn_level_command;
|
||||||
#[cfg(not(feature = "demo"))]
|
#[cfg(not(feature = "demo"))]
|
||||||
use crate::hexgrid::spawn_grid as spawn_level_command;
|
use crate::maze::spawn_grid as spawn_level_command;
|
||||||
use crate::{asset_tracking::LoadResource, audio::Music, screens::Screen};
|
use crate::{asset_tracking::LoadResource, audio::Music, screens::Screen};
|
||||||
|
|
||||||
pub(super) fn plugin(app: &mut App) {
|
pub(super) fn plugin(app: &mut App) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user