From daa61a51eb97f868a56a52fc61b560832dde353b Mon Sep 17 00:00:00 2001 From: Raymond Hogenson Date: Sat, 18 Aug 2018 00:25:29 -0400 Subject: Write a working bullet hell I just fucked up the enemy movement, but hopefully I won't ever need that old code. The new one is going to look really cool and sweet. Anything with just modifying acceleration must look very cool and smooth. --- src/state.rs | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 src/state.rs (limited to 'src/state.rs') 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::()*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) + } +} -- cgit v1.3.1