diff options
| author | Raymond Hogenson <rhogenson@posteo.net> | 2018-08-19 00:45:11 -0400 |
|---|---|---|
| committer | Raymond Hogenson <rhogenson@posteo.net> | 2018-08-19 00:45:11 -0400 |
| commit | 5846773a84b629765b6a7236bb6363bc4e34ab94 (patch) | |
| tree | 1d0df0ee8d99f91b78b4adca6086ee09255502d3 /src/gates.rs | |
| parent | Redo binary blob asset to have more actual binary (diff) | |
| download | stallman-shooter-5846773a84b629765b6a7236bb6363bc4e34ab94.tar.zst | |
Move some code around and improve abstraction
This doesn't change the functionality of the game at all (ideally), but
makes it easier to refactor and to add new enemies and new stages, which
is really the end-goal of this whole thing.
Diffstat (limited to 'src/gates.rs')
| -rw-r--r-- | src/gates.rs | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/src/gates.rs b/src/gates.rs new file mode 100644 index 0000000..c79297a --- /dev/null +++ b/src/gates.rs @@ -0,0 +1,185 @@ +extern crate rand; +extern crate std; + +use super::state; +use super::constants; + +pub struct Gates { + x: f64, + y: f64, + v_x: f64, + v_y: f64, + a_x: f64, + a_y: f64, + target_x: f64, + target_y: f64, + health: f64, +} + +pub struct GatesBullet { + real_x: f64, + real_y: f64, + d_x: f64, + d_y: f64, +} + +impl GatesBullet { + pub fn new(x: i32, d_x: f64, y: i32, d_y: f64) -> GatesBullet { + GatesBullet { real_x: x as f64, real_y: y as f64, d_x: d_x, d_y: d_y } + } +} + +impl state::Positioned for GatesBullet { + fn x(&self) -> i32 { + self.real_x.round() as i32 + } + fn y(&self) -> i32 { + self.real_y.round() as i32 + } + fn radius() -> u32 { + 10 + } +} + +impl state::Positioned for Gates { + fn x(&self) -> i32 { + self.x.round() as i32 + } + fn y(&self) -> i32 { + self.y.round() as i32 + } + fn radius() -> u32 { + 15 + } +} + +fn random_position() -> (f64, f64) { + (rand::random::<f64>() * (constants::X_DIM - 200) as f64 + 100., rand::random::<f64>() * 100.) +} + +impl state::StraightBullet for GatesBullet { + fn real_x(&self) -> f64 { + self.real_x + } + fn real_y(&self) -> f64 { + self.real_y + } + fn set_real_x(&mut self, real_x: f64) { + self.real_x = real_x; + } + fn set_real_y(&mut self, real_y: f64) { + self.real_y = real_y; + } + fn d_x(&self) -> f64 { + self.d_x + } + fn d_y(&self) -> f64 { + self.d_y + } +} + +fn random_bullet<T: state::Enemy<GatesBullet>>(enemy: &T) -> GatesBullet { + let multiplier = 2. + 2.*(1. - enemy.health()); + let theta: f64 = rand::random::<f64>()*2.*std::f64::consts::PI/3. + std::f64::consts::PI/6.; + let dx = f64::cos(theta) * multiplier; + let dy = f64::sin(theta) * multiplier; + GatesBullet::new(enemy.x(), dx, enemy.y(), dy) +} + +fn shorten(x: f64, y: f64, maxlen: f64) -> (f64, f64) { + let len = f64::sqrt(x*x + y*y); + if len > maxlen { + (x / len / 2., y / len / 2.) + } else { + (x, y) + } +} + +impl state::Enemy<GatesBullet> for Gates { + fn new() -> Gates { + Gates { x: 200., y: 40., v_x: 0., v_y: 0., a_x: 0., a_y: 0., target_x: 200., target_y: 40., health: 1. } + } + fn act(&mut self, count: u64) -> Vec<GatesBullet> { + let max_accel = 0.25; + let max_velocity = 5.; + let dx = self.target_x - self.x; + let dy = self.target_y - self.y; + /* If we've arrived (close and stopped) */ + if (dx*dx + dy*dy).sqrt() < max_velocity / max_accel && (self.v_x*self.v_x + self.v_y*self.v_y).sqrt() < 0.01 { + /* Then pick a new target */ + let (x, y) = random_position(); + self.target_x = x; + self.target_y = y; + } + + let dx = self.target_x - self.x; + let dy = self.target_y - self.y; + /* If we're close */ + if (dx*dx + dy*dy).sqrt() < max_velocity / max_accel { + /* Then slow down */ + let (x, y) = shorten(-self.v_x, -self.v_y, max_accel); + self.a_x = x; + self.a_y = y; + } else { + /* Otherwise, speed up */ + let (x, y) = shorten(dx, dy, max_accel); + self.a_x = x; + self.a_y = y; + } + + /* If we're going too fast */ + if (self.v_x*self.v_x + self.v_y*self.v_y).sqrt() > max_velocity { + /* Then don't go faster */ + if self.v_x.signum() == self.a_x.signum() { + self.a_x = 0.; + } + if self.v_y.signum() == self.a_y.signum() { + self.a_y = 0.; + } + } + + self.v_x += self.a_x; + self.x += self.v_x; + self.v_y += self.a_y; + self.y += self.v_y; + if count % 20 == 0 { + let num_bullets; + if self.health >= 0.8 { + num_bullets = 4; + } else if self.health >= 0.5 { + num_bullets = 5; + } else if self.health >= 0.3 { + num_bullets = 6; + } else if self.health >= 0.2 { + num_bullets = 7; + } else { + num_bullets = 8; + } + let mut result = Vec::new(); + for _ in 0..num_bullets { + result.push(random_bullet(&*self)); + } + result + } else { + Vec::new() + } + } + fn health(&self) -> f64 { + self.health + } + fn set_health(&mut self, health: f64) { + self.health = health; + } +} + +impl state::Drawable for GatesBullet { + fn center() -> (u32, u32) { + (20, 20) + } +} + +impl state::Drawable for Gates { + fn center() -> (u32, u32) { + (16, 23) + } +} |
