Mercurial > touhou
comparison 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 |
comparison
equal
deleted
inserted
replaced
657:ff7b6355cdf1 | 658:3a9d82a02c88 |
---|---|
6 use crate::util::prng::Prng; | 6 use crate::util::prng::Prng; |
7 use std::cell::RefCell; | 7 use std::cell::RefCell; |
8 use std::collections::HashMap; | 8 use std::collections::HashMap; |
9 use std::rc::{Rc, Weak}; | 9 use std::rc::{Rc, Weak}; |
10 | 10 |
11 #[derive(Debug, Clone, Copy)] | 11 /// The 2D position of an object in the game. |
12 struct Position { | 12 #[derive(Debug, Clone, Copy, Default)] |
13 pub struct Position { | |
13 x: f32, | 14 x: f32, |
14 y: f32, | 15 y: f32, |
15 } | 16 } |
16 | 17 |
17 #[derive(Debug, Clone, Copy)] | 18 /// An offset which can be added to a Position. |
18 struct Offset { | 19 #[derive(Debug, Clone, Copy, Default)] |
20 pub struct Offset { | |
19 dx: f32, | 21 dx: f32, |
20 dy: f32, | 22 dy: f32, |
21 } | 23 } |
22 | 24 |
23 impl Position { | 25 impl Position { |
26 /// Create said position. | |
24 pub fn new(x: f32, y: f32) -> Position { | 27 pub fn new(x: f32, y: f32) -> Position { |
25 Position { x, y } | 28 Position { x, y } |
26 } | 29 } |
27 } | 30 } |
28 | 31 |
29 impl Offset { | 32 impl Offset { |
33 /// Create said offset. | |
30 pub fn new(dx: f32, dy: f32) -> Offset { | 34 pub fn new(dx: f32, dy: f32) -> Offset { |
31 Offset { dx, dy } | 35 Offset { dx, dy } |
32 } | 36 } |
33 } | 37 } |
34 | 38 |
46 struct Callback; | 50 struct Callback; |
47 | 51 |
48 #[derive(Debug, Clone)] | 52 #[derive(Debug, Clone)] |
49 struct Laser; | 53 struct Laser; |
50 | 54 |
51 #[derive(Debug, Clone)] | 55 #[derive(Debug, Clone, Default)] |
52 struct Process; | 56 struct Process; |
53 | 57 |
54 struct Game { | 58 /// God struct of our game. |
55 enemies: Vec<Enemy>, | 59 pub struct Game { |
60 enemies: Vec<Rc<RefCell<Enemy>>>, | |
61 anmrunners: Vec<Rc<RefCell<AnmRunner>>>, | |
56 prng: Rc<RefCell<Prng>>, | 62 prng: Rc<RefCell<Prng>>, |
63 } | |
64 | |
65 impl Game { | |
66 /// Create said god struct. | |
67 pub fn new(prng: Rc<RefCell<Prng>>) -> Game { | |
68 Game { | |
69 enemies: Vec::new(), | |
70 anmrunners: Vec::new(), | |
71 prng, | |
72 } | |
73 } | |
74 | |
75 /// Run the simulation for a single frame. | |
76 pub fn run_frame(&mut self) { | |
77 /* | |
78 for eclrunner in self.eclrunners { | |
79 eclrunner.run_frame(); | |
80 } | |
81 */ | |
82 | |
83 for anmrunner in self.anmrunners.iter() { | |
84 let mut anmrunner = anmrunner.borrow_mut(); | |
85 anmrunner.run_frame(); | |
86 } | |
87 } | |
88 | |
89 /// Returns a list of all sprites currently being displayed on screen. | |
90 pub fn get_sprites(&self) -> Vec<Rc<RefCell<Sprite>>> { | |
91 let mut sprites = vec![]; | |
92 for anmrunner in self.anmrunners.iter() { | |
93 let anmrunner = anmrunner.borrow(); | |
94 let sprite = anmrunner.get_sprite(); | |
95 sprites.push(sprite); | |
96 } | |
97 sprites | |
98 } | |
57 } | 99 } |
58 | 100 |
59 /// Common to all elements in game. | 101 /// Common to all elements in game. |
60 struct Element { | 102 struct Element { |
61 pos: Position, | 103 pos: Position, |
62 removed: bool, | 104 removed: bool, |
63 sprite: Weak<RefCell<Sprite>>, | |
64 anmrunner: AnmRunner, | 105 anmrunner: AnmRunner, |
65 } | 106 } |
66 | 107 |
67 /// The enemy struct, containing everything pertaining to an enemy. | 108 /// The enemy struct, containing everything pertaining to an enemy. |
109 #[derive(Default)] | |
68 pub struct Enemy { | 110 pub struct Enemy { |
69 // Common to all elements in game. | 111 // Common to all elements in game. |
70 pos: Position, | 112 pos: Position, |
71 removed: bool, | 113 removed: bool, |
72 sprite: Rc<RefCell<Sprite>>, | 114 anmrunner: Weak<RefCell<AnmRunner>>, |
73 anmrunner: Rc<RefCell<AnmRunner>>, | |
74 | 115 |
75 // Specific to enemy. | 116 // Specific to enemy. |
76 // Floats. | 117 // Floats. |
77 z: f32, | 118 z: f32, |
78 angle: f32, | 119 angle: f32, |
86 die_score: u32, | 127 die_score: u32, |
87 frame: u32, | 128 frame: u32, |
88 life: u32, | 129 life: u32, |
89 death_flags: u32, | 130 death_flags: u32, |
90 current_laser_id: u32, | 131 current_laser_id: u32, |
91 low_life_trigger: u32, | 132 low_life_trigger: Option<u32>, |
92 timeout: u32, | 133 timeout: Option<u32>, |
93 remaining_lives: u32, | 134 remaining_lives: u32, |
94 bullet_launch_interval: u32, | 135 bullet_launch_interval: u32, |
95 bullet_launch_timer: u32, | 136 bullet_launch_timer: u32, |
96 death_anim: u32, | 137 death_anim: u32, |
97 direction: u32, | 138 direction: u32, |
123 | 164 |
124 // Laser. | 165 // Laser. |
125 laser_by_id: HashMap<u32, Laser>, | 166 laser_by_id: HashMap<u32, Laser>, |
126 | 167 |
127 // Options. | 168 // Options. |
169 // TODO: actually a 8 element array. | |
128 options: Vec<Element>, | 170 options: Vec<Element>, |
129 | 171 |
130 // Interpolators. | 172 // Interpolators. |
131 interpolator: Option<Interpolator2<f32>>, | 173 interpolator: Option<Interpolator2<f32>>, |
132 speed_interpolator: Option<Interpolator1<f32>>, | 174 speed_interpolator: Option<Interpolator1<f32>>, |
134 // Misc stuff, do we need them? | 176 // Misc stuff, do we need them? |
135 anm0: Weak<RefCell<Anm0>>, | 177 anm0: Weak<RefCell<Anm0>>, |
136 process: Rc<RefCell<Process>>, | 178 process: Rc<RefCell<Process>>, |
137 game: Weak<RefCell<Game>>, | 179 game: Weak<RefCell<Game>>, |
138 prng: Weak<RefCell<Prng>>, | 180 prng: Weak<RefCell<Prng>>, |
139 hitbox_half_size: (f32, f32), | 181 hitbox_half_size: [f32; 2], |
140 } | 182 } |
141 | 183 |
142 impl Enemy { | 184 impl Enemy { |
185 /// Create a new enemy. | |
186 pub fn new(pos: Position, life: i32, bonus_dropped: u32, die_score: u32, anm0: Weak<RefCell<Anm0>>, game: Weak<RefCell<Game>>) -> Enemy { | |
187 Enemy { | |
188 pos, | |
189 anm0, | |
190 game, | |
191 visible: true, | |
192 bonus_dropped, | |
193 die_score, | |
194 life: if life < 0 { 1 } else { life as u32 }, | |
195 touchable: true, | |
196 collidable: true, | |
197 damageable: true, | |
198 difficulty_coeffs: (-0.5, 0.5, 0, 0, 0, 0), | |
199 ..Default::default() | |
200 } | |
201 } | |
202 | |
143 /// Sets the animation to the one indexed by index in the current anm0. | 203 /// Sets the animation to the one indexed by index in the current anm0. |
144 pub fn set_anim(&mut self, index: u8) { | 204 pub fn set_anim(&mut self, index: u8) { |
145 self.sprite = Rc::new(RefCell::new(Sprite::new())); | |
146 let anm0 = self.anm0.upgrade().unwrap(); | 205 let anm0 = self.anm0.upgrade().unwrap(); |
147 let anmrunner = AnmRunner::new(&*anm0.borrow(), index, self.sprite.clone(), self.prng.clone(), 0); | 206 let game = self.game.upgrade().unwrap(); |
148 self.anmrunner = Rc::new(RefCell::new(anmrunner)); | 207 let sprite = Rc::new(RefCell::new(Sprite::new())); |
149 } | 208 let anmrunner = AnmRunner::new(&*anm0.borrow(), index, sprite, self.prng.clone(), 0); |
150 } | 209 let anmrunner = Rc::new(RefCell::new(anmrunner)); |
210 self.anmrunner = Rc::downgrade(&anmrunner); | |
211 (*game.borrow_mut()).anmrunners.push(anmrunner); | |
212 } | |
213 | |
214 /// Sets the hitbox around the enemy. | |
215 pub fn set_hitbox(&mut self, width: f32, height: f32) { | |
216 self.hitbox_half_size = [width, height]; | |
217 } | |
218 } | |
219 | |
220 #[cfg(test)] | |
221 mod tests { | |
222 use super::*; | |
223 use std::io::{self, Read}; | |
224 use std::fs::File; | |
225 | |
226 #[test] | |
227 fn enemy() { | |
228 let file = File::open("EoSD/ST/stg1enm.anm").unwrap(); | |
229 let mut file = io::BufReader::new(file); | |
230 let mut buf = vec![]; | |
231 file.read_to_end(&mut buf).unwrap(); | |
232 let anm0 = Anm0::from_slice(&buf).unwrap(); | |
233 let anm0 = Rc::new(RefCell::new(anm0)); | |
234 let prng = Rc::new(RefCell::new(Prng::new(0))); | |
235 let game = Game::new(prng); | |
236 let game = Rc::new(RefCell::new(game)); | |
237 let mut enemy = Enemy::new(Position::new(0., 0.), 500, 0, 640, Rc::downgrade(&anm0), Rc::downgrade(&game)); | |
238 assert!(enemy.anmrunner.upgrade().is_none()); | |
239 enemy.set_anim(0); | |
240 assert!(enemy.anmrunner.upgrade().is_some()); | |
241 } | |
242 } |