From 730daed20a9fc1144a4d2d42f81ec5eae4cab7e7 Mon Sep 17 00:00:00 2001 From: Xevion Date: Fri, 15 Aug 2025 10:06:09 -0500 Subject: [PATCH] feat: entity type for proper edge permission calculations --- src/game/mod.rs | 3 ++- src/systems/components.rs | 11 +++++++++++ src/systems/movement.rs | 22 +++++++++++++--------- src/systems/render.rs | 13 +++++++++++-- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/game/mod.rs b/src/game/mod.rs index 5c56540..1991cac 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -8,7 +8,7 @@ use crate::error::{GameError, GameResult, TextureError}; use crate::events::GameEvent; use crate::map::builder::Map; use crate::systems::components::{ - DeltaTime, DirectionalAnimated, GlobalState, PlayerBundle, PlayerControlled, Position, Renderable, Velocity, + DeltaTime, DirectionalAnimated, EntityType, GlobalState, PlayerBundle, PlayerControlled, Position, Renderable, Velocity, }; use crate::systems::control::player_system; use crate::systems::movement::movement_system; @@ -143,6 +143,7 @@ impl Game { textures, stopped_textures, }, + entity_type: EntityType::Player, }; world.insert_non_send_resource(atlas); diff --git a/src/systems/components.rs b/src/systems/components.rs index 3ab2e89..e58e3ae 100644 --- a/src/systems/components.rs +++ b/src/systems/components.rs @@ -11,6 +11,16 @@ use crate::{ #[derive(Default, Component)] pub struct PlayerControlled; +/// A tag component denoting the type of entity. +#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum EntityType { + Player, + Ghost, + Pellet, + PowerPellet, + Wall, +} + /// A component for entities that have a sprite, with a layer for ordering. /// /// This is intended to be modified by other entities allowing animation. @@ -127,6 +137,7 @@ pub struct PlayerBundle { pub velocity: Velocity, pub sprite: Renderable, pub directional_animated: DirectionalAnimated, + pub entity_type: EntityType, } #[derive(Resource)] diff --git a/src/systems/movement.rs b/src/systems/movement.rs index 7ca5e6d..fc8cffd 100644 --- a/src/systems/movement.rs +++ b/src/systems/movement.rs @@ -1,21 +1,25 @@ -use crate::entity::graph::EdgePermissions; +use crate::entity::graph::{Edge, EdgePermissions, Graph}; use crate::error::{EntityError, GameError}; use crate::map::builder::Map; -use crate::systems::components::{DeltaTime, PlayerControlled, Position, Velocity}; +use crate::systems::components::{DeltaTime, EntityType, Position, Velocity}; use bevy_ecs::event::EventWriter; use bevy_ecs::system::{Query, Res}; -fn can_traverse(_player: &mut PlayerControlled, edge: crate::entity::graph::Edge) -> bool { - matches!(edge.permissions, EdgePermissions::All) +fn can_traverse(entity_type: EntityType, edge: Edge) -> bool { + match entity_type { + EntityType::Player => matches!(edge.permissions, EdgePermissions::All), + EntityType::Ghost => matches!(edge.permissions, EdgePermissions::All | EdgePermissions::GhostsOnly), + _ => matches!(edge.permissions, EdgePermissions::All), + } } pub fn movement_system( map: Res, delta_time: Res, - mut entities: Query<(&mut PlayerControlled, &mut Velocity, &mut Position)>, + mut entities: Query<(&mut Velocity, &mut Position, &EntityType)>, mut errors: EventWriter, ) { - for (mut player, mut velocity, mut position) in entities.iter_mut() { + for (mut velocity, mut position, entity_type) in entities.iter_mut() { let distance = velocity.speed * 60.0 * delta_time.0; // Decrement the remaining frames for the next direction @@ -32,7 +36,7 @@ pub fn movement_system( // We're not moving, but a buffered direction is available. if let Some((next_direction, _)) = velocity.next_direction { if let Some(edge) = map.graph.find_edge_in_direction(node_id, next_direction) { - if can_traverse(&mut player, edge) { + if can_traverse(*entity_type, edge) { // Start moving in that direction *position = Position::BetweenNodes { from: node_id, @@ -90,7 +94,7 @@ pub fn movement_system( // If we buffered a direction, try to find an edge in that direction if let Some((next_dir, _)) = velocity.next_direction { if let Some(edge) = map.graph.find_edge_in_direction(to, next_dir) { - if can_traverse(&mut player, edge) { + if can_traverse(*entity_type, edge) { *position = Position::BetweenNodes { from: to, to: edge.target, @@ -107,7 +111,7 @@ pub fn movement_system( // If we didn't move, try to continue in the current direction if !moved { if let Some(edge) = map.graph.find_edge_in_direction(to, velocity.direction) { - if can_traverse(&mut player, edge) { + if can_traverse(*entity_type, edge) { *position = Position::BetweenNodes { from: to, to: edge.target, diff --git a/src/systems/render.rs b/src/systems/render.rs index 5f959e4..27b9727 100644 --- a/src/systems/render.rs +++ b/src/systems/render.rs @@ -9,6 +9,8 @@ use sdl2::render::{Canvas, Texture}; use sdl2::video::Window; /// Updates the directional animated texture of an entity. +/// +/// This runs before the render system so it can update the sprite based on the current direction of travel, as well as whether the entity is moving. pub fn directional_render_system( dt: Res, mut renderables: Query<(&Velocity, &mut DirectionalAnimated, &mut Renderable, &Position)>, @@ -34,7 +36,10 @@ pub fn directional_render_system( } } +/// A non-send resource for the map texture. This just wraps the texture with a type so it can be differentiated when exposed as a resource. pub struct MapTextureResource(pub Texture<'static>); + +/// A non-send resource for the backbuffer texture. This just wraps the texture with a type so it can be differentiated when exposed as a resource. pub struct BackbufferResource(pub Texture<'static>); pub fn render_system( @@ -43,7 +48,7 @@ pub fn render_system( mut backbuffer: NonSendMut, mut atlas: NonSendMut, map: Res, - mut renderables: Query<(Entity, &mut Renderable, &Position)>, + renderables: Query<(Entity, &mut Renderable, &Position)>, mut errors: EventWriter, ) { // Clear the main canvas first @@ -64,7 +69,11 @@ pub fn render_system( .map(|e| errors.write(TextureError::RenderFailed(e.to_string()).into())); // Render all entities to the backbuffer - for (_, mut renderable, position) in renderables.iter_mut() { + for (_, mut renderable, position) in renderables + // .iter_mut() + // .sort_by_key::<&mut Renderable, _, _>(|(renderable, renderable, renderable)| renderable.layer) + // .collect() + { let pos = position.get_pixel_pos(&map.graph); match pos { Ok(pos) => {