mirror of
https://github.com/kristoferssolo/maze-ascension.git
synced 2025-10-21 19:20:34 +00:00
feat(dev-tools): add maze orientation toggle
This commit is contained in:
parent
1a0a859fec
commit
8ef2db1d48
@ -1,7 +1,7 @@
|
|||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
use bevy::{prelude::*, window::PrimaryWindow};
|
use bevy::{prelude::*, window::PrimaryWindow};
|
||||||
use hexx::Hex;
|
use hexx::{Hex, HexOrientation};
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
use crate::maze::{events::RecreateMazeEvent, MazeConfig, MazePluginLoaded};
|
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, "Radius:", &mut maze_config.radius, 1.0, 1..=100);
|
||||||
changed |=
|
changed |=
|
||||||
add_drag_value_control(ui, "Height:", &mut maze_config.height, 0.5, 1.0..=50.0);
|
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, "Start Position:", &mut maze_config.start_pos);
|
||||||
changed |= add_position_control(ui, "End Position:", &mut maze_config.end_pos);
|
changed |= add_position_control(ui, "End Position:", &mut maze_config.end_pos);
|
||||||
|
|
||||||
// Trigger recreation if any value changed
|
// Trigger recreation if any value changed
|
||||||
if changed {
|
if changed {
|
||||||
|
maze_config.update();
|
||||||
if let Some(mut event_writer) =
|
if let Some(mut event_writer) =
|
||||||
world.get_resource_mut::<Events<RecreateMazeEvent>>()
|
world.get_resource_mut::<Events<RecreateMazeEvent>>()
|
||||||
{
|
{
|
||||||
@ -115,3 +125,19 @@ fn add_seed_control(ui: &mut Ui, seed: &mut u64) -> bool {
|
|||||||
|
|
||||||
changed
|
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
|
||||||
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
|
use super::MazeConfig;
|
||||||
|
use bevy::prelude::*;
|
||||||
use std::f32::consts::FRAC_PI_2;
|
use std::f32::consts::FRAC_PI_2;
|
||||||
|
|
||||||
use bevy::prelude::*;
|
const WALL_OVERLAP_MODIFIER: f32 = 1.25;
|
||||||
|
const HEX_SIDES: usize = 6;
|
||||||
use super::{resources::WALL_SIZE, MazeConfig};
|
const WHITE_EMISSION_INTENSITY: f32 = 10.;
|
||||||
|
|
||||||
pub(crate) struct MazeAssets {
|
pub(crate) struct MazeAssets {
|
||||||
pub(crate) hex_mesh: Handle<Mesh>,
|
pub(crate) hex_mesh: Handle<Mesh>,
|
||||||
@ -11,22 +13,27 @@ pub(crate) struct MazeAssets {
|
|||||||
pub(crate) wall_material: Handle<StandardMaterial>,
|
pub(crate) wall_material: Handle<StandardMaterial>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create_base_assets(
|
impl MazeAssets {
|
||||||
meshes: &mut ResMut<Assets<Mesh>>,
|
pub(crate) fn new(
|
||||||
materials: &mut ResMut<Assets<StandardMaterial>>,
|
meshes: &mut ResMut<Assets<Mesh>>,
|
||||||
config: &MazeConfig,
|
materials: &mut ResMut<Assets<StandardMaterial>>,
|
||||||
) -> MazeAssets {
|
config: &MazeConfig,
|
||||||
MazeAssets {
|
) -> MazeAssets {
|
||||||
hex_mesh: meshes.add(generate_hex_mesh(config.size, config.height)),
|
MazeAssets {
|
||||||
wall_mesh: meshes.add(generate_square_mesh(config.size)),
|
hex_mesh: meshes.add(generate_hex_mesh(config.hex_size, config.height)),
|
||||||
hex_material: materials.add(white_material()),
|
wall_mesh: meshes.add(generate_square_mesh(
|
||||||
wall_material: materials.add(Color::BLACK),
|
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 {
|
fn generate_hex_mesh(radius: f32, depth: f32) -> Mesh {
|
||||||
let hexagon = RegularPolygon {
|
let hexagon = RegularPolygon {
|
||||||
sides: 6,
|
sides: HEX_SIDES,
|
||||||
circumcircle: Circle::new(radius),
|
circumcircle: Circle::new(radius),
|
||||||
};
|
};
|
||||||
let prism_shape = Extrusion::new(hexagon, depth);
|
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)
|
Mesh::from(prism_shape).rotated_by(rotation)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_square_mesh(depth: f32) -> Mesh {
|
fn generate_square_mesh(depth: f32, wall_size: f32) -> Mesh {
|
||||||
let square = Rectangle::new(WALL_SIZE, WALL_SIZE);
|
let square = Rectangle::new(wall_size, wall_size);
|
||||||
let rectangular_prism = Extrusion::new(square, depth);
|
let rectangular_prism = Extrusion::new(square, depth);
|
||||||
let rotation = Quat::from_rotation_x(FRAC_PI_2);
|
let rotation = Quat::from_rotation_x(FRAC_PI_2);
|
||||||
|
|
||||||
@ -44,10 +51,14 @@ fn generate_square_mesh(depth: f32) -> Mesh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn white_material() -> StandardMaterial {
|
fn white_material() -> StandardMaterial {
|
||||||
let val = 10.;
|
|
||||||
StandardMaterial {
|
StandardMaterial {
|
||||||
base_color: Color::WHITE,
|
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()
|
..default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ use bevy::{
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
events::RecreateMazeEvent,
|
events::RecreateMazeEvent,
|
||||||
resources::Layout,
|
|
||||||
systems::{self, recreation::handle_maze_recreation_event},
|
systems::{self, recreation::handle_maze_recreation_event},
|
||||||
MazeConfig, MazePluginLoaded,
|
MazeConfig, MazePluginLoaded,
|
||||||
};
|
};
|
||||||
@ -16,7 +15,6 @@ 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>()
|
app.init_resource::<MazeConfig>()
|
||||||
.init_resource::<Layout>()
|
|
||||||
.add_event::<RecreateMazeEvent>()
|
.add_event::<RecreateMazeEvent>()
|
||||||
.add_systems(Update, handle_maze_recreation_event);
|
.add_systems(Update, handle_maze_recreation_event);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,6 @@ use thiserror::Error;
|
|||||||
#[reflect(Resource)]
|
#[reflect(Resource)]
|
||||||
pub struct MazePluginLoaded;
|
pub struct MazePluginLoaded;
|
||||||
|
|
||||||
pub(crate) const WALL_SIZE: f32 = 1.0;
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum MazeConfigError {
|
pub enum MazeConfigError {
|
||||||
#[error("Failed to convert radius from u32 to i32: {0}")]
|
#[error("Failed to convert radius from u32 to i32: {0}")]
|
||||||
@ -21,17 +20,19 @@ pub enum MazeConfigError {
|
|||||||
pub struct MazeConfig {
|
pub struct MazeConfig {
|
||||||
pub radius: u32,
|
pub radius: u32,
|
||||||
pub height: f32,
|
pub height: f32,
|
||||||
pub size: f32,
|
pub hex_size: f32,
|
||||||
pub start_pos: Hex,
|
pub start_pos: Hex,
|
||||||
pub end_pos: Hex,
|
pub end_pos: Hex,
|
||||||
pub seed: u64,
|
pub seed: u64,
|
||||||
|
pub layout: HexLayout,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MazeConfig {
|
impl MazeConfig {
|
||||||
fn new(
|
fn new(
|
||||||
radius: u32,
|
radius: u32,
|
||||||
height: f32,
|
height: f32,
|
||||||
size: f32,
|
hex_size: f32,
|
||||||
|
orientation: HexOrientation,
|
||||||
seed: Option<u64>,
|
seed: Option<u64>,
|
||||||
) -> Result<Self, MazeConfigError> {
|
) -> Result<Self, MazeConfigError> {
|
||||||
let seed = seed.unwrap_or_else(|| thread_rng().gen());
|
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!("Start pos: ({},{})", start_pos.x, start_pos.y);
|
||||||
debug!("End pos: ({},{})", end_pos.x, end_pos.y);
|
debug!("End pos: ({},{})", end_pos.x, end_pos.y);
|
||||||
|
|
||||||
|
let layout = HexLayout {
|
||||||
|
orientation,
|
||||||
|
hex_size: Vec2::splat(hex_size),
|
||||||
|
..default()
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
radius: radius as u32,
|
radius: radius as u32,
|
||||||
height,
|
height,
|
||||||
size,
|
hex_size,
|
||||||
start_pos,
|
start_pos,
|
||||||
end_pos,
|
end_pos,
|
||||||
seed,
|
seed,
|
||||||
|
layout,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_unchecked(radius: u32, height: f32, hex_size: f32, seed: Option<u64>) -> Self {
|
pub fn new_unchecked(
|
||||||
Self::new(radius, height, hex_size, seed)
|
radius: u32,
|
||||||
|
height: f32,
|
||||||
|
hex_size: f32,
|
||||||
|
orientation: HexOrientation,
|
||||||
|
seed: Option<u64>,
|
||||||
|
) -> Self {
|
||||||
|
Self::new(radius, height, hex_size, orientation, seed)
|
||||||
.expect("Failed to create MazeConfig with supposedly safe values")
|
.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 {
|
impl Default for MazeConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new_unchecked(7, 20., 6., None)
|
Self::new_unchecked(7, 20., 6., HexOrientation::Flat, 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::<MazeConfig>();
|
|
||||||
Self(HexLayout {
|
|
||||||
orientation: HexOrientation::Flat,
|
|
||||||
hex_size: Vec2::splat(config.size),
|
|
||||||
..default()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
use crate::maze::{
|
use crate::maze::{components::MazeFloor, events::RecreateMazeEvent, MazeConfig};
|
||||||
components::MazeFloor, events::RecreateMazeEvent, resources::Layout, MazeConfig,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::setup::setup_maze;
|
use super::setup::setup_maze;
|
||||||
|
|
||||||
@ -11,13 +9,12 @@ pub(crate) fn handle_maze_recreation_event(
|
|||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
config: Res<MazeConfig>,
|
config: Res<MazeConfig>,
|
||||||
layout: Res<Layout>,
|
|
||||||
query: Query<(Entity, &MazeFloor)>,
|
query: Query<(Entity, &MazeFloor)>,
|
||||||
mut event_reader: EventReader<RecreateMazeEvent>,
|
mut event_reader: EventReader<RecreateMazeEvent>,
|
||||||
) {
|
) {
|
||||||
for event in event_reader.read() {
|
for event in event_reader.read() {
|
||||||
despawn_floor(&mut commands, &query, event.floor);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use hexlab::{GeneratorType, MazeBuilder};
|
use hexlab::{GeneratorType, MazeBuilder};
|
||||||
|
|
||||||
use crate::maze::{
|
use crate::maze::{assets::MazeAssets, components::MazeFloor, MazeConfig};
|
||||||
assets::create_base_assets, components::MazeFloor, resources::Layout, MazeConfig,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::spawn::spawn_single_hex_tile;
|
use super::spawn::spawn_single_hex_tile;
|
||||||
|
|
||||||
@ -12,9 +10,8 @@ pub(crate) fn setup(
|
|||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
config: Res<MazeConfig>,
|
config: Res<MazeConfig>,
|
||||||
layout: Res<Layout>,
|
|
||||||
) {
|
) {
|
||||||
setup_maze(&mut commands, &mut meshes, &mut materials, &config, &layout);
|
setup_maze(&mut commands, &mut meshes, &mut materials, &config);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn setup_maze(
|
pub(super) fn setup_maze(
|
||||||
@ -22,7 +19,6 @@ pub(super) fn setup_maze(
|
|||||||
meshes: &mut ResMut<Assets<Mesh>>,
|
meshes: &mut ResMut<Assets<Mesh>>,
|
||||||
materials: &mut ResMut<Assets<StandardMaterial>>,
|
materials: &mut ResMut<Assets<StandardMaterial>>,
|
||||||
config: &MazeConfig,
|
config: &MazeConfig,
|
||||||
layout: &Layout,
|
|
||||||
) {
|
) {
|
||||||
let maze = MazeBuilder::new()
|
let maze = MazeBuilder::new()
|
||||||
.with_radius(config.radius)
|
.with_radius(config.radius)
|
||||||
@ -31,7 +27,7 @@ pub(super) fn setup_maze(
|
|||||||
.build()
|
.build()
|
||||||
.expect("Something went wrong while creating maze");
|
.expect("Something went wrong while creating maze");
|
||||||
|
|
||||||
let assets = create_base_assets(meshes, materials, config);
|
let assets = MazeAssets::new(meshes, materials, config);
|
||||||
commands
|
commands
|
||||||
.spawn((
|
.spawn((
|
||||||
Name::new("Floor"),
|
Name::new("Floor"),
|
||||||
@ -43,7 +39,7 @@ pub(super) fn setup_maze(
|
|||||||
))
|
))
|
||||||
.with_children(|parent| {
|
.with_children(|parent| {
|
||||||
for tile in maze.values() {
|
for tile in maze.values() {
|
||||||
spawn_single_hex_tile(parent, &assets, tile, &layout.0, &config)
|
spawn_single_hex_tile(parent, &assets, tile, &config)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ use hexx::HexOrientation;
|
|||||||
use crate::maze::{
|
use crate::maze::{
|
||||||
assets::MazeAssets,
|
assets::MazeAssets,
|
||||||
components::{MazeTile, MazeWall},
|
components::{MazeTile, MazeWall},
|
||||||
resources::WALL_SIZE,
|
|
||||||
MazeConfig,
|
MazeConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -15,11 +14,10 @@ pub(super) fn spawn_single_hex_tile(
|
|||||||
parent: &mut ChildBuilder,
|
parent: &mut ChildBuilder,
|
||||||
assets: &MazeAssets,
|
assets: &MazeAssets,
|
||||||
tile: &HexTile,
|
tile: &HexTile,
|
||||||
layout: &HexLayout,
|
|
||||||
config: &MazeConfig,
|
config: &MazeConfig,
|
||||||
) {
|
) {
|
||||||
let world_pos = tile.to_vec3(layout);
|
let world_pos = tile.to_vec3(&config.layout);
|
||||||
let rotation = match layout.orientation {
|
let rotation = match config.layout.orientation {
|
||||||
HexOrientation::Pointy => Quat::from_rotation_y(0.0),
|
HexOrientation::Pointy => Quat::from_rotation_y(0.0),
|
||||||
HexOrientation::Flat => Quat::from_rotation_y(FRAC_PI_6), // 30 degrees rotation
|
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 wall_angle = -FRAC_PI_3 * i as f32;
|
||||||
|
|
||||||
let x_offset = (config.size - WALL_SIZE) * f32::cos(wall_angle);
|
let x_offset = config.wall_offset() * f32::cos(wall_angle);
|
||||||
let z_offset = (config.size - WALL_SIZE) * f32::sin(wall_angle);
|
let z_offset = config.wall_offset() * f32::sin(wall_angle);
|
||||||
let pos = Vec3::new(x_offset, y_offset, z_offset);
|
let pos = Vec3::new(x_offset, y_offset, z_offset);
|
||||||
|
|
||||||
let x_rotation = Quat::from_rotation_x(wall_angle + FRAC_PI_2);
|
let x_rotation = Quat::from_rotation_x(wall_angle + FRAC_PI_2);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user