feat(player): add player respawn and despawn

This commit is contained in:
Kristofers Solo 2024-12-12 20:33:26 +02:00
parent b89921dcd6
commit f4aefb00fa
19 changed files with 162 additions and 121 deletions

7
Cargo.lock generated
View File

@ -2589,12 +2589,13 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "hexlab"
version = "0.2.1"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b912e78d292803bc279aec3a4e2a0cdd0e0ac1540bcdc5d0f32cbfe9e4d234dc"
dependencies = [
"bevy",
"hexx",
"rand",
"rand_chacha",
"thiserror 2.0.6",
]
@ -3076,7 +3077,7 @@ dependencies = [
[[package]]
name = "maze-ascension"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"bevy",
"bevy-inspector-egui",

View File

@ -1,7 +1,7 @@
[package]
name = "maze-ascension"
authors = ["Kristofers Solo <dev@kristofers.xyz>"]
version = "0.1.0"
version = "0.2.0"
edition = "2021"
[dependencies]
@ -18,7 +18,7 @@ tracing = { version = "0.1", features = [
"release_max_level_warn",
] }
hexx = { version = "0.19", features = ["bevy_reflect", "grid"] }
hexlab = { path = "../hexlab", features = ["bevy"] }
hexlab = { version = "0.3", features = ["bevy"] }
bevy-inspector-egui = { version = "0.28", optional = true }
bevy_egui = { version = "0.31", optional = true }
thiserror = "2.0"

View File

@ -1,14 +1,15 @@
use std::ops::RangeInclusive;
use crate::{
maze::{events::RecreateMazeEvent, MazeConfig, MazePluginLoaded},
player::events::RespawnPlayer,
};
use bevy::{prelude::*, window::PrimaryWindow};
use hexx::{Hex, HexOrientation};
use rand::{thread_rng, Rng};
use crate::maze::{events::RecreateMazeEvent, MazeConfig, MazePluginLoaded};
use bevy_egui::{
egui::{self, emath::Numeric, DragValue, TextEdit, Ui},
EguiContext,
};
use hexx::{Hex, HexOrientation};
use rand::{thread_rng, Rng};
use std::ops::RangeInclusive;
pub(crate) fn maze_controls_ui(world: &mut World) {
if world.get_resource::<MazePluginLoaded>().is_none() {
@ -55,6 +56,9 @@ pub(crate) fn maze_controls_ui(world: &mut World) {
{
event_writer.send(RecreateMazeEvent { floor: 1 });
}
if let Some(mut event_writer) = world.get_resource_mut::<Events<RespawnPlayer>>() {
event_writer.send(RespawnPlayer);
}
}
}
});
@ -82,9 +86,9 @@ fn add_position_control(ui: &mut Ui, label: &str, pos: &mut Hex) -> bool {
ui.horizontal(|ui| {
ui.label(label);
let response_x = ui.add(DragValue::new(&mut pos.x).speed(1).prefix("x: "));
let response_y = ui.add(DragValue::new(&mut pos.y).speed(1).prefix("y: "));
changed = response_x.changed() || response_y.changed();
let response_q = ui.add(DragValue::new(&mut pos.x).speed(1).prefix("q: "));
let response_r = ui.add(DragValue::new(&mut pos.y).speed(1).prefix("r: "));
changed = response_r.changed() || response_q.changed();
});
changed
}

View File

@ -7,12 +7,11 @@ mod resources;
mod systems;
pub use resources::{MazeConfig, MazePluginLoaded};
use systems::recreation::handle_maze_recreation_event;
pub(super) fn plugin(app: &mut App) {
app.init_resource::<MazeConfig>()
.add_event::<RecreateMazeEvent>()
.add_systems(Update, handle_maze_recreation_event);
.add_plugins(systems::plugin);
}
pub fn spawn_level_command(world: &mut World) {

View File

@ -1,28 +0,0 @@
use bevy::{
ecs::{system::RunSystemOnce, world::Command},
prelude::*,
};
use super::{
events::RecreateMazeEvent,
systems::{self, recreation::handle_maze_recreation_event},
MazeConfig, MazePluginLoaded,
};
#[derive(Default)]
pub(crate) struct MazePlugin;
impl Plugin for MazePlugin {
fn build(&self, app: &mut App) {
app.init_resource::<MazeConfig>()
.add_event::<RecreateMazeEvent>()
.add_systems(Update, handle_maze_recreation_event);
}
}
impl Command for MazePlugin {
fn apply(self, world: &mut World) {
world.insert_resource(MazePluginLoaded);
let _ = world.run_system_once(systems::setup::setup);
}
}

View File

@ -40,8 +40,8 @@ impl MazeConfig {
let start_pos = generate_pos(radius, &mut rng)?;
let end_pos = generate_pos(radius, &mut rng)?;
debug!("Start pos: ({},{})", start_pos.x, start_pos.y);
debug!("End pos: ({},{})", end_pos.x, end_pos.y);
info!("Start pos: (q={}, r={})", start_pos.x, start_pos.y);
info!("End pos: (q={}, r={})", end_pos.x, end_pos.y);
let layout = HexLayout {
orientation,

View File

@ -1,3 +1,14 @@
use crate::maze::components::Floor;
use bevy::prelude::*;
use crate::maze::components::MazeFloor;
pub(crate) fn despawn_floor(
commands: &mut Commands,
query: &Query<(Entity, &Floor)>,
floor_num: u8,
) {
for (entity, floor) in query.iter() {
if floor.0 == floor_num {
commands.entity(entity).despawn_recursive();
}
}
}

View File

@ -1,3 +1,11 @@
pub mod despawn;
pub mod recreation;
pub mod setup;
mod spawn;
pub mod spawn;
use bevy::prelude::*;
use recreation::recreate_maze;
pub(super) fn plugin(app: &mut App) {
app.add_systems(Update, recreate_maze);
}

View File

@ -2,9 +2,9 @@ use bevy::prelude::*;
use crate::maze::{components::Floor, events::RecreateMazeEvent, MazeConfig};
use super::setup::setup_maze;
use super::{despawn::despawn_floor, spawn::spawn_floor};
pub(crate) fn handle_maze_recreation_event(
pub(crate) fn recreate_maze(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
@ -14,14 +14,6 @@ pub(crate) fn handle_maze_recreation_event(
) {
for event in event_reader.read() {
despawn_floor(&mut commands, &query, event.floor);
setup_maze(&mut commands, &mut meshes, &mut materials, &config);
}
}
fn despawn_floor(commands: &mut Commands, query: &Query<(Entity, &Floor)>, floor_num: u8) {
for (entity, floor) in query.iter() {
if floor.0 == floor_num {
commands.entity(entity).despawn_recursive();
}
spawn_floor(&mut commands, &mut meshes, &mut materials, &config);
}
}

View File

@ -1,13 +1,6 @@
use super::spawn::spawn_floor;
use crate::maze::MazeConfig;
use bevy::prelude::*;
use hexlab::{GeneratorType, MazeBuilder};
use crate::maze::{
assets::MazeAssets,
components::{Floor, Maze},
MazeConfig,
};
use super::spawn::spawn_single_hex_tile;
pub(crate) fn setup(
mut commands: Commands,
@ -15,34 +8,5 @@ pub(crate) fn setup(
mut materials: ResMut<Assets<StandardMaterial>>,
config: Res<MazeConfig>,
) {
setup_maze(&mut commands, &mut meshes, &mut materials, &config);
}
pub(super) fn setup_maze(
commands: &mut Commands,
meshes: &mut ResMut<Assets<Mesh>>,
materials: &mut ResMut<Assets<StandardMaterial>>,
config: &MazeConfig,
) {
let maze = MazeBuilder::new()
.with_radius(config.radius)
.with_seed(config.seed)
.with_generator(GeneratorType::RecursiveBacktracking)
.build()
.expect("Something went wrong while creating maze");
let assets = MazeAssets::new(meshes, materials, config);
commands
.spawn((
Name::new("Floor"),
Maze(maze.clone()),
Floor(1),
Transform::from_translation(Vec3::ZERO),
Visibility::Visible,
))
.with_children(|parent| {
for tile in maze.values() {
spawn_single_hex_tile(parent, &assets, tile, config)
}
});
spawn_floor(&mut commands, &mut meshes, &mut materials, &config);
}

View File

@ -1,14 +1,41 @@
use std::f32::consts::{FRAC_PI_2, FRAC_PI_3, FRAC_PI_6};
use crate::maze::{
assets::MazeAssets,
components::{Floor, Maze, Tile, Wall},
MazeConfig,
};
use bevy::prelude::*;
use hexlab::prelude::*;
use hexx::HexOrientation;
use std::f32::consts::{FRAC_PI_2, FRAC_PI_3, FRAC_PI_6};
use crate::maze::{
assets::MazeAssets,
components::{Tile, Wall},
MazeConfig,
};
pub(super) fn spawn_floor(
commands: &mut Commands,
meshes: &mut ResMut<Assets<Mesh>>,
materials: &mut ResMut<Assets<StandardMaterial>>,
config: &MazeConfig,
) {
let maze = MazeBuilder::new()
.with_radius(config.radius)
.with_seed(config.seed)
.with_generator(GeneratorType::RecursiveBacktracking)
.build()
.expect("Something went wrong while creating maze");
let assets = MazeAssets::new(meshes, materials, config);
commands
.spawn((
Name::new("Floor"),
Maze(maze.clone()),
Floor(1),
Transform::from_translation(Vec3::ZERO),
Visibility::Visible,
))
.with_children(|parent| {
for tile in maze.values() {
spawn_single_hex_tile(parent, &assets, tile, config)
}
});
}
pub(super) fn spawn_single_hex_tile(
parent: &mut ChildBuilder,

View File

@ -16,7 +16,7 @@ pub struct MovementSpeed(pub f32);
impl Default for MovementSpeed {
fn default() -> Self {
Self(50.)
Self(100.)
}
}

4
src/player/events.rs Normal file
View File

@ -0,0 +1,4 @@
use bevy::prelude::*;
#[derive(Debug, Event)]
pub(crate) struct RespawnPlayer;

View File

@ -1,14 +1,18 @@
mod assets;
pub mod components;
pub mod events;
mod systems;
use bevy::{ecs::system::RunSystemOnce, prelude::*};
use components::Player;
use events::RespawnPlayer;
pub(super) fn plugin(app: &mut App) {
app.register_type::<Player>().add_plugins(systems::plugin);
app.register_type::<Player>()
.add_event::<RespawnPlayer>()
.add_plugins(systems::plugin);
}
pub fn spawn_player_command(world: &mut World) {
let _ = world.run_system_once(systems::spawn::spawn_player);
let _ = world.run_system_once(systems::setup::setup);
}

View File

@ -0,0 +1,9 @@
use bevy::prelude::*;
use crate::player::components::Player;
pub(crate) fn despawn_players(commands: &mut Commands, query: &Query<Entity, With<Player>>) {
for entity in query.iter() {
commands.entity(entity).despawn_recursive();
}
}

View File

@ -1,11 +1,22 @@
pub mod despawn;
mod input;
mod movement;
pub mod respawn;
pub mod setup;
pub mod spawn;
use bevy::prelude::*;
use input::player_input;
use movement::player_movement;
use respawn::respawn_player;
pub(super) fn plugin(app: &mut App) {
app.add_systems(Update, (player_input, player_movement.after(player_input)));
app.add_systems(
Update,
(
player_input,
player_movement.after(player_input),
respawn_player,
),
);
}

View File

@ -0,0 +1,21 @@
use crate::{
maze::MazeConfig,
player::{components::Player, events::RespawnPlayer},
};
use bevy::prelude::*;
use super::{despawn::despawn_players, spawn::spawn_player};
pub(crate) fn respawn_player(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
config: Res<MazeConfig>,
query: Query<Entity, With<Player>>,
mut event_reader: EventReader<RespawnPlayer>,
) {
for _ in event_reader.read() {
despawn_players(&mut commands, &query);
spawn_player(&mut commands, &mut meshes, &mut materials, &config);
}
}

View File

@ -0,0 +1,14 @@
use bevy::prelude::*;
use crate::maze::MazeConfig;
use super::spawn::spawn_player;
pub(crate) fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
config: Res<MazeConfig>,
) {
spawn_player(&mut commands, &mut meshes, &mut materials, &config);
}

View File

@ -6,26 +6,26 @@ use crate::{
},
};
use bevy::prelude::*;
use hexx::Hex;
pub fn spawn_player(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
maze_config: Res<MazeConfig>,
pub(super) fn spawn_player(
commands: &mut Commands,
meshes: &mut ResMut<Assets<Mesh>>,
materials: &mut ResMut<Assets<StandardMaterial>>,
config: &MazeConfig,
) {
let player_height = maze_config.height * 0.5;
let player_radius = maze_config.hex_size * 0.5;
let player_radius = config.hex_size * 0.5;
let player_height = player_radius * 3.5;
let start_hex = Hex::new(1, 1);
let start_pos = maze_config.layout.hex_to_world_pos(start_hex);
let y_offset = config.height / 2. + player_height / 1.3;
let start_pos = config.layout.hex_to_world_pos(config.start_pos);
commands.spawn((
Name::new("Player"),
Player,
CurrentPosition(start_hex),
CurrentPosition(config.start_pos),
Mesh3d(meshes.add(generate_pill_mesh(player_radius, player_height / 2.))),
MeshMaterial3d(materials.add(blue_material())),
Transform::from_xyz(start_pos.x, player_height * 2., start_pos.y),
Transform::from_xyz(start_pos.x, y_offset, start_pos.y),
));
}