summaryrefslogtreecommitdiffstats
path: root/src/state.rs
diff options
context:
space:
mode:
authorRaymond Hogenson <rhogenson@posteo.net>2018-08-18 00:25:29 -0400
committerRaymond Hogenson <rhogenson@posteo.net>2018-08-18 00:25:29 -0400
commitdaa61a51eb97f868a56a52fc61b560832dde353b (patch)
tree4da42fd8b8265b7e639275e613d4c7f78bf980e9 /src/state.rs
downloadstallman-shooter-daa61a51eb97f868a56a52fc61b560832dde353b.tar.zst
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.
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)
+ }
+}