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/state.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/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) } } |
