diff src/th06/enemy.rs @ 658:3a9d82a02c88

Add a contructor for enemy, and a new example.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sat, 10 Aug 2019 12:48:01 +0200
parents ff7b6355cdf1
children 31fc0d881105
line wrap: on
line diff
--- a/src/th06/enemy.rs
+++ b/src/th06/enemy.rs
@@ -8,25 +8,29 @@ use std::cell::RefCell;
 use std::collections::HashMap;
 use std::rc::{Rc, Weak};
 
-#[derive(Debug, Clone, Copy)]
-struct Position {
+/// The 2D position of an object in the game.
+#[derive(Debug, Clone, Copy, Default)]
+pub struct Position {
     x: f32,
     y: f32,
 }
 
-#[derive(Debug, Clone, Copy)]
-struct Offset {
+/// An offset which can be added to a Position.
+#[derive(Debug, Clone, Copy, Default)]
+pub struct Offset {
     dx: f32,
     dy: f32,
 }
 
 impl Position {
+    /// Create said position.
     pub fn new(x: f32, y: f32) -> Position {
         Position { x, y }
     }
 }
 
 impl Offset {
+    /// Create said offset.
     pub fn new(dx: f32, dy: f32) -> Offset {
         Offset { dx, dy }
     }
@@ -48,29 +52,66 @@ struct Callback;
 #[derive(Debug, Clone)]
 struct Laser;
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Default)]
 struct Process;
 
-struct Game {
-    enemies: Vec<Enemy>,
+/// God struct of our game.
+pub struct Game {
+    enemies: Vec<Rc<RefCell<Enemy>>>,
+    anmrunners: Vec<Rc<RefCell<AnmRunner>>>,
     prng: Rc<RefCell<Prng>>,
 }
 
+impl Game {
+    /// Create said god struct.
+    pub fn new(prng: Rc<RefCell<Prng>>) -> Game {
+        Game {
+            enemies: Vec::new(),
+            anmrunners: Vec::new(),
+            prng,
+        }
+    }
+
+    /// Run the simulation for a single frame.
+    pub fn run_frame(&mut self) {
+        /*
+        for eclrunner in self.eclrunners {
+            eclrunner.run_frame();
+        }
+        */
+
+        for anmrunner in self.anmrunners.iter() {
+            let mut anmrunner = anmrunner.borrow_mut();
+            anmrunner.run_frame();
+        }
+    }
+
+    /// Returns a list of all sprites currently being displayed on screen.
+    pub fn get_sprites(&self) -> Vec<Rc<RefCell<Sprite>>> {
+        let mut sprites = vec![];
+        for anmrunner in self.anmrunners.iter() {
+            let anmrunner = anmrunner.borrow();
+            let sprite = anmrunner.get_sprite();
+            sprites.push(sprite);
+        }
+        sprites
+    }
+}
+
 /// Common to all elements in game.
 struct Element {
     pos: Position,
     removed: bool,
-    sprite: Weak<RefCell<Sprite>>,
     anmrunner: AnmRunner,
 }
 
 /// The enemy struct, containing everything pertaining to an enemy.
+#[derive(Default)]
 pub struct Enemy {
     // Common to all elements in game.
     pos: Position,
     removed: bool,
-    sprite: Rc<RefCell<Sprite>>,
-    anmrunner: Rc<RefCell<AnmRunner>>,
+    anmrunner: Weak<RefCell<AnmRunner>>,
 
     // Specific to enemy.
     // Floats.
@@ -88,8 +129,8 @@ pub struct Enemy {
     life: u32,
     death_flags: u32,
     current_laser_id: u32,
-    low_life_trigger: u32,
-    timeout: u32,
+    low_life_trigger: Option<u32>,
+    timeout: Option<u32>,
     remaining_lives: u32,
     bullet_launch_interval: u32,
     bullet_launch_timer: u32,
@@ -125,6 +166,7 @@ pub struct Enemy {
     laser_by_id: HashMap<u32, Laser>,
 
     // Options.
+    // TODO: actually a 8 element array.
     options: Vec<Element>,
 
     // Interpolators.
@@ -136,15 +178,65 @@ pub struct Enemy {
     process: Rc<RefCell<Process>>,
     game: Weak<RefCell<Game>>,
     prng: Weak<RefCell<Prng>>,
-    hitbox_half_size: (f32, f32),
+    hitbox_half_size: [f32; 2],
 }
 
 impl Enemy {
+    /// Create a new enemy.
+    pub fn new(pos: Position, life: i32, bonus_dropped: u32, die_score: u32, anm0: Weak<RefCell<Anm0>>, game: Weak<RefCell<Game>>) -> Enemy {
+        Enemy {
+            pos,
+            anm0,
+            game,
+            visible: true,
+            bonus_dropped,
+            die_score,
+            life: if life < 0 { 1 } else { life as u32 },
+            touchable: true,
+            collidable: true,
+            damageable: true,
+            difficulty_coeffs: (-0.5, 0.5, 0, 0, 0, 0),
+            ..Default::default()
+        }
+    }
+
     /// Sets the animation to the one indexed by index in the current anm0.
     pub fn set_anim(&mut self, index: u8) {
-        self.sprite = Rc::new(RefCell::new(Sprite::new()));
         let anm0 = self.anm0.upgrade().unwrap();
-        let anmrunner = AnmRunner::new(&*anm0.borrow(), index, self.sprite.clone(), self.prng.clone(), 0);
-        self.anmrunner = Rc::new(RefCell::new(anmrunner));
+        let game = self.game.upgrade().unwrap();
+        let sprite = Rc::new(RefCell::new(Sprite::new()));
+        let anmrunner = AnmRunner::new(&*anm0.borrow(), index, sprite, self.prng.clone(), 0);
+        let anmrunner = Rc::new(RefCell::new(anmrunner));
+        self.anmrunner = Rc::downgrade(&anmrunner);
+        (*game.borrow_mut()).anmrunners.push(anmrunner);
+    }
+
+    /// Sets the hitbox around the enemy.
+    pub fn set_hitbox(&mut self, width: f32, height: f32) {
+        self.hitbox_half_size = [width, height];
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::io::{self, Read};
+    use std::fs::File;
+
+    #[test]
+    fn enemy() {
+        let file = File::open("EoSD/ST/stg1enm.anm").unwrap();
+        let mut file = io::BufReader::new(file);
+        let mut buf = vec![];
+        file.read_to_end(&mut buf).unwrap();
+        let anm0 = Anm0::from_slice(&buf).unwrap();
+        let anm0 = Rc::new(RefCell::new(anm0));
+        let prng = Rc::new(RefCell::new(Prng::new(0)));
+        let game = Game::new(prng);
+        let game = Rc::new(RefCell::new(game));
+        let mut enemy = Enemy::new(Position::new(0., 0.), 500, 0, 640, Rc::downgrade(&anm0), Rc::downgrade(&game));
+        assert!(enemy.anmrunner.upgrade().is_none());
+        enemy.set_anim(0);
+        assert!(enemy.anmrunner.upgrade().is_some());
+    }
+}