mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-06 07:15:41 -06:00
feat: implement generic optimized collision system
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -571,6 +571,7 @@ version = "0.2.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bevy_ecs",
|
"bevy_ecs",
|
||||||
|
"bitflags 2.9.1",
|
||||||
"glam 0.30.5",
|
"glam 0.30.5",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ strum = "0.27.2"
|
|||||||
strum_macros = "0.27.2"
|
strum_macros = "0.27.2"
|
||||||
phf = { version = "0.11", features = ["macros"] }
|
phf = { version = "0.11", features = ["macros"] }
|
||||||
bevy_ecs = "0.16.1"
|
bevy_ecs = "0.16.1"
|
||||||
|
bitflags = "2.9.1"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
use bevy_ecs::event::Event;
|
use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
use crate::systems::input::GameCommand;
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum GameCommand {
|
||||||
|
Exit,
|
||||||
|
MovePlayer(crate::entity::direction::Direction),
|
||||||
|
ToggleDebug,
|
||||||
|
MuteAudio,
|
||||||
|
ResetLevel,
|
||||||
|
TogglePause,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Event)]
|
#[derive(Event, Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum GameEvent {
|
pub enum GameEvent {
|
||||||
Command(GameCommand),
|
Command(GameCommand),
|
||||||
|
Collision(Entity, Entity),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<GameCommand> for GameEvent {
|
impl From<GameCommand> for GameEvent {
|
||||||
|
|||||||
@@ -7,28 +7,33 @@ use crate::entity::direction::Direction;
|
|||||||
use crate::error::{GameError, GameResult, TextureError};
|
use crate::error::{GameError, GameResult, TextureError};
|
||||||
use crate::events::GameEvent;
|
use crate::events::GameEvent;
|
||||||
use crate::map::builder::Map;
|
use crate::map::builder::Map;
|
||||||
use crate::systems::components::{
|
use crate::systems::blinking::Blinking;
|
||||||
DeltaTime, DirectionalAnimated, EntityType, GlobalState, PlayerBundle, PlayerControlled, Position, Renderable, Velocity,
|
use crate::systems::{
|
||||||
|
blinking::blinking_system,
|
||||||
|
collision::collision_system,
|
||||||
|
components::{
|
||||||
|
Collider, CollisionLayer, DeltaTime, DirectionalAnimated, EntityType, GlobalState, ItemBundle, ItemCollider,
|
||||||
|
PacmanCollider, PlayerBundle, PlayerControlled, Position, Renderable, Score, ScoreResource, Velocity,
|
||||||
|
},
|
||||||
|
control::player_system,
|
||||||
|
input::input_system,
|
||||||
|
movement::movement_system,
|
||||||
|
render::{directional_render_system, render_system, BackbufferResource, MapTextureResource},
|
||||||
};
|
};
|
||||||
use crate::systems::control::player_system;
|
|
||||||
use crate::systems::movement::movement_system;
|
|
||||||
use crate::systems::render::{directional_render_system, render_system, BackbufferResource, MapTextureResource};
|
|
||||||
use crate::texture::animated::AnimatedTexture;
|
use crate::texture::animated::AnimatedTexture;
|
||||||
use bevy_ecs::event::EventRegistry;
|
|
||||||
use bevy_ecs::observer::Trigger;
|
|
||||||
use bevy_ecs::schedule::IntoScheduleConfigs;
|
use bevy_ecs::schedule::IntoScheduleConfigs;
|
||||||
use bevy_ecs::system::ResMut;
|
use bevy_ecs::{event::EventRegistry, observer::Trigger, schedule::Schedule, system::ResMut, world::World};
|
||||||
use bevy_ecs::{schedule::Schedule, world::World};
|
|
||||||
use sdl2::image::LoadTexture;
|
use sdl2::image::LoadTexture;
|
||||||
use sdl2::render::{Canvas, ScaleMode, TextureCreator};
|
use sdl2::render::{Canvas, ScaleMode, TextureCreator};
|
||||||
use sdl2::video::{Window, WindowContext};
|
use sdl2::video::{Window, WindowContext};
|
||||||
use sdl2::EventPump;
|
use sdl2::EventPump;
|
||||||
|
|
||||||
use crate::asset::{get_asset_bytes, Asset};
|
|
||||||
use crate::map::render::MapRenderer;
|
|
||||||
use crate::systems::input::{input_system, Bindings, GameCommand};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
asset::{get_asset_bytes, Asset},
|
||||||
constants,
|
constants,
|
||||||
|
events::GameCommand,
|
||||||
|
map::render::MapRenderer,
|
||||||
|
systems::input::Bindings,
|
||||||
texture::sprite::{AtlasMapper, SpriteAtlas},
|
texture::sprite::{AtlasMapper, SpriteAtlas},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -138,12 +143,18 @@ impl Game {
|
|||||||
sprite: SpriteAtlas::get_tile(&atlas, "pacman/full.png")
|
sprite: SpriteAtlas::get_tile(&atlas, "pacman/full.png")
|
||||||
.ok_or_else(|| GameError::Texture(TextureError::AtlasTileNotFound("pacman/full.png".to_string())))?,
|
.ok_or_else(|| GameError::Texture(TextureError::AtlasTileNotFound("pacman/full.png".to_string())))?,
|
||||||
layer: 0,
|
layer: 0,
|
||||||
|
visible: true,
|
||||||
},
|
},
|
||||||
directional_animated: DirectionalAnimated {
|
directional_animated: DirectionalAnimated {
|
||||||
textures,
|
textures,
|
||||||
stopped_textures,
|
stopped_textures,
|
||||||
},
|
},
|
||||||
entity_type: EntityType::Player,
|
entity_type: EntityType::Player,
|
||||||
|
collider: Collider {
|
||||||
|
size: constants::CELL_SIZE as f32 * 1.25,
|
||||||
|
layer: CollisionLayer::PACMAN,
|
||||||
|
},
|
||||||
|
pacman_collider: PacmanCollider,
|
||||||
};
|
};
|
||||||
|
|
||||||
world.insert_non_send_resource(atlas);
|
world.insert_non_send_resource(atlas);
|
||||||
@@ -154,23 +165,29 @@ impl Game {
|
|||||||
|
|
||||||
world.insert_resource(map);
|
world.insert_resource(map);
|
||||||
world.insert_resource(GlobalState { exit: false });
|
world.insert_resource(GlobalState { exit: false });
|
||||||
|
world.insert_resource(ScoreResource(0));
|
||||||
world.insert_resource(Bindings::default());
|
world.insert_resource(Bindings::default());
|
||||||
world.insert_resource(DeltaTime(0f32));
|
world.insert_resource(DeltaTime(0f32));
|
||||||
|
|
||||||
world.add_observer(|event: Trigger<GameEvent>, mut state: ResMut<GlobalState>| match *event {
|
world.add_observer(
|
||||||
|
|event: Trigger<GameEvent>, mut state: ResMut<GlobalState>, mut score: ResMut<ScoreResource>| match *event {
|
||||||
GameEvent::Command(command) => match command {
|
GameEvent::Command(command) => match command {
|
||||||
GameCommand::Exit => {
|
GameCommand::Exit => {
|
||||||
state.exit = true;
|
state.exit = true;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
});
|
GameEvent::Collision(a, b) => {}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
schedule.add_systems(
|
schedule.add_systems(
|
||||||
(
|
(
|
||||||
input_system,
|
input_system,
|
||||||
player_system,
|
player_system,
|
||||||
movement_system,
|
movement_system,
|
||||||
|
collision_system,
|
||||||
|
blinking_system,
|
||||||
directional_render_system,
|
directional_render_system,
|
||||||
render_system,
|
render_system,
|
||||||
)
|
)
|
||||||
@@ -180,6 +197,50 @@ impl Game {
|
|||||||
// Spawn player
|
// Spawn player
|
||||||
world.spawn(player);
|
world.spawn(player);
|
||||||
|
|
||||||
|
// Spawn items
|
||||||
|
let pellet_sprite = SpriteAtlas::get_tile(world.non_send_resource::<SpriteAtlas>(), "maze/pellet.png")
|
||||||
|
.ok_or_else(|| GameError::Texture(TextureError::AtlasTileNotFound("maze/pellet.png".to_string())))?;
|
||||||
|
let energizer_sprite = SpriteAtlas::get_tile(world.non_send_resource::<SpriteAtlas>(), "maze/energizer.png")
|
||||||
|
.ok_or_else(|| GameError::Texture(TextureError::AtlasTileNotFound("maze/energizer.png".to_string())))?;
|
||||||
|
|
||||||
|
let nodes: Vec<_> = world.resource::<Map>().iter_nodes().map(|(id, tile)| (*id, *tile)).collect();
|
||||||
|
|
||||||
|
for (node_id, tile) in nodes {
|
||||||
|
let (item_type, score, sprite, size) = match tile {
|
||||||
|
crate::constants::MapTile::Pellet => (EntityType::Pellet, 10, pellet_sprite, constants::CELL_SIZE as f32 * 0.2),
|
||||||
|
crate::constants::MapTile::PowerPellet => (
|
||||||
|
EntityType::PowerPellet,
|
||||||
|
50,
|
||||||
|
energizer_sprite,
|
||||||
|
constants::CELL_SIZE as f32 * 0.9,
|
||||||
|
),
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut item = world.spawn(ItemBundle {
|
||||||
|
position: Position::AtNode(node_id),
|
||||||
|
sprite: Renderable {
|
||||||
|
sprite,
|
||||||
|
layer: 1,
|
||||||
|
visible: true,
|
||||||
|
},
|
||||||
|
entity_type: item_type,
|
||||||
|
score: Score(score),
|
||||||
|
collider: Collider {
|
||||||
|
size,
|
||||||
|
layer: CollisionLayer::ITEM,
|
||||||
|
},
|
||||||
|
item_collider: ItemCollider,
|
||||||
|
});
|
||||||
|
|
||||||
|
if item_type == EntityType::PowerPellet {
|
||||||
|
item.insert(Blinking {
|
||||||
|
timer: 0.0,
|
||||||
|
interval: 0.2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Game { world, schedule })
|
Ok(Game { world, schedule })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +275,6 @@ impl Game {
|
|||||||
// GameEvent::Command(command) => self.handle_command(command),
|
// GameEvent::Command(command) => self.handle_command(command),
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Resets the game state, randomizing ghost positions and resetting Pac-Man
|
// /// Resets the game state, randomizing ghost positions and resetting Pac-Man
|
||||||
// fn reset_game_state(&mut self) -> GameResult<()> {
|
// fn reset_game_state(&mut self) -> GameResult<()> {
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ pub struct Map {
|
|||||||
pub grid_to_node: HashMap<IVec2, NodeId>,
|
pub grid_to_node: HashMap<IVec2, NodeId>,
|
||||||
/// A mapping of the starting positions of the entities.
|
/// A mapping of the starting positions of the entities.
|
||||||
pub start_positions: NodePositions,
|
pub start_positions: NodePositions,
|
||||||
|
/// The raw tile data for the map.
|
||||||
|
tiles: [[MapTile; BOARD_CELL_SIZE.y as usize]; BOARD_CELL_SIZE.x as usize],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl Map {
|
||||||
@@ -153,6 +155,14 @@ impl Map {
|
|||||||
graph,
|
graph,
|
||||||
grid_to_node,
|
grid_to_node,
|
||||||
start_positions,
|
start_positions,
|
||||||
|
tiles: map,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_nodes(&self) -> impl Iterator<Item = (&NodeId, &MapTile)> {
|
||||||
|
self.grid_to_node.iter().map(move |(pos, node_id)| {
|
||||||
|
let tile = &self.tiles[pos.x as usize][pos.y as usize];
|
||||||
|
(node_id, tile)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
27
src/systems/blinking.rs
Normal file
27
src/systems/blinking.rs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
use bevy_ecs::{
|
||||||
|
component::Component,
|
||||||
|
system::{Query, Res},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::systems::components::{DeltaTime, Renderable};
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct Blinking {
|
||||||
|
pub timer: f32,
|
||||||
|
pub interval: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates blinking entities by toggling their visibility at regular intervals.
|
||||||
|
///
|
||||||
|
/// This system manages entities that have both `Blinking` and `Renderable` components,
|
||||||
|
/// accumulating time and toggling visibility when the specified interval is reached.
|
||||||
|
pub fn blinking_system(time: Res<DeltaTime>, mut query: Query<(&mut Blinking, &mut Renderable)>) {
|
||||||
|
for (mut blinking, mut renderable) in query.iter_mut() {
|
||||||
|
blinking.timer += time.0;
|
||||||
|
|
||||||
|
if blinking.timer >= blinking.interval {
|
||||||
|
blinking.timer = 0.0;
|
||||||
|
renderable.visible = !renderable.visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/systems/collision.rs
Normal file
47
src/systems/collision.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
use bevy_ecs::entity::Entity;
|
||||||
|
use bevy_ecs::event::EventWriter;
|
||||||
|
use bevy_ecs::query::With;
|
||||||
|
use bevy_ecs::system::{Query, Res};
|
||||||
|
|
||||||
|
use crate::error::GameError;
|
||||||
|
use crate::events::GameEvent;
|
||||||
|
use crate::map::builder::Map;
|
||||||
|
use crate::systems::components::{Collider, ItemCollider, PacmanCollider, Position};
|
||||||
|
|
||||||
|
pub fn collision_system(
|
||||||
|
map: Res<Map>,
|
||||||
|
pacman_query: Query<(Entity, &Position, &Collider), With<PacmanCollider>>,
|
||||||
|
item_query: Query<(Entity, &Position, &Collider), With<ItemCollider>>,
|
||||||
|
mut events: EventWriter<GameEvent>,
|
||||||
|
mut errors: EventWriter<GameError>,
|
||||||
|
) {
|
||||||
|
// Check PACMAN × ITEM collisions
|
||||||
|
for (pacman_entity, pacman_pos, pacman_collider) in pacman_query.iter() {
|
||||||
|
for (item_entity, item_pos, item_collider) in item_query.iter() {
|
||||||
|
match (pacman_pos.get_pixel_pos(&map.graph), item_pos.get_pixel_pos(&map.graph)) {
|
||||||
|
(Ok(pacman_pixel), Ok(item_pixel)) => {
|
||||||
|
// Calculate the distance between the two entities's precise pixel positions
|
||||||
|
let distance = pacman_pixel.distance(item_pixel);
|
||||||
|
// Calculate the distance at which the two entities will collide
|
||||||
|
let collision_distance = (pacman_collider.size + item_collider.size) / 2.0;
|
||||||
|
|
||||||
|
// If the distance between the two entities is less than the collision distance, then the two entities are colliding
|
||||||
|
if distance < collision_distance {
|
||||||
|
events.write(GameEvent::Collision(pacman_entity, item_entity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Either or both of the pixel positions failed to get, so we need to report the error
|
||||||
|
(result_a, result_b) => {
|
||||||
|
for result in [result_a, result_b] {
|
||||||
|
if let Err(e) = result {
|
||||||
|
errors.write(GameError::InvalidState(format!(
|
||||||
|
"Collision system failed to get pixel positions for entities {:?} and {:?}: {}",
|
||||||
|
pacman_entity, item_entity, e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use bevy_ecs::{bundle::Bundle, component::Component, resource::Resource};
|
use bevy_ecs::{bundle::Bundle, component::Component, resource::Resource};
|
||||||
|
use bitflags::bitflags;
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -28,6 +29,7 @@ pub enum EntityType {
|
|||||||
pub struct Renderable {
|
pub struct Renderable {
|
||||||
pub sprite: AtlasTile,
|
pub sprite: AtlasTile,
|
||||||
pub layer: u8,
|
pub layer: u8,
|
||||||
|
pub visible: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A component for entities that have a directional animated texture.
|
/// A component for entities that have a directional animated texture.
|
||||||
@@ -62,6 +64,10 @@ impl Position {
|
|||||||
///
|
///
|
||||||
/// Converts the graph position to screen coordinates, accounting for
|
/// Converts the graph position to screen coordinates, accounting for
|
||||||
/// the board offset and centering the sprite.
|
/// the board offset and centering the sprite.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an `EntityError` if the node or edge is not found.
|
||||||
pub fn get_pixel_pos(&self, graph: &Graph) -> GameResult<Vec2> {
|
pub fn get_pixel_pos(&self, graph: &Graph) -> GameResult<Vec2> {
|
||||||
let pos = match self {
|
let pos = match self {
|
||||||
Position::AtNode(node_id) => {
|
Position::AtNode(node_id) => {
|
||||||
@@ -130,6 +136,34 @@ pub struct Velocity {
|
|||||||
pub speed: f32,
|
pub speed: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
#[derive(Component, Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct CollisionLayer: u8 {
|
||||||
|
const PACMAN = 1 << 0;
|
||||||
|
const GHOST = 1 << 1;
|
||||||
|
const ITEM = 1 << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct Collider {
|
||||||
|
pub size: f32,
|
||||||
|
pub layer: CollisionLayer,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marker components for collision filtering optimization
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct PacmanCollider;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct GhostCollider;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct ItemCollider;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct Score(pub u32);
|
||||||
|
|
||||||
#[derive(Bundle)]
|
#[derive(Bundle)]
|
||||||
pub struct PlayerBundle {
|
pub struct PlayerBundle {
|
||||||
pub player: PlayerControlled,
|
pub player: PlayerControlled,
|
||||||
@@ -138,6 +172,18 @@ pub struct PlayerBundle {
|
|||||||
pub sprite: Renderable,
|
pub sprite: Renderable,
|
||||||
pub directional_animated: DirectionalAnimated,
|
pub directional_animated: DirectionalAnimated,
|
||||||
pub entity_type: EntityType,
|
pub entity_type: EntityType,
|
||||||
|
pub collider: Collider,
|
||||||
|
pub pacman_collider: PacmanCollider,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Bundle)]
|
||||||
|
pub struct ItemBundle {
|
||||||
|
pub position: Position,
|
||||||
|
pub sprite: Renderable,
|
||||||
|
pub entity_type: EntityType,
|
||||||
|
pub score: Score,
|
||||||
|
pub collider: Collider,
|
||||||
|
pub item_collider: ItemCollider,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
@@ -145,5 +191,8 @@ pub struct GlobalState {
|
|||||||
pub exit: bool,
|
pub exit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct ScoreResource(pub u32);
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct DeltaTime(pub f32);
|
pub struct DeltaTime(pub f32);
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
event::{EventReader, EventWriter},
|
event::{EventReader, EventWriter},
|
||||||
|
prelude::ResMut,
|
||||||
query::With,
|
query::With,
|
||||||
system::{Query, ResMut},
|
system::Query,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::GameError,
|
error::GameError,
|
||||||
events::GameEvent,
|
events::{GameCommand, GameEvent},
|
||||||
systems::{
|
systems::components::{GlobalState, PlayerControlled, Velocity},
|
||||||
components::{GlobalState, PlayerControlled, Velocity},
|
|
||||||
input::GameCommand,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handles
|
// Handles
|
||||||
@@ -41,6 +39,9 @@ pub fn player_system(
|
|||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
|
GameEvent::Collision(a, b) => {
|
||||||
|
tracing::info!("Collision between {:?} and {:?}", a, b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,12 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{event::EventWriter, prelude::Res, resource::Resource, system::NonSendMut};
|
||||||
event::EventWriter,
|
|
||||||
resource::Resource,
|
|
||||||
system::{NonSendMut, Res},
|
|
||||||
};
|
|
||||||
use sdl2::{event::Event, keyboard::Keycode, EventPump};
|
use sdl2::{event::Event, keyboard::Keycode, EventPump};
|
||||||
|
|
||||||
use crate::{entity::direction::Direction, events::GameEvent};
|
use crate::{
|
||||||
|
entity::direction::Direction,
|
||||||
#[derive(Debug, Clone, Copy)]
|
events::{GameCommand, GameEvent},
|
||||||
pub enum GameCommand {
|
};
|
||||||
MovePlayer(Direction),
|
|
||||||
Exit,
|
|
||||||
TogglePause,
|
|
||||||
ToggleDebug,
|
|
||||||
MuteAudio,
|
|
||||||
ResetLevel,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Resource)]
|
#[derive(Debug, Clone, Resource)]
|
||||||
pub struct Bindings {
|
pub struct Bindings {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
//! This module contains all the ECS-related logic, including components, systems,
|
//! This module contains all the ECS-related logic, including components, systems,
|
||||||
//! and resources.
|
//! and resources.
|
||||||
|
|
||||||
|
pub mod blinking;
|
||||||
|
pub mod collision;
|
||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod control;
|
pub mod control;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::entity::graph::{Edge, EdgePermissions, Graph};
|
use crate::entity::graph::{Edge, EdgePermissions};
|
||||||
use crate::error::{EntityError, GameError};
|
use crate::error::{EntityError, GameError};
|
||||||
use crate::map::builder::Map;
|
use crate::map::builder::Map;
|
||||||
use crate::systems::components::{DeltaTime, EntityType, Position, Velocity};
|
use crate::systems::components::{DeltaTime, EntityType, Position, Velocity};
|
||||||
|
|||||||
Reference in New Issue
Block a user