mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-15 04:12:34 -06:00
142 lines
3.9 KiB
Rust
142 lines
3.9 KiB
Rust
use bevy_ecs::{
|
|
event::Event,
|
|
observer::Trigger,
|
|
system::{Commands, NonSendMut, Res},
|
|
};
|
|
use rand::Rng;
|
|
use strum_macros::IntoStaticStr;
|
|
use tracing::debug;
|
|
|
|
use crate::{
|
|
constants,
|
|
map::builder::Map,
|
|
platform::rng,
|
|
systems::{common::bundles::ItemBundle, Collider, Position, Renderable, TimeToLive},
|
|
texture::{
|
|
sprite::SpriteAtlas,
|
|
sprites::{EffectSprite, GameSprite},
|
|
},
|
|
};
|
|
|
|
use crate::{systems::common::components::EntityType, systems::ItemCollider};
|
|
|
|
use std::cmp::Ordering;
|
|
|
|
/// Tracks the number of pellets consumed by the player for fruit spawning mechanics.
|
|
#[derive(bevy_ecs::resource::Resource, Debug, Default)]
|
|
pub struct PelletCount(pub u32);
|
|
|
|
/// Represents the different fruit sprites that can appear as bonus items.
|
|
#[derive(IntoStaticStr, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
#[strum(serialize_all = "snake_case")]
|
|
pub enum FruitType {
|
|
Cherry,
|
|
Strawberry,
|
|
Orange,
|
|
Apple,
|
|
Melon,
|
|
Galaxian,
|
|
Bell,
|
|
Key,
|
|
}
|
|
|
|
impl PartialOrd for FruitType {
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl Ord for FruitType {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
(self.score_value()).cmp(&other.score_value())
|
|
}
|
|
}
|
|
|
|
impl FruitType {
|
|
/// Returns the score value for this fruit type.
|
|
pub fn score_value(self) -> u32 {
|
|
match self {
|
|
FruitType::Cherry => 100,
|
|
FruitType::Strawberry => 300,
|
|
FruitType::Orange => 500,
|
|
FruitType::Apple => 700,
|
|
FruitType::Melon => 1000,
|
|
FruitType::Galaxian => 2000,
|
|
FruitType::Bell => 3000,
|
|
FruitType::Key => 5000,
|
|
}
|
|
}
|
|
|
|
pub fn from_index(index: u8) -> Self {
|
|
match index {
|
|
0 => FruitType::Cherry,
|
|
1 => FruitType::Strawberry,
|
|
2 => FruitType::Orange,
|
|
3 => FruitType::Apple,
|
|
4 => FruitType::Melon,
|
|
5 => FruitType::Galaxian,
|
|
6 => FruitType::Bell,
|
|
7 => FruitType::Key,
|
|
_ => panic!("Invalid fruit index: {}", index),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Trigger to spawn a fruit
|
|
#[derive(Event, Clone, Copy, Debug)]
|
|
pub enum SpawnTrigger {
|
|
Fruit,
|
|
Bonus { position: Position, value: u32, ttl: u32 },
|
|
}
|
|
|
|
pub fn spawn_fruit_observer(
|
|
trigger: Trigger<SpawnTrigger>,
|
|
mut commands: Commands,
|
|
atlas: NonSendMut<SpriteAtlas>,
|
|
map: Res<Map>,
|
|
) {
|
|
let entity = match *trigger {
|
|
SpawnTrigger::Fruit => {
|
|
// Use cherry sprite as the default fruit (first fruit in original Pac-Man)
|
|
let sprite = &atlas
|
|
.get_tile(&GameSprite::Fruit(FruitType::from_index(0)).to_path())
|
|
.unwrap();
|
|
let bundle = ItemBundle {
|
|
position: map.start_positions.fruit_spawn,
|
|
sprite: Renderable {
|
|
sprite: *sprite,
|
|
layer: 1,
|
|
},
|
|
entity_type: EntityType::Fruit(FruitType::Cherry),
|
|
collider: Collider {
|
|
size: constants::collider::FRUIT_SIZE,
|
|
},
|
|
item_collider: ItemCollider,
|
|
};
|
|
|
|
let lifetime_ticks = (rng().random_range(9f32..10f32) * 60f32).round() as u32;
|
|
|
|
commands.spawn((bundle, TimeToLive::new(lifetime_ticks)))
|
|
}
|
|
SpawnTrigger::Bonus { position, value, ttl } => {
|
|
let sprite = &atlas
|
|
.get_tile(&GameSprite::Effect(EffectSprite::Bonus(value)).to_path())
|
|
.unwrap();
|
|
|
|
let bundle = (
|
|
position,
|
|
TimeToLive::new(ttl),
|
|
Renderable {
|
|
sprite: *sprite,
|
|
layer: 1,
|
|
},
|
|
EntityType::Effect,
|
|
);
|
|
|
|
commands.spawn(bundle)
|
|
}
|
|
};
|
|
|
|
debug!(entity = ?entity.id(), "Entity spawned via trigger");
|
|
}
|