summaryrefslogtreecommitdiffstats
path: root/src/state.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/state.rs')
-rw-r--r--src/state.rs246
1 files changed, 66 insertions, 180 deletions
diff --git a/src/state.rs b/src/state.rs
index 5f622b5..d80c550 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -5,167 +5,89 @@ extern crate rand;
use super::player;
use super::constants;
-pub struct EBullet {
- x: i32,
- y: i32,
- radius: u32,
+pub trait StraightBullet: Positioned + Drawable {
+ fn real_x(&self) -> f64;
+ fn real_y(&self) -> f64;
+ fn set_real_x(&mut self, real_x: f64);
+ fn set_real_y(&mut self, real_y: f64);
+ fn d_x(&self) -> f64;
+ fn d_y(&self) -> f64;
+}
+
+pub struct PBullet {
real_x: f64,
real_y: f64,
d_x: f64,
d_y: f64,
}
-pub struct Enemy {
- pub x: f64,
- pub y: f64,
- v_x: f64,
- v_y: f64,
- a_x: f64,
- a_y: f64,
- target_x: f64,
- target_y: f64,
- radius: u32,
- pub health: i64,
-}
-
-pub const STARTING_HEALTH: i64 = 100;
-
-impl EBullet {
- pub fn new(x: i32, d_x: f64, y: i32, d_y: f64) -> EBullet {
- EBullet { x: x, real_x: x as f64, y: y, real_y: y as f64, radius: 10, d_x: d_x, d_y: d_y }
+impl StraightBullet for PBullet {
+ fn real_x(&self) -> f64 {
+ self.real_x
}
-
- pub fn act(&mut self) {
- self.real_x += self.d_x;
- self.real_y += self.d_y;
- self.x = self.real_x.round() as i32;
- self.y = self.real_y.round() as i32;
+ fn real_y(&self) -> f64 {
+ self.real_y
}
-}
-
-pub struct PBullet {
- b: EBullet,
-}
-
-impl PBullet {
- pub fn new(x: i32, d_x: f64, y: i32, d_y: f64) -> PBullet {
- PBullet { b: EBullet::new(x, d_x, y, d_y) }
+ fn set_real_x(&mut self, real_x: f64) {
+ self.real_x = real_x;
}
- pub fn act(&mut self) {
- self.b.act()
+ fn set_real_y(&mut self, real_y: f64) {
+ self.real_y = real_y;
}
- pub fn delete(&mut self) {
- self.b.x = -10;
+ fn d_x(&self) -> f64 {
+ self.d_x
+ }
+ fn d_y(&self) -> f64 {
+ self.d_y
}
}
-fn random_bullet(enemy: &Enemy) -> EBullet {
- let multiplier = 2. + (STARTING_HEALTH as i64 - enemy.health) as f64 / STARTING_HEALTH as f64 * 2.;
- 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;
- EBullet::new(enemy.x.round() as i32, dx, enemy.y.round() as i32, dy)
-}
-
-fn random_position() -> (f64, f64) {
- (rand::random::<f64>() * (constants::X_DIM - 200) as f64 + 100., rand::random::<f64>() * 100.)
+pub trait Bullet: Positioned + Drawable {
+ fn act(&mut self);
+ fn delete(&mut self);
}
-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<T: StraightBullet> Bullet for T {
+ fn act(&mut self) {
+ let real_x = self.real_x();
+ let d_x = self.d_x();
+ self.set_real_x(real_x + d_x);
+ let real_y = self.real_y();
+ let d_y = self.d_y();
+ self.set_real_y(real_y + d_y);
}
-}
-
-impl Enemy {
- pub fn new() -> Enemy {
- let (x, y) = random_position();
- Enemy { x: 200., y: 40., v_x: 0., v_y: 0., a_x: 0., a_y: 0., radius: 30, health: STARTING_HEALTH, target_x: x, target_y: y }
+ fn delete(&mut self) {
+ self.set_real_x(-10.);
}
- pub fn act(&mut self, count: u64) -> Vec<EBullet> {
- 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 >= 80 {
- num_bullets = 4;
- } else if self.health >= 50 {
- num_bullets = 5;
- } else if self.health >= 30 {
- num_bullets = 6;
- } else if self.health >= 20 {
- 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()
- }
+impl PBullet {
+ pub fn new(x: i32, d_x: f64, y: i32, d_y: f64) -> PBullet {
+ PBullet { real_x: x as f64, real_y: y as f64, d_x: d_x, d_y: d_y }
}
- pub fn health(&self) -> i64 {
- self.health
+ pub fn damage() -> f64 {
+ 0.01
}
}
-pub struct State {
+pub trait Enemy<T>: Drawable {
+ fn new() -> Self;
+ fn act(&mut self, count: u64) -> Vec<T>;
+ fn health(&self) -> f64;
+ fn set_health(&mut self, health: f64);
+}
+
+pub struct State<T, U> {
pub player: player::Player,
- pub enemies: Vec<Enemy>,
- pub bullets: Vec<EBullet>,
+ pub enemies: Vec<T>,
+ pub bullets: Vec<U>,
pub player_bullets: Vec<PBullet>,
pub count: u64,
}
-impl State {
- pub fn new() -> State {
- State { player: player::Player::new(), enemies: Vec::new(), bullets: Vec::new(), count: 0, player_bullets: Vec::new() }
+impl<T: Enemy<U>, U> State<T, U> {
+ pub fn new() -> State<T, U> {
+ State { player: player::Player::new(), enemies: vec![T::new()], bullets: Vec::new(), count: 0, player_bullets: Vec::new() }
}
}
@@ -178,17 +100,17 @@ fn dist(x1: i32, y1: i32, x2: i32, y2: i32) -> f64 {
pub trait Positioned {
fn x(&self) -> i32;
fn y(&self) -> i32;
- fn radius(&self) -> u32;
+ fn radius() -> u32;
fn contains(&self, x: i32, y: i32) -> bool {
let d = dist(self.x(), self.y(), x, y);
- d <= self.radius() as f64
+ d <= Self::radius() as f64
}
fn overlaps<T: Positioned>(&self, other: &T) -> bool {
let sx = self.x();
let ox = other.x();
let sy = self.y();
let oy = other.y();
- let threshold = self.radius() + other.radius();
+ let threshold = Self::radius() + T::radius();
if (sx - ox).abs() as u32 >= threshold || (sy - oy).abs() as u32 >= threshold {
return false;
}
@@ -202,68 +124,32 @@ pub trait Positioned {
}
}
-impl Positioned for EBullet {
- fn x(&self) -> i32 {
- self.x
- }
- fn y(&self) -> i32 {
- self.y
- }
- fn radius(&self) -> u32 {
- self.radius
- }
-}
-
impl Positioned for PBullet {
fn x(&self) -> i32 {
- self.b.x()
+ self.real_x.round() as i32
}
fn y(&self) -> i32 {
- self.b.y()
+ self.real_y.round() as i32
}
- fn radius(&self) -> u32 {
- self.b.radius()
- }
-}
-
-impl Positioned for Enemy {
- fn x(&self) -> i32 {
- self.x.round() as i32
- }
- fn y(&self) -> i32 {
- self.y.round() as i32
- }
- fn radius(&self) -> u32 {
- self.radius
+ fn radius() -> u32 {
+ 10
}
}
pub trait Drawable : Positioned {
- fn center(&self) -> (u32, u32);
+ fn center() -> (u32, u32);
fn draw(&self, canvas: &mut sdl2::render::WindowCanvas, texture: &sdl2::render::Texture) {
let tw = texture.query().width;
let th = texture.query().height;
- let (cx, cy) = self.center();
+ let (cx, cy) = Self::center();
let x0 = self.x() - cx as i32;
let y0 = self.y() - cy as i32;
canvas.copy(&texture, None, Some(sdl2::rect::Rect::new(x0, y0, tw, th))).unwrap();
}
}
-impl Drawable for Enemy {
- fn center(&self) -> (u32, u32) {
- (0, 0)
- }
-}
-
-impl Drawable for EBullet {
- fn center(&self) -> (u32, u32) {
- (20, 20)
- }
-}
-
impl Drawable for PBullet {
- fn center(&self) -> (u32, u32) {
+ fn center() -> (u32, u32) {
(16, 22)
}
}