diff options
Diffstat (limited to 'src/state.rs')
| -rw-r--r-- | src/state.rs | 246 |
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) } } |
