summaryrefslogtreecommitdiffstats
path: root/src/state.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/state.rs')
-rw-r--r--src/state.rs237
1 files changed, 237 insertions, 0 deletions
diff --git a/src/state.rs b/src/state.rs
new file mode 100644
index 0000000..74ac73b
--- /dev/null
+++ b/src/state.rs
@@ -0,0 +1,237 @@
+extern crate sdl2;
+extern crate std;
+extern crate rand;
+
+use super::player;
+use super::constants;
+
+pub struct EBullet {
+ x: i32,
+ y: i32,
+ radius: u32,
+ real_x: f64,
+ real_y: f64,
+ d_x: f64,
+ d_y: f64,
+}
+
+pub struct Enemy {
+ pub x: i32,
+ pub y: i32,
+ action_count: u64,
+ v_x: f64,
+ v_y: f64,
+ a_x: f64,
+ a_y: f64,
+ target_x: f64,
+ target_y: f64,
+ radius: u32,
+ pub health: i64,
+}
+
+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 }
+ }
+
+ 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;
+ }
+}
+
+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) }
+ }
+ pub fn act(&mut self) {
+ self.b.act()
+ }
+ pub fn delete(&mut self) {
+ self.b.x = -10;
+ }
+}
+
+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, dx, enemy.y, dy)
+}
+
+fn random_position() -> (f64, f64) {
+ (rand::random() * (constants::X_DIM - 200) as f64 + 100., rand::random() * 200)
+}
+
+impl Enemy {
+ pub fn new() -> Enemy {
+ Enemy { x: 200, y: 40, action_count: 1, v_x: 0., v_y: 0., a_x: 0., a_y: 0., radius: 30, health: STARTING_HEALTH, target_x: 200, target_y: 400 }
+ }
+ pub fn act(&mut self, count: u64) -> Vec<EBullet> {
+ let dx = self.target_x - self.x;
+ let dy = self.target_y - self.y;
+ /* Made it; pick a new destination */
+ if f64::sqrt(dx*dx + dy*dy) < 10 {
+ let (self.target_x, self.target_y) = random_position();
+ }
+ let vec_x = self.target_x - self.real_x;
+ let vec_y = self.target_y - self.real_y;
+ let len = f64::sqrt(vec_x*vec_x + vec_y*vec_y);
+ self.a_x = vec_x / len / 2.;
+ self.a_y = vec_y / len / 2.;
+
+ self.v_x += self.a_x;
+ self.x = (self.x as f64 + self.v_x).round() as i32;
+ self.v_y += self.a_y;
+ self.y = (self.y as f64 + self.v_y).round() as i32;
+ 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()
+ }
+ }
+ pub fn health(&self) -> i64 {
+ self.health
+ }
+}
+
+pub struct State {
+ pub player: player::Player,
+ pub enemies: Vec<Enemy>,
+ pub bullets: Vec<EBullet>,
+ 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() }
+ }
+}
+
+fn dist(x1: i32, y1: i32, x2: i32, y2: i32) -> f64 {
+ let xdist = x1 - x2;
+ let ydist = y1 - y2;
+ f64::sqrt((xdist*xdist + ydist*ydist) as f64)
+}
+
+pub trait Positioned {
+ fn x(&self) -> i32;
+ fn y(&self) -> i32;
+ fn radius(&self) -> u32;
+ fn contains(&self, x: i32, y: i32) -> bool {
+ let d = dist(self.x(), self.y(), x, y);
+ d <= self.radius() as f64
+ }
+ fn overlaps<T: Positioned>(&self, other: &T) -> bool {
+ let dist = dist(self.x(), self.y(), other.x(), other.y());
+ dist < (self.radius() + other.radius()) as f64
+ }
+ fn outside(&self) -> bool {
+ let x = self.x();
+ let y = self.y();
+ x < 0 || x as u32 > constants::X_DIM || y < 0 || y as u32 > constants::Y_DIM
+ }
+}
+
+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()
+ }
+ fn y(&self) -> i32 {
+ self.b.y()
+ }
+ fn radius(&self) -> u32 {
+ self.b.radius()
+ }
+}
+
+impl Positioned for Enemy {
+ fn x(&self) -> i32 {
+ self.x
+ }
+ fn y(&self) -> i32 {
+ self.y
+ }
+ fn radius(&self) -> u32 {
+ self.radius
+ }
+}
+
+pub trait Drawable : Positioned {
+ fn color(&self) -> sdl2::pixels::Color;
+ fn draw(&self, canvas: &mut sdl2::render::WindowCanvas) {
+ let x = self.x();
+ let y = self.y();
+ let r = self.radius();
+ let r = r as i32;
+ let x_min = x - r;
+ let x_max = x + r;
+ let y_min = y - r;
+ let y_max = y + r;
+ canvas.set_draw_color(self.color());
+ for x in x_min..x_max + 1 {
+ for y in y_min..y_max + 1 {
+ if self.contains(x, y) {
+ canvas.fill_rect(sdl2::rect::Rect::new(x, y, 1, 1)).unwrap();
+ }
+ }
+ }
+ }
+}
+
+impl Drawable for Enemy {
+ fn color(&self) -> sdl2::pixels::Color {
+ let red_scale = self.health as f64 / STARTING_HEALTH as f64 * 255.;
+ sdl2::pixels::Color::RGB(red_scale as u8, 255 - red_scale as u8, 0)
+ }
+}
+
+impl Drawable for EBullet {
+ fn color(&self) -> sdl2::pixels::Color {
+ sdl2::pixels::Color::RGB(0, 0, 255)
+ }
+}
+
+impl Drawable for PBullet {
+ fn color(&self) -> sdl2::pixels::Color {
+ sdl2::pixels::Color::RGB(230, 255, 230)
+ }
+}