From 8ef2db1d48928dcbe13eecbdf950d4c92336810e Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Sun, 8 Dec 2024 19:30:58 +0200 Subject: [PATCH] feat(dev-tools): add maze orientation toggle --- src/dev_tools/ui/maze_controls.rs | 28 +++++++++++++++- src/maze/assets.rs | 47 ++++++++++++++++---------- src/maze/plugin.rs | 2 -- src/maze/resources.rs | 55 ++++++++++++++++++------------- src/maze/systems/recreation.rs | 7 ++-- src/maze/systems/setup.rs | 12 +++---- src/maze/systems/spawn.rs | 10 +++--- 7 files changed, 99 insertions(+), 62 deletions(-) diff --git a/src/dev_tools/ui/maze_controls.rs b/src/dev_tools/ui/maze_controls.rs index f5b0a0a..387fbdc 100644 --- a/src/dev_tools/ui/maze_controls.rs +++ b/src/dev_tools/ui/maze_controls.rs @@ -1,7 +1,7 @@ use std::ops::RangeInclusive; use bevy::{prelude::*, window::PrimaryWindow}; -use hexx::Hex; +use hexx::{Hex, HexOrientation}; use rand::{thread_rng, Rng}; use crate::maze::{events::RecreateMazeEvent, MazeConfig, MazePluginLoaded}; @@ -34,12 +34,22 @@ pub(crate) fn maze_controls_ui(world: &mut World) { changed |= add_drag_value_control(ui, "Radius:", &mut maze_config.radius, 1.0, 1..=100); changed |= add_drag_value_control(ui, "Height:", &mut maze_config.height, 0.5, 1.0..=50.0); + changed |= add_drag_value_control( + ui, + "Hex Size:", + &mut maze_config.hex_size, + 1.0, + 1.0..=100.0, + ); + + changed |= add_orientation_control(ui, &mut maze_config.layout.orientation); changed |= add_position_control(ui, "Start Position:", &mut maze_config.start_pos); changed |= add_position_control(ui, "End Position:", &mut maze_config.end_pos); // Trigger recreation if any value changed if changed { + maze_config.update(); if let Some(mut event_writer) = world.get_resource_mut::>() { @@ -115,3 +125,19 @@ fn add_seed_control(ui: &mut Ui, seed: &mut u64) -> bool { changed } + +fn add_orientation_control(ui: &mut Ui, orientation: &mut HexOrientation) -> bool { + let mut changed = false; + + ui.horizontal(|ui| { + ui.label("Orientation:"); + + let response = ui.radio_value(orientation, HexOrientation::Flat, "Flat"); + changed |= response.changed(); + + let response = ui.radio_value(orientation, HexOrientation::Pointy, "Pointy"); + changed |= response.changed(); + }); + + changed +} diff --git a/src/maze/assets.rs b/src/maze/assets.rs index 5a2d31d..3d3dba5 100644 --- a/src/maze/assets.rs +++ b/src/maze/assets.rs @@ -1,8 +1,10 @@ +use super::MazeConfig; +use bevy::prelude::*; use std::f32::consts::FRAC_PI_2; -use bevy::prelude::*; - -use super::{resources::WALL_SIZE, MazeConfig}; +const WALL_OVERLAP_MODIFIER: f32 = 1.25; +const HEX_SIDES: usize = 6; +const WHITE_EMISSION_INTENSITY: f32 = 10.; pub(crate) struct MazeAssets { pub(crate) hex_mesh: Handle, @@ -11,22 +13,27 @@ pub(crate) struct MazeAssets { pub(crate) wall_material: Handle, } -pub(crate) fn create_base_assets( - meshes: &mut ResMut>, - materials: &mut ResMut>, - config: &MazeConfig, -) -> MazeAssets { - MazeAssets { - hex_mesh: meshes.add(generate_hex_mesh(config.size, config.height)), - wall_mesh: meshes.add(generate_square_mesh(config.size)), - hex_material: materials.add(white_material()), - wall_material: materials.add(Color::BLACK), +impl MazeAssets { + pub(crate) fn new( + meshes: &mut ResMut>, + materials: &mut ResMut>, + config: &MazeConfig, + ) -> MazeAssets { + MazeAssets { + hex_mesh: meshes.add(generate_hex_mesh(config.hex_size, config.height)), + wall_mesh: meshes.add(generate_square_mesh( + config.hex_size + config.wall_size() / WALL_OVERLAP_MODIFIER, + config.wall_size(), + )), + hex_material: materials.add(white_material()), + wall_material: materials.add(Color::BLACK), + } } } fn generate_hex_mesh(radius: f32, depth: f32) -> Mesh { let hexagon = RegularPolygon { - sides: 6, + sides: HEX_SIDES, circumcircle: Circle::new(radius), }; let prism_shape = Extrusion::new(hexagon, depth); @@ -35,8 +42,8 @@ fn generate_hex_mesh(radius: f32, depth: f32) -> Mesh { Mesh::from(prism_shape).rotated_by(rotation) } -fn generate_square_mesh(depth: f32) -> Mesh { - let square = Rectangle::new(WALL_SIZE, WALL_SIZE); +fn generate_square_mesh(depth: f32, wall_size: f32) -> Mesh { + let square = Rectangle::new(wall_size, wall_size); let rectangular_prism = Extrusion::new(square, depth); let rotation = Quat::from_rotation_x(FRAC_PI_2); @@ -44,10 +51,14 @@ fn generate_square_mesh(depth: f32) -> Mesh { } fn white_material() -> StandardMaterial { - let val = 10.; StandardMaterial { base_color: Color::WHITE, - emissive: LinearRgba::new(val, val, val, val), + emissive: LinearRgba::new( + WHITE_EMISSION_INTENSITY, + WHITE_EMISSION_INTENSITY, + WHITE_EMISSION_INTENSITY, + WHITE_EMISSION_INTENSITY, + ), ..default() } } diff --git a/src/maze/plugin.rs b/src/maze/plugin.rs index 2e24d7f..cd60cba 100644 --- a/src/maze/plugin.rs +++ b/src/maze/plugin.rs @@ -5,7 +5,6 @@ use bevy::{ use super::{ events::RecreateMazeEvent, - resources::Layout, systems::{self, recreation::handle_maze_recreation_event}, MazeConfig, MazePluginLoaded, }; @@ -16,7 +15,6 @@ pub(crate) struct MazePlugin; impl Plugin for MazePlugin { fn build(&self, app: &mut App) { app.init_resource::() - .init_resource::() .add_event::() .add_systems(Update, handle_maze_recreation_event); } diff --git a/src/maze/resources.rs b/src/maze/resources.rs index 7e7245a..5c4dc60 100644 --- a/src/maze/resources.rs +++ b/src/maze/resources.rs @@ -9,7 +9,6 @@ use thiserror::Error; #[reflect(Resource)] pub struct MazePluginLoaded; -pub(crate) const WALL_SIZE: f32 = 1.0; #[derive(Debug, Error)] pub enum MazeConfigError { #[error("Failed to convert radius from u32 to i32: {0}")] @@ -21,17 +20,19 @@ pub enum MazeConfigError { pub struct MazeConfig { pub radius: u32, pub height: f32, - pub size: f32, + pub hex_size: f32, pub start_pos: Hex, pub end_pos: Hex, pub seed: u64, + pub layout: HexLayout, } impl MazeConfig { fn new( radius: u32, height: f32, - size: f32, + hex_size: f32, + orientation: HexOrientation, seed: Option, ) -> Result { let seed = seed.unwrap_or_else(|| thread_rng().gen()); @@ -43,40 +44,50 @@ impl MazeConfig { debug!("Start pos: ({},{})", start_pos.x, start_pos.y); debug!("End pos: ({},{})", end_pos.x, end_pos.y); + let layout = HexLayout { + orientation, + hex_size: Vec2::splat(hex_size), + ..default() + }; + Ok(Self { radius: radius as u32, height, - size, + hex_size, start_pos, end_pos, seed, + layout, }) } - pub fn new_unchecked(radius: u32, height: f32, hex_size: f32, seed: Option) -> Self { - Self::new(radius, height, hex_size, seed) + pub fn new_unchecked( + radius: u32, + height: f32, + hex_size: f32, + orientation: HexOrientation, + seed: Option, + ) -> Self { + Self::new(radius, height, hex_size, orientation, seed) .expect("Failed to create MazeConfig with supposedly safe values") } + + pub fn wall_size(&self) -> f32 { + self.hex_size / 6. + } + + pub fn wall_offset(&self) -> f32 { + self.hex_size - self.wall_size() + } + + pub fn update(&mut self) { + self.layout.hex_size = Vec2::splat(self.hex_size); + } } impl Default for MazeConfig { fn default() -> Self { - Self::new_unchecked(7, 20., 6., None) - } -} - -#[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 config = world.resource::(); - Self(HexLayout { - orientation: HexOrientation::Flat, - hex_size: Vec2::splat(config.size), - ..default() - }) + Self::new_unchecked(7, 20., 6., HexOrientation::Flat, None) } } diff --git a/src/maze/systems/recreation.rs b/src/maze/systems/recreation.rs index cadd2cb..b3a6472 100644 --- a/src/maze/systems/recreation.rs +++ b/src/maze/systems/recreation.rs @@ -1,8 +1,6 @@ use bevy::prelude::*; -use crate::maze::{ - components::MazeFloor, events::RecreateMazeEvent, resources::Layout, MazeConfig, -}; +use crate::maze::{components::MazeFloor, events::RecreateMazeEvent, MazeConfig}; use super::setup::setup_maze; @@ -11,13 +9,12 @@ pub(crate) fn handle_maze_recreation_event( mut meshes: ResMut>, mut materials: ResMut>, config: Res, - layout: Res, query: Query<(Entity, &MazeFloor)>, mut event_reader: EventReader, ) { for event in event_reader.read() { despawn_floor(&mut commands, &query, event.floor); - setup_maze(&mut commands, &mut meshes, &mut materials, &config, &layout); + setup_maze(&mut commands, &mut meshes, &mut materials, &config); } } diff --git a/src/maze/systems/setup.rs b/src/maze/systems/setup.rs index 96556ad..58cae06 100644 --- a/src/maze/systems/setup.rs +++ b/src/maze/systems/setup.rs @@ -1,9 +1,7 @@ use bevy::prelude::*; use hexlab::{GeneratorType, MazeBuilder}; -use crate::maze::{ - assets::create_base_assets, components::MazeFloor, resources::Layout, MazeConfig, -}; +use crate::maze::{assets::MazeAssets, components::MazeFloor, MazeConfig}; use super::spawn::spawn_single_hex_tile; @@ -12,9 +10,8 @@ pub(crate) fn setup( mut meshes: ResMut>, mut materials: ResMut>, config: Res, - layout: Res, ) { - setup_maze(&mut commands, &mut meshes, &mut materials, &config, &layout); + setup_maze(&mut commands, &mut meshes, &mut materials, &config); } pub(super) fn setup_maze( @@ -22,7 +19,6 @@ pub(super) fn setup_maze( meshes: &mut ResMut>, materials: &mut ResMut>, config: &MazeConfig, - layout: &Layout, ) { let maze = MazeBuilder::new() .with_radius(config.radius) @@ -31,7 +27,7 @@ pub(super) fn setup_maze( .build() .expect("Something went wrong while creating maze"); - let assets = create_base_assets(meshes, materials, config); + let assets = MazeAssets::new(meshes, materials, config); commands .spawn(( Name::new("Floor"), @@ -43,7 +39,7 @@ pub(super) fn setup_maze( )) .with_children(|parent| { for tile in maze.values() { - spawn_single_hex_tile(parent, &assets, tile, &layout.0, &config) + spawn_single_hex_tile(parent, &assets, tile, &config) } }); } diff --git a/src/maze/systems/spawn.rs b/src/maze/systems/spawn.rs index ca6b8d8..838ae3d 100644 --- a/src/maze/systems/spawn.rs +++ b/src/maze/systems/spawn.rs @@ -7,7 +7,6 @@ use hexx::HexOrientation; use crate::maze::{ assets::MazeAssets, components::{MazeTile, MazeWall}, - resources::WALL_SIZE, MazeConfig, }; @@ -15,11 +14,10 @@ pub(super) fn spawn_single_hex_tile( parent: &mut ChildBuilder, assets: &MazeAssets, tile: &HexTile, - layout: &HexLayout, config: &MazeConfig, ) { - let world_pos = tile.to_vec3(layout); - let rotation = match layout.orientation { + let world_pos = tile.to_vec3(&config.layout); + let rotation = match config.layout.orientation { HexOrientation::Pointy => Quat::from_rotation_y(0.0), HexOrientation::Flat => Quat::from_rotation_y(FRAC_PI_6), // 30 degrees rotation }; @@ -49,8 +47,8 @@ fn spawn_walls(parent: &mut ChildBuilder, assets: &MazeAssets, config: &MazeConf let wall_angle = -FRAC_PI_3 * i as f32; - let x_offset = (config.size - WALL_SIZE) * f32::cos(wall_angle); - let z_offset = (config.size - WALL_SIZE) * f32::sin(wall_angle); + let x_offset = config.wall_offset() * f32::cos(wall_angle); + let z_offset = config.wall_offset() * f32::sin(wall_angle); let pos = Vec3::new(x_offset, y_offset, z_offset); let x_rotation = Quat::from_rotation_x(wall_angle + FRAC_PI_2);