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::()*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 { 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, pub bullets: Vec, pub player_bullets: Vec, 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(&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) } }