use crate::{Direction, Entity, FPos, Pos}; pub const ZOMBIE_HEALTH: u32 = 50; #[derive(Clone, Debug, PartialEq)] pub enum EnemyMoveSpeed { Slow, Medium, Fast, } /// Every (value) seconds, an enemy with a (speed) can move one tile pub const SLOW_SPEED_SEC_PER_TILE: f32 = 1.; pub const MEDIUM_SPEED_SEC_PER_TILE: f32 = 0.5; pub const FAST_SPEED_SEC_PER_TILE: f32 = 0.25; #[derive(Clone, Debug, PartialEq)] pub enum EnemyAttackType { Melee, Ranged, } #[derive(Clone, Debug, PartialEq)] pub enum EnemyType { Zombie, } #[derive(Clone, Debug, PartialEq)] pub struct Enemy { pub entity: Entity, pub enemy_type: EnemyType, pub move_speed: EnemyMoveSpeed, pub attack_type: EnemyAttackType, time_acc: f32, } impl Enemy { pub fn new(enemy_type: EnemyType, pos: Pos) -> Self { match enemy_type { EnemyType::Zombie => Self::zombie(pos), } } fn _new( pos: Pos, health: u32, enemy_type: EnemyType, move_speed: EnemyMoveSpeed, attack_type: EnemyAttackType, ) -> Self { let entity = Entity::enemy(pos, health); Self { entity, enemy_type, move_speed, attack_type, time_acc: 0., } } fn zombie(pos: Pos) -> Self { Self::_new( pos, ZOMBIE_HEALTH, EnemyType::Zombie, EnemyMoveSpeed::Slow, EnemyAttackType::Melee, ) } fn is_there(&self) -> bool { self.time_acc >= match &self.move_speed { EnemyMoveSpeed::Slow => SLOW_SPEED_SEC_PER_TILE, EnemyMoveSpeed::Medium => MEDIUM_SPEED_SEC_PER_TILE, EnemyMoveSpeed::Fast => FAST_SPEED_SEC_PER_TILE, } } /// /// Rough concept for enemy "AI": /// /// State: Roam/Patrol /// Moves around in a small area (2x2, 3x3, 4x4) randomly choosing direction and how much to move. /// State: Attack /// Sees player in facing direction (only in box/rectangle in dir) /// (ex. facing north, if player is anywhere above monster and theres no walls in the way, attack) /// Do A* pathing to player until enemy dead or player dead or floor change /// /// Current implementation below is just a test /// pub fn update(&mut self, player_pos: Pos, time_since_last_frame: f32) { if self.entity.pos == player_pos { return; } self.time_acc += time_since_last_frame; if self.is_there() { let temp_pos = self.entity.pos.step(Direction::West).unwrap(); self.entity.pos = temp_pos; self.entity.fpos = FPos::from_pos(temp_pos); self.time_acc = 0.; } } }