feat(maze): add maze recreation ability

This commit is contained in:
Kristofers Solo 2024-12-08 17:09:21 +02:00
parent 0ca94082a9
commit 24b92a24cc
10 changed files with 116 additions and 17 deletions

View File

@ -7,23 +7,29 @@ use bevy::{
}, },
input::common_conditions::input_just_pressed, input::common_conditions::input_just_pressed,
prelude::*, prelude::*,
window::PrimaryWindow,
}; };
use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_inspector_egui::{bevy_egui::EguiContext, DefaultInspectorConfigPlugin};
use crate::screens::Screen; use crate::{maze::events::RecreateMazeEvent, screens::Screen};
use bevy_egui::{
egui::{self, Button, Color32, ScrollArea},
EguiPlugin,
};
pub(super) fn plugin(app: &mut App) { pub(super) fn plugin(app: &mut App) {
// Log `Screen` state transitions. // Log `Screen` state transitions.
app.add_systems(Update, log_transitions::<Screen>); app.add_systems(Update, log_transitions::<Screen>)
.add_plugins(EguiPlugin)
// Toggle the debug overlay for UI. .add_plugins(DebugUiPlugin)
app.add_plugins(DebugUiPlugin); .add_plugins(DefaultInspectorConfigPlugin)
app.add_plugins(WorldInspectorPlugin::default()); .add_systems(Update, inspector_ui)
app.add_systems( // Toggle the debug overlay for UI.
Update, .add_systems(
toggle_debug_ui.run_if(input_just_pressed(TOGGLE_KEY)), Update,
); toggle_debug_ui.run_if(input_just_pressed(TOGGLE_KEY)),
);
} }
const TOGGLE_KEY: KeyCode = KeyCode::Backquote; const TOGGLE_KEY: KeyCode = KeyCode::Backquote;
@ -31,3 +37,30 @@ const TOGGLE_KEY: KeyCode = KeyCode::Backquote;
fn toggle_debug_ui(mut options: ResMut<UiDebugOptions>) { fn toggle_debug_ui(mut options: ResMut<UiDebugOptions>) {
options.toggle(); options.toggle();
} }
fn inspector_ui(world: &mut World) {
let Ok(egui_context) = world
.query_filtered::<&mut EguiContext, With<PrimaryWindow>>()
.get_single(world)
else {
return;
};
let mut egui_context = egui_context.clone();
egui::Window::new("UI").show(egui_context.get_mut(), |ui| {
ScrollArea::vertical().show(ui, |ui| {
bevy_inspector_egui::bevy_inspector::ui_for_world(world, ui);
});
ui.add_space(8.);
let button = Button::new("Recreate maze").fill(Color32::from_rgb(108, 108, 108));
if ui.add(button).clicked() {
if let Some(mut event_writer) = world.get_resource_mut::<Events<RecreateMazeEvent>>() {
event_writer.send(RecreateMazeEvent { floor: 1 });
}
}
});
}

View File

@ -17,7 +17,7 @@ pub(crate) struct MazeAssets {
pub(crate) fn create_base_assets( pub(crate) fn create_base_assets(
meshes: &mut ResMut<Assets<Mesh>>, meshes: &mut ResMut<Assets<Mesh>>,
materials: &mut ResMut<Assets<StandardMaterial>>, materials: &mut ResMut<Assets<StandardMaterial>>,
config: &Res<MazeConfig>, config: &MazeConfig,
) -> MazeAssets { ) -> MazeAssets {
MazeAssets { MazeAssets {
hex_mesh: meshes.add(generate_hex_mesh(HEX_SIZE, config.height)), hex_mesh: meshes.add(generate_hex_mesh(HEX_SIZE, config.height)),

View File

@ -2,8 +2,12 @@ use bevy::prelude::*;
#[derive(Debug, Reflect, Component)] #[derive(Debug, Reflect, Component)]
#[reflect(Component)] #[reflect(Component)]
pub(crate) struct MazeWall; pub(crate) struct MazeFloor(pub(crate) u8);
#[derive(Debug, Reflect, Component)] #[derive(Debug, Reflect, Component)]
#[reflect(Component)] #[reflect(Component)]
pub(crate) struct MazeTile; pub(crate) struct MazeTile;
#[derive(Debug, Reflect, Component)]
#[reflect(Component)]
pub(crate) struct MazeWall;

6
src/maze/events.rs Normal file
View File

@ -0,0 +1,6 @@
use bevy::prelude::*;
#[derive(Debug, Event)]
pub(crate) struct RecreateMazeEvent {
pub(crate) floor: u8,
}

View File

@ -2,6 +2,7 @@ use bevy::{ecs::world::Command, prelude::*};
use plugin::MazePlugin; use plugin::MazePlugin;
mod assets; mod assets;
mod components; mod components;
pub mod events;
pub mod plugin; pub mod plugin;
mod resources; mod resources;
mod systems; mod systems;

View File

@ -3,14 +3,22 @@ use bevy::{
prelude::*, prelude::*,
}; };
use super::{resources::Layout, systems, MazeConfig}; use super::{
events::RecreateMazeEvent,
resources::Layout,
systems::{self, recreation::handle_maze_recreation_event},
MazeConfig,
};
#[derive(Default)] #[derive(Default)]
pub(crate) struct MazePlugin; pub(crate) struct MazePlugin;
impl Plugin for MazePlugin { impl Plugin for MazePlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.init_resource::<MazeConfig>().init_resource::<Layout>(); app.init_resource::<MazeConfig>()
.init_resource::<Layout>()
.add_event::<RecreateMazeEvent>()
.add_systems(Update, handle_maze_recreation_event);
} }
} }

View File

@ -1,2 +1,3 @@
pub mod recreation;
pub mod setup; pub mod setup;
mod spawn; mod spawn;

View File

@ -0,0 +1,30 @@
use bevy::prelude::*;
use crate::maze::{
components::MazeFloor, events::RecreateMazeEvent, resources::Layout, MazeConfig,
};
use super::setup::setup_maze;
pub(crate) fn handle_maze_recreation_event(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
config: Res<MazeConfig>,
layout: Res<Layout>,
query: Query<(Entity, &MazeFloor)>,
mut event_reader: EventReader<RecreateMazeEvent>,
) {
for event in event_reader.read() {
despawn_floor(&mut commands, &query, event.floor);
setup_maze(&mut commands, &mut meshes, &mut materials, &config, &layout);
}
}
fn despawn_floor(commands: &mut Commands, query: &Query<(Entity, &MazeFloor)>, floor_num: u8) {
for (entity, maze_floor) in query.iter() {
if maze_floor.0 == floor_num {
commands.entity(entity).despawn_recursive();
}
}
}

View File

@ -1,7 +1,9 @@
use bevy::prelude::*; use bevy::prelude::*;
use hexlab::{GeneratorType, MazeBuilder}; use hexlab::{GeneratorType, MazeBuilder};
use crate::maze::{assets::create_base_assets, resources::Layout, MazeConfig}; use crate::maze::{
assets::create_base_assets, components::MazeFloor, resources::Layout, MazeConfig,
};
use super::spawn::spawn_single_hex_tile; use super::spawn::spawn_single_hex_tile;
@ -11,6 +13,16 @@ pub(crate) fn setup(
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
config: Res<MazeConfig>, config: Res<MazeConfig>,
layout: Res<Layout>, layout: Res<Layout>,
) {
setup_maze(&mut commands, &mut meshes, &mut materials, &config, &layout);
}
pub(super) fn setup_maze(
commands: &mut Commands,
meshes: &mut ResMut<Assets<Mesh>>,
materials: &mut ResMut<Assets<StandardMaterial>>,
config: &MazeConfig,
layout: &Layout,
) { ) {
let maze = MazeBuilder::new() let maze = MazeBuilder::new()
.with_radius(config.radius) .with_radius(config.radius)
@ -19,10 +31,11 @@ pub(crate) fn setup(
.build() .build()
.expect("Something went wrong while creating maze"); .expect("Something went wrong while creating maze");
let assets = create_base_assets(&mut meshes, &mut materials, &config); let assets = create_base_assets(meshes, materials, config);
commands commands
.spawn(( .spawn((
Name::new("Floor"), Name::new("Floor"),
MazeFloor(1),
SpatialBundle { SpatialBundle {
transform: Transform::from_translation(Vec3::ZERO), transform: Transform::from_translation(Vec3::ZERO),
..default() ..default()

View File

@ -6,6 +6,7 @@ use hexx::HexOrientation;
use crate::maze::{ use crate::maze::{
assets::MazeAssets, assets::MazeAssets,
components::{MazeTile, MazeWall},
resources::{HEX_SIZE, WALL_SIZE}, resources::{HEX_SIZE, WALL_SIZE},
}; };
@ -25,6 +26,7 @@ pub(super) fn spawn_single_hex_tile(
parent parent
.spawn(( .spawn((
Name::new(format!("Hex {}", tile.to_string())), Name::new(format!("Hex {}", tile.to_string())),
MazeTile,
PbrBundle { PbrBundle {
mesh: assets.hex_mesh.clone(), mesh: assets.hex_mesh.clone(),
material: assets.hex_material.clone(), material: assets.hex_material.clone(),
@ -64,6 +66,7 @@ fn spawn_single_wall(
) { ) {
parent.spawn(( parent.spawn((
Name::new("Wall"), Name::new("Wall"),
MazeWall,
PbrBundle { PbrBundle {
mesh: asstets.wall_mesh.clone(), mesh: asstets.wall_mesh.clone(),
material: asstets.wall_material.clone(), material: asstets.wall_material.clone(),