mirror of
https://github.com/kristoferssolo/maze-ascension.git
synced 2025-10-21 19:20:34 +00:00
fix(floor): multiple floor create
This commit is contained in:
parent
433a3ce5e8
commit
4635b0f134
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -2669,11 +2669,13 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
||||
|
||||
[[package]]
|
||||
name = "hexlab"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b912e78d292803bc279aec3a4e2a0cdd0e0ac1540bcdc5d0f32cbfe9e4d234dc"
|
||||
checksum = "94f91bb99b0ef58661cc4c18e9bab7bba9e66a3d3047fec9af76e31381647442"
|
||||
dependencies = [
|
||||
"bevy",
|
||||
"bevy_reflect",
|
||||
"bevy_utils",
|
||||
"glam",
|
||||
"hexx",
|
||||
"rand",
|
||||
"thiserror 2.0.6",
|
||||
|
||||
@ -18,7 +18,7 @@ tracing = { version = "0.1", features = [
|
||||
"release_max_level_warn",
|
||||
] }
|
||||
hexx = { version = "0.19", features = ["bevy_reflect", "grid"] }
|
||||
hexlab = { version = "0.3", features = ["bevy"] }
|
||||
hexlab = { version = "0.4", features = ["bevy_reflect"] }
|
||||
bevy-inspector-egui = { version = "0.28", optional = true }
|
||||
bevy_egui = { version = "0.31", optional = true }
|
||||
thiserror = "2.0"
|
||||
|
||||
1
justfile
1
justfile
@ -17,4 +17,3 @@ web-dev:
|
||||
# Run web release
|
||||
web-release:
|
||||
trunk serve --release --no-default-features
|
||||
|
||||
|
||||
@ -1,27 +1,45 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::maze::components::MazeConfig;
|
||||
use super::components::Floor;
|
||||
|
||||
#[derive(Debug, Reflect, Event)]
|
||||
pub struct SpawnFloor {
|
||||
pub floor: u8,
|
||||
pub config: MazeConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Reflect, Event)]
|
||||
pub struct RespawnFloor {
|
||||
pub floor: u8,
|
||||
pub config: MazeConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Reflect, Event)]
|
||||
pub struct DespawnFloor {
|
||||
pub floor: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Reflect, Event, Default)]
|
||||
#[derive(Debug, Clone, Copy, Reflect, Event, Default, PartialEq, Eq)]
|
||||
pub enum TransitionFloor {
|
||||
#[default]
|
||||
Ascend,
|
||||
Descend,
|
||||
}
|
||||
|
||||
impl TransitionFloor {
|
||||
pub fn into_direction(&self) -> f32 {
|
||||
self.into()
|
||||
}
|
||||
|
||||
pub fn opposite(&self) -> Self {
|
||||
match self {
|
||||
Self::Ascend => Self::Descend,
|
||||
Self::Descend => Self::Ascend,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_floor_num(&self, floor: &Floor) -> u8 {
|
||||
match self {
|
||||
Self::Ascend => *floor.increased(),
|
||||
Self::Descend => *floor.decreased(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransitionFloor> for f32 {
|
||||
fn from(value: TransitionFloor) -> Self {
|
||||
f32::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&TransitionFloor> for f32 {
|
||||
fn from(value: &TransitionFloor) -> Self {
|
||||
match value {
|
||||
TransitionFloor::Ascend => -1.,
|
||||
TransitionFloor::Descend => 1.,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
pub mod components;
|
||||
pub mod events;
|
||||
pub mod resources;
|
||||
mod systems;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use events::TransitionFloor;
|
||||
use resources::HighestFloor;
|
||||
|
||||
pub(super) fn plugin(app: &mut App) {
|
||||
app.add_event::<TransitionFloor>()
|
||||
.insert_resource(HighestFloor(1))
|
||||
.add_plugins(systems::plugin);
|
||||
}
|
||||
|
||||
5
src/floor/resources.rs
Normal file
5
src/floor/resources.rs
Normal file
@ -0,0 +1,5 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
#[derive(Debug, Default, Reflect, Resource, PartialEq, Eq)]
|
||||
#[reflect(Resource)]
|
||||
pub struct HighestFloor(pub u8);
|
||||
0
src/floor/systems/clear_events.rs
Normal file
0
src/floor/systems/clear_events.rs
Normal file
@ -1,3 +1,4 @@
|
||||
mod clear_events;
|
||||
mod despawn;
|
||||
mod movement;
|
||||
mod spawn;
|
||||
|
||||
@ -39,11 +39,16 @@ pub(super) fn handle_floor_transition_events(
|
||||
next_query: Query<Entity, With<NextFloor>>,
|
||||
mut event_reader: EventReader<TransitionFloor>,
|
||||
) {
|
||||
let is_moving = maze_query
|
||||
.iter()
|
||||
.any(|(_, _, movement_state)| movement_state.is_some());
|
||||
|
||||
if is_moving {
|
||||
return;
|
||||
}
|
||||
|
||||
for event in event_reader.read() {
|
||||
let direction = match event {
|
||||
TransitionFloor::Ascend => -1.,
|
||||
TransitionFloor::Descend => 1.,
|
||||
};
|
||||
let direction = event.into();
|
||||
|
||||
let Some((current_entity, current_y)) = get_floor_info(&maze_query, ¤t_query) else {
|
||||
continue;
|
||||
@ -64,6 +69,7 @@ pub(super) fn handle_floor_transition_events(
|
||||
}
|
||||
|
||||
update_current_next_floor(&mut commands, current_entity, next_entity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use crate::{
|
||||
floor::{
|
||||
components::{CurrentFloor, Floor},
|
||||
components::{CurrentFloor, Floor, MovementState},
|
||||
events::TransitionFloor,
|
||||
resources::HighestFloor,
|
||||
},
|
||||
maze::events::SpawnMaze,
|
||||
};
|
||||
@ -10,23 +11,31 @@ use bevy::prelude::*;
|
||||
pub(super) fn spawn_floor(
|
||||
mut commands: Commands,
|
||||
query: Query<&mut Floor, With<CurrentFloor>>,
|
||||
movement_state_query: Query<Option<&MovementState>>,
|
||||
mut event_reader: EventReader<TransitionFloor>,
|
||||
mut highest_floor: ResMut<HighestFloor>,
|
||||
) {
|
||||
let Ok(floor) = query.get_single() else {
|
||||
return;
|
||||
};
|
||||
|
||||
for event in event_reader.read() {
|
||||
let floor = match event {
|
||||
TransitionFloor::Ascend => *floor.increased(),
|
||||
TransitionFloor::Descend => *floor.decreased(),
|
||||
};
|
||||
let is_moving = movement_state_query
|
||||
.iter()
|
||||
.any(|movement_state| movement_state.is_some());
|
||||
if is_moving {
|
||||
return;
|
||||
}
|
||||
|
||||
if floor == 1 {
|
||||
for event in event_reader.read() {
|
||||
let floor = event.next_floor_num(floor);
|
||||
|
||||
if floor == 1 && *event == TransitionFloor::Descend {
|
||||
warn!("Cannot descend below floor 1");
|
||||
return;
|
||||
}
|
||||
|
||||
highest_floor.0 = highest_floor.0.max(floor);
|
||||
|
||||
info!("Creating level for floor {}", floor);
|
||||
|
||||
commands.trigger(SpawnMaze { floor, ..default() });
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::floor::components::Floor;
|
||||
|
||||
use super::{errors::MazeConfigError, GlobalMazeConfig};
|
||||
use super::GlobalMazeConfig;
|
||||
use bevy::prelude::*;
|
||||
use hexlab::HexMaze;
|
||||
use hexx::{Hex, HexLayout, HexOrientation};
|
||||
@ -22,7 +22,7 @@ pub struct Wall;
|
||||
#[derive(Debug, Reflect, Component, Clone)]
|
||||
#[reflect(Component)]
|
||||
pub struct MazeConfig {
|
||||
pub radius: u32,
|
||||
pub radius: u16,
|
||||
pub start_pos: Hex,
|
||||
pub end_pos: Hex,
|
||||
pub seed: u64,
|
||||
@ -31,19 +31,21 @@ pub struct MazeConfig {
|
||||
|
||||
impl MazeConfig {
|
||||
fn new(
|
||||
radius: u32,
|
||||
radius: u16,
|
||||
orientation: HexOrientation,
|
||||
seed: Option<u64>,
|
||||
global_conig: &GlobalMazeConfig,
|
||||
) -> Result<Self, MazeConfigError> {
|
||||
) -> Self {
|
||||
let seed = seed.unwrap_or_else(|| thread_rng().gen());
|
||||
let mut rng = StdRng::seed_from_u64(seed);
|
||||
|
||||
let start_pos = generate_pos(radius, &mut rng)?;
|
||||
let end_pos = generate_pos(radius, &mut rng)?;
|
||||
let start_pos = generate_pos(radius, &mut rng);
|
||||
let end_pos = generate_pos(radius, &mut rng);
|
||||
|
||||
info!("Start pos: (q={}, r={})", start_pos.x, start_pos.y);
|
||||
info!("End pos: (q={}, r={})", end_pos.x, end_pos.y);
|
||||
info!(
|
||||
"Start pos: (q={}, r={}). End pos: (q={}, r={})",
|
||||
start_pos.x, start_pos.y, end_pos.x, end_pos.y
|
||||
);
|
||||
|
||||
let layout = HexLayout {
|
||||
orientation,
|
||||
@ -51,23 +53,13 @@ impl MazeConfig {
|
||||
..default()
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
Self {
|
||||
radius,
|
||||
start_pos,
|
||||
end_pos,
|
||||
seed,
|
||||
layout,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_unchecked(
|
||||
radius: u32,
|
||||
orientation: HexOrientation,
|
||||
seed: Option<u64>,
|
||||
global_conig: &GlobalMazeConfig,
|
||||
) -> Self {
|
||||
Self::new(radius, orientation, seed, global_conig)
|
||||
.expect("Failed to create MazeConfig with supposedly safe values")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, global_conig: &GlobalMazeConfig) {
|
||||
@ -77,14 +69,14 @@ impl MazeConfig {
|
||||
|
||||
impl Default for MazeConfig {
|
||||
fn default() -> Self {
|
||||
Self::new_unchecked(7, HexOrientation::Flat, None, &GlobalMazeConfig::default())
|
||||
Self::new(8, HexOrientation::Flat, None, &GlobalMazeConfig::default())
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_pos<R: Rng>(radius: u32, rng: &mut R) -> Result<Hex, MazeConfigError> {
|
||||
let radius = i32::try_from(radius)?;
|
||||
Ok(Hex::new(
|
||||
fn generate_pos<R: Rng>(radius: u16, rng: &mut R) -> Hex {
|
||||
let radius = radius as i32;
|
||||
Hex::new(
|
||||
rng.gen_range(-radius..radius),
|
||||
rng.gen_range(-radius..radius),
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ pub enum MazeError {
|
||||
#[error("Floor {0} not found")]
|
||||
FloorNotFound(u8),
|
||||
#[error("Failed to generate maze with config: {radius}, seed: {seed}")]
|
||||
GenerationFailed { radius: u32, seed: u64 },
|
||||
GenerationFailed { radius: u16, seed: u64 },
|
||||
#[error("Invalid tile entity: {0:?}")]
|
||||
TileNotFound(bevy::prelude::Entity),
|
||||
#[error("Failed to create maze assets")]
|
||||
@ -32,7 +32,7 @@ impl MazeError {
|
||||
Self::ConfigurationError(msg.into())
|
||||
}
|
||||
|
||||
pub const fn generation_failed(radius: u32, seed: u64) -> Self {
|
||||
pub const fn generation_failed(radius: u16, seed: u64) -> Self {
|
||||
Self::GenerationFailed { radius, seed }
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,12 @@ pub(super) fn spawn_maze(
|
||||
}
|
||||
};
|
||||
|
||||
let y_offset = (floor - 1) * FLOOR_Y_OFFSET;
|
||||
let y_offset = match *floor {
|
||||
1 => 0,
|
||||
_ => FLOOR_Y_OFFSET,
|
||||
} as f32;
|
||||
|
||||
// (floor - 1) * FLOOR_Y_OFFSET
|
||||
|
||||
let entity = commands
|
||||
.spawn((
|
||||
@ -46,7 +51,7 @@ pub(super) fn spawn_maze(
|
||||
Maze(maze.clone()),
|
||||
Floor(*floor),
|
||||
config.clone(),
|
||||
Transform::from_translation(Vec3::ZERO.with_y(y_offset as f32)),
|
||||
Transform::from_translation(Vec3::ZERO.with_y(y_offset)),
|
||||
Visibility::Visible,
|
||||
))
|
||||
.insert_if(CurrentFloor, || *floor == 1)
|
||||
|
||||
@ -7,16 +7,17 @@ use bevy::prelude::*;
|
||||
|
||||
pub(super) fn ascend_player(
|
||||
query: Query<&CurrentPosition, With<Player>>,
|
||||
maze_config_query: Query<&MazeConfig, With<CurrentFloor>>,
|
||||
maze_config: Query<&MazeConfig, With<CurrentFloor>>,
|
||||
mut event_writer: EventWriter<TransitionFloor>,
|
||||
) {
|
||||
let Ok(config) = maze_config_query.get_single() else {
|
||||
let Ok(config) = maze_config.get_single() else {
|
||||
warn!("Failed to get maze configuration for current floor - cannot ascend player");
|
||||
return;
|
||||
};
|
||||
|
||||
for current_hex in query.iter() {
|
||||
if current_hex.0 == config.end_pos {
|
||||
dbg!("Ascend");
|
||||
event_writer.send(TransitionFloor::Ascend);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -11,10 +11,10 @@ use crate::{
|
||||
|
||||
pub(super) fn descend_player(
|
||||
query: Query<&CurrentPosition, With<Player>>,
|
||||
maze_config_query: Query<(&MazeConfig, &Floor), With<CurrentFloor>>,
|
||||
maze_config: Query<(&MazeConfig, &Floor), With<CurrentFloor>>,
|
||||
mut event_writer: EventWriter<TransitionFloor>,
|
||||
) {
|
||||
let Ok((config, floor)) = maze_config_query.get_single() else {
|
||||
let Ok((config, floor)) = maze_config.get_single() else {
|
||||
warn!("Failed to get maze configuration for current floor - cannot descend player");
|
||||
return;
|
||||
};
|
||||
|
||||
@ -11,10 +11,12 @@ pub const HEADER_TEXT: Color = Color::srgb(0.867, 0.827, 0.412);
|
||||
|
||||
pub const NODE_BACKGROUND: Color = Color::srgb(0.286, 0.478, 0.773);
|
||||
|
||||
const MAX_COLOR_VALUE: f32 = 255.;
|
||||
|
||||
pub(super) const fn rgb_u8(red: u8, green: u8, blue: u8) -> Color {
|
||||
Color::srgb(scale(red), scale(green), scale(blue))
|
||||
}
|
||||
|
||||
const fn scale(value: u8) -> f32 {
|
||||
value as f32 / 255.
|
||||
value as f32 / MAX_COLOR_VALUE
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user