summaryrefslogtreecommitdiffstats
path: root/src/gates.rs
diff options
context:
space:
mode:
authorRaymond Hogenson <rhogenson@posteo.net>2018-08-19 00:45:11 -0400
committerRaymond Hogenson <rhogenson@posteo.net>2018-08-19 00:45:11 -0400
commit5846773a84b629765b6a7236bb6363bc4e34ab94 (patch)
tree1d0df0ee8d99f91b78b4adca6086ee09255502d3 /src/gates.rs
parentRedo binary blob asset to have more actual binary (diff)
downloadstallman-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.rs185
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)
+ }
+}