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