From 8e3521fe56702f9bfb53e200f23d86d3e818481a Mon Sep 17 00:00:00 2001 From: Levi Pearson Date: Sat, 30 Jul 2016 15:02:27 -0600 Subject: [PATCH] Big bunch of development --- Cargo.lock | 2 +- Cargo.toml | 4 +- src/game.rs | 339 ------------------------------------------- src/game/bullet.rs | 33 +++++ src/game/camera.rs | 52 +++++++ src/game/controls.rs | 78 ++++++++++ src/game/map.rs | 61 ++++++++ src/game/mod.rs | 108 ++++++++++++++ src/game/ship.rs | 58 ++++++++ src/main.rs | 2 +- 10 files changed, 394 insertions(+), 343 deletions(-) delete mode 100644 src/game.rs create mode 100644 src/game/bullet.rs create mode 100644 src/game/camera.rs create mode 100644 src/game/controls.rs create mode 100644 src/game/map.rs create mode 100644 src/game/mod.rs create mode 100644 src/game/ship.rs diff --git a/Cargo.lock b/Cargo.lock index 886c1f7..f6fa376 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,5 @@ [root] -name = "getting-started-spinning-square" +name = "rust-pilot" version = "0.1.0" dependencies = [ "piston_window 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index b20a98c..449e284 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,13 @@ [package] -name = "getting-started-spinning-square" +name = "rust-pilot" version = "0.1.0" authors = [ "Levi Pearson " ] [[bin]] -name = "spinning-square" +name = "rust-pilot" [dependencies] piston_window = "0.40.0" diff --git a/src/game.rs b/src/game.rs deleted file mode 100644 index 1f86c95..0000000 --- a/src/game.rs +++ /dev/null @@ -1,339 +0,0 @@ -use piston_window::*; -use piston_window::math::*; -use piston_window::draw_state::Blend; -use std::f64::consts::*; - -static TURN_RATE: Scalar = 4.0; -static THRUST_RATE: Scalar = 4.0; - -struct Controls { - up_d: bool, - down_d: bool, - left_d: bool, - right_d: bool, - fire: bool -} - -impl Controls { - fn new() -> Self { - Controls { - up_d: false, down_d: false, left_d: false, right_d: false, - fire: false - } - } - - fn update(&mut self, inp: Input) { - match inp { - Input::Press(b) => { - match b { - Button::Keyboard(Key::Up) => { self.up_d = true; } - Button::Keyboard(Key::Down) => { self.down_d = true; } - Button::Keyboard(Key::Left) => { self.left_d = true; } - Button::Keyboard(Key::Right) => { self.right_d = true; } - _ => {} - } - } - Input::Release(b) => { - match b { - Button::Keyboard(Key::Up) => { self.up_d = false; } - Button::Keyboard(Key::Down) => { self.down_d = false; } - Button::Keyboard(Key::Left) => { self.left_d = false; } - Button::Keyboard(Key::Right) => { self.right_d = false; } - Button::Keyboard(Key::Space) => { self.fire = true; } - _ => {} - } - } - _ => {} - } - } - - fn velocity_change(&self, rot: Scalar, dt: Scalar) -> Vec2d { - let thrust = if self.up_d { - THRUST_RATE * dt - } else if self.down_d { - -THRUST_RATE * dt - } else { - 0.0 - }; - if thrust != 0.0 { - [rot.cos() * thrust, rot.sin() * thrust] - } else { - [0.0, 0.0] - } - } - - fn rotation_change(&self, dt: Scalar) -> Scalar { - if self.left_d { - -TURN_RATE * dt - } else if self.right_d { - TURN_RATE * dt - } else { - 0.0 - } - } - - fn fire_check(&self) -> bool { - self.fire - } -} - -const BULLET_POLY: &'static [[Scalar; 2]] = &[ - [-1.5, -1.5], - [-1.5, 1.5], - [1.5, 1.5], - [1.5, -1.5] -]; - -#[derive(Debug)] -pub struct Bullet { - position: Vec2d, - velocity: Vec2d, - ttl: Scalar, - geometry: &'static [[Scalar; 2]] -} - -const SHIP_POLY: &'static [[Scalar; 2]] = &[ - [-10.0, -8.0], - [10.0, 0.0], - [-10.0, 8.0] -]; - -impl Bullet { - pub fn new(loc: Vec2d, velocity: Vec2d, ttl: Scalar) -> Self { - Bullet { - position: loc, - velocity: velocity, - ttl: ttl, - geometry: BULLET_POLY - } - } - - pub fn update(&mut self, dt: Scalar) -> Scalar { - self.position = add(self.position, self.velocity); - self.ttl -= dt; - self.ttl - } -} - -pub struct Ship { - rotation: Scalar, - position: Vec2d, - velocity: Vec2d, - geometry: &'static [[Scalar; 2]] -} - -impl Ship { - pub fn new(loc: Vec2d) -> Self { - Ship { - rotation: -FRAC_PI_2, - position: loc, - velocity: [0.0, 0.0], - geometry: SHIP_POLY - } - } - - pub fn update(&mut self, dv: Vec2d, dr: Scalar, map: &Map) { - self.rotation += dr; - self.velocity = add(self.velocity, dv); - self.position = add(self.position, self.velocity); - if self.position[0] > map.width { - self.velocity[0] = 0.0; - self.position[0] = map.width; - } - if self.position[0] < 0.0 { - self.velocity[0] = 0.0; - self.position[0] = 0.0; - } - if self.position[1] > map.height { - self.velocity[1] = 0.0; - self.position[1] = map.height; - } - if self.position[1] < 0.0 { - self.velocity[1] = 0.0; - self.position[1] = 0.0; - } - } - - pub fn trajectory(&self) -> (Vec2d, Vec2d, Vec2d) { - let nose = self.geometry[1]; - let rot = rotate_radians(self.rotation); - let trans = translate(self.position); - let tmat = multiply(trans, rot); - (transform_pos(tmat, nose), transform_vec(rot, [1.0,0.0]), self.velocity) - } -} - -pub struct Camera { - position: Vec2d, - height: Scalar, - width: Scalar -} - -impl Camera { - pub fn new(pos: Vec2d, width: Scalar, height: Scalar) -> Self { - Camera { - position: pos, - width: width, - height: height - } - } - - pub fn follow(&mut self, pos: Vec2d, map: &Map) { - let dp = sub(pos, self.position); - let xmargin = self.width / 4.0; - let ymargin = self.height / 4.0; - - if dp[0] > xmargin { - self.position[0] += dp[0] - xmargin; - } - if dp[0] < -xmargin { - self.position[0] += dp[0] + xmargin; - } - if dp[1] > ymargin { - self.position[1] += dp[1] - ymargin; - } - if dp[1] < -ymargin { - self.position[1] += dp[1] + ymargin; - } - - if self.position[0] + self.width / 2.0 > map.width { - self.position[0] = map.width - self.width / 2.0; - } - if self.position[0] - self.width / 2.0 < 0.0 { - self.position[0] = 0.0 + self.width / 2.0; - } - if self.position[1] + self.height / 2.0 > map.height { - self.position[1] = map.height - self.height / 2.0; - } - if self.position[1] - self.height / 2.0 < 0.0 { - self.position[1] = 0.0 + self.height / 2.0; - } - - } -} - -pub struct Map { - width: Scalar, - height: Scalar -} - -impl Map { - pub fn new(width: Scalar, height: Scalar) -> Self { - Map { width: width, height: height } - } - pub fn center(&self) -> Vec2d { - [self.width / 2.0, self.height / 2.0] - } - pub fn draw_grid(&self, cpos: Vec2d, - cw: Scalar, ch: Scalar, - draw_state: &DrawState, - transform: Matrix2d, g: &mut G) - where G: Graphics { - - const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 0.05]; - - let minx = cpos[0] - cw / 2.0; - let miny = cpos[1] - ch / 2.0; - - let xcount = (cw / 100.0).ceil() as u32 + 2; - let ycount = (ch / 100.0).ceil() as u32 + 2; - - let firstx = (minx / 100.0).trunc() * 100.0; - let firsty = (miny / 100.0).trunc() * 100.0; - - for x in 0..xcount { - let sy = cpos[1] - ch; - let ey = cpos[1] + ch; - let lx = firstx + (100.0 * x as Scalar); - Line::new(GREEN, 1.0) - .draw([lx-cpos[0], sy-cpos[1], lx-cpos[0], ey-cpos[1]], - draw_state, transform, g); - } - for y in 0..ycount { - let sx = cpos[0] - cw; - let ex = cpos[0] + cw; - let ly = firsty + (100.0 * y as Scalar); - Line::new(GREEN, 1.0) - .draw([sx-cpos[0], ly-cpos[1], ex-cpos[0], ly-cpos[1]], - draw_state, transform, g); - } - } -} - -pub struct Game { - player: Ship, - bullets: Vec, - map: Map, - camera: Camera, - controls: Controls -} - -impl Game { - pub fn new(width: Scalar, height: Scalar) -> Self { - let new_map = Map::new(10000.0, 10000.0); - let center = new_map.center(); - Game { - player: Ship::new(center), - bullets: Vec::new(), - map: new_map, - camera: Camera::new(center, width, height), - controls: Controls::new() - } - } - - pub fn render(&mut self, args: RenderArgs, w: PistonWindow) { - const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0]; - const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0]; - const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0]; - - let rotation = self.player.rotation; - let cpos = sub(self.player.position, self.camera.position); - - let (x, y) = ((args.width / 2) as Scalar + cpos[0], - (args.height / 2) as Scalar + cpos[1]); - - w.draw_2d(|c, gl| { - let transform = c.transform - .trans(x, y) - .rot_rad(rotation); - let cp = self.camera.position; - let cw = self.camera.width; - let ch = self.camera.height; - let ct = c.transform.trans((args.width / 2) as Scalar, - (args.height / 2) as Scalar); - let ds = c.draw_state.blend(Blend::Alpha); - - clear(BLACK, gl); - self.map.draw_grid(cp, cw, ch, &ds, ct, gl); - for bullet in self.bullets.iter() { - let bpos = sub(bullet.position, self.camera.position); - let (bx, by) = ((args.width / 2) as Scalar + bpos[0], - (args.height / 2) as Scalar + bpos[1]); - let btrans = c.transform.trans(bx, by); - Polygon::new(WHITE).draw(bullet.geometry, &ds, btrans, gl); - } - Polygon::new(RED).draw(self.player.geometry, &ds, transform, gl); - }); - } - - pub fn update(&mut self, args: UpdateArgs) { - let dv = self.controls.velocity_change(self.player.rotation, args.dt); - let dr = self.controls.rotation_change(args.dt); - let firing = self.controls.fire_check(); - - self.player.update(dv, dr, &self.map); - for bullet in self.bullets.iter_mut() { bullet.update(args.dt); } - self.bullets.retain(|&ref bullet| bullet.ttl > 0.0); - if firing { - let (nose, dir, vel) = self.player.trajectory(); - let bul = Bullet::new(nose, add(vel,mul_scalar(dir, 3.0)), 2.0); - self.bullets.push(bul); - self.controls.fire = false; - } - self.camera.follow(self.player.position, &self.map); - } - - pub fn input(&mut self, inp: Input) { - self.controls.update(inp); - } -} diff --git a/src/game/bullet.rs b/src/game/bullet.rs new file mode 100644 index 0000000..85aa971 --- /dev/null +++ b/src/game/bullet.rs @@ -0,0 +1,33 @@ +use piston_window::math::*; + +const BULLET_POLY: &'static [[Scalar; 2]] = &[ + [-1.5, -1.5], + [-1.5, 1.5], + [1.5, 1.5], + [1.5, -1.5] +]; + +#[derive(Debug)] +pub struct Bullet { + pub position: Vec2d, + pub velocity: Vec2d, + pub ttl: Scalar, + pub geometry: &'static [[Scalar; 2]] +} + +impl Bullet { + pub fn new(loc: Vec2d, velocity: Vec2d, ttl: Scalar) -> Self { + Bullet { + position: loc, + velocity: velocity, + ttl: ttl, + geometry: BULLET_POLY + } + } + + pub fn update(&mut self, dt: Scalar) -> Scalar { + self.position = add(self.position, self.velocity); + self.ttl -= dt; + self.ttl + } +} diff --git a/src/game/camera.rs b/src/game/camera.rs new file mode 100644 index 0000000..537baae --- /dev/null +++ b/src/game/camera.rs @@ -0,0 +1,52 @@ +use piston_window::math::*; + +use super::map::Map; + +pub struct Camera { + pub position: Vec2d, + pub height: Scalar, + pub width: Scalar +} + +impl Camera { + pub fn new(pos: Vec2d, width: Scalar, height: Scalar) -> Self { + Camera { + position: pos, + width: width, + height: height + } + } + + pub fn follow(&mut self, pos: Vec2d, map: &Map) { + let dp = sub(pos, self.position); + let xmargin = self.width / 4.0; + let ymargin = self.height / 4.0; + + if dp[0] > xmargin { + self.position[0] += dp[0] - xmargin; + } + if dp[0] < -xmargin { + self.position[0] += dp[0] + xmargin; + } + if dp[1] > ymargin { + self.position[1] += dp[1] - ymargin; + } + if dp[1] < -ymargin { + self.position[1] += dp[1] + ymargin; + } + + if self.position[0] + self.width / 2.0 > map.width { + self.position[0] = map.width - self.width / 2.0; + } + if self.position[0] - self.width / 2.0 < 0.0 { + self.position[0] = 0.0 + self.width / 2.0; + } + if self.position[1] + self.height / 2.0 > map.height { + self.position[1] = map.height - self.height / 2.0; + } + if self.position[1] - self.height / 2.0 < 0.0 { + self.position[1] = 0.0 + self.height / 2.0; + } + + } +} diff --git a/src/game/controls.rs b/src/game/controls.rs new file mode 100644 index 0000000..f1d2d78 --- /dev/null +++ b/src/game/controls.rs @@ -0,0 +1,78 @@ +use piston_window::*; +use piston_window::math::*; + +static TURN_RATE: Scalar = 4.0; +static THRUST_RATE: Scalar = 4.0; + +pub struct Controls { + up_d: bool, + down_d: bool, + left_d: bool, + right_d: bool, + fire: bool +} + +impl Controls { + pub fn new() -> Self { + Controls { + up_d: false, down_d: false, left_d: false, right_d: false, + fire: false + } + } + + pub fn update(&mut self, inp: Input) { + match inp { + Input::Press(b) => { + match b { + Button::Keyboard(Key::Up) => { self.up_d = true; } + Button::Keyboard(Key::Down) => { self.down_d = true; } + Button::Keyboard(Key::Left) => { self.left_d = true; } + Button::Keyboard(Key::Right) => { self.right_d = true; } + _ => {} + } + } + Input::Release(b) => { + match b { + Button::Keyboard(Key::Up) => { self.up_d = false; } + Button::Keyboard(Key::Down) => { self.down_d = false; } + Button::Keyboard(Key::Left) => { self.left_d = false; } + Button::Keyboard(Key::Right) => { self.right_d = false; } + Button::Keyboard(Key::Space) => { self.fire = true; } + _ => {} + } + } + _ => {} + } + } + + pub fn velocity_change(&self, rot: Scalar, dt: Scalar) -> Vec2d { + let thrust = if self.up_d { + THRUST_RATE * dt + } else if self.down_d { + -THRUST_RATE * dt + } else { + 0.0 + }; + if thrust != 0.0 { + [rot.cos() * thrust, rot.sin() * thrust] + } else { + [0.0, 0.0] + } + } + + pub fn rotation_change(&self, dt: Scalar) -> Scalar { + if self.left_d { + -TURN_RATE * dt + } else if self.right_d { + TURN_RATE * dt + } else { + 0.0 + } + } + + pub fn fire_check(&mut self) -> bool { + let firing = self.fire; + self.fire = false; + firing + } +} diff --git a/src/game/map.rs b/src/game/map.rs new file mode 100644 index 0000000..2a1846d --- /dev/null +++ b/src/game/map.rs @@ -0,0 +1,61 @@ +use piston_window::*; +use piston_window::math::*; + +const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 0.05]; + +pub struct Map { + pub width: Scalar, + pub height: Scalar +} + +impl Map { + pub fn new(width: Scalar, height: Scalar) -> Self { + Map { width: width, height: height } + } + + pub fn center(&self) -> Vec2d { + [self.width / 2.0, self.height / 2.0] + } + + pub fn draw_grid(&self, + cam_pos: Vec2d, + cam_width: Scalar, + cam_height: Scalar, + draw_state: &DrawState, + transform: Matrix2d, + g: &mut G) + where G: Graphics + { + + let xcount = (cam_width / 100.0).ceil() as u32 + 2; + let ycount = (cam_height / 100.0).ceil() as u32 + 2; + + let min_x = cam_pos[0] - cam_width / 2.0; + let min_y = cam_pos[1] - cam_height / 2.0; + + let first_x = (min_x / 100.0).trunc() * 100.0; + let first_y = (min_y / 100.0).trunc() * 100.0; + + let start_y = cam_pos[1] - cam_height; + let end_y = cam_pos[1] + cam_height; + for x in 0..xcount { + let line_x = first_x + (100.0 * x as Scalar); + let p1 = sub([line_x, start_y], cam_pos); + let p2 = sub([line_x, end_y], cam_pos); + Line::new(GREEN, 1.0) + .draw([p1[0], p1[1], p2[0], p2[1]], + draw_state, transform, g); + } + + let start_x = cam_pos[0] - cam_width; + let end_x = cam_pos[0] + cam_width; + for y in 0..ycount { + let line_y = first_y + (100.0 * y as Scalar); + let p1 = sub([start_x, line_y], cam_pos); + let p2 = sub([end_x, line_y], cam_pos); + Line::new(GREEN, 1.0) + .draw([p1[0], p1[1], p2[0], p2[1]], + draw_state, transform, g); + } + } +} diff --git a/src/game/mod.rs b/src/game/mod.rs new file mode 100644 index 0000000..7eb8ca2 --- /dev/null +++ b/src/game/mod.rs @@ -0,0 +1,108 @@ +mod controls; +mod bullet; +mod ship; +mod camera; +mod map; + +use piston_window::*; +use piston_window::math::*; +use piston_window::draw_state::Blend; + +use self::ship::Ship; +use self::bullet::Bullet; +use self::camera::Camera; +use self::map::Map; +use self::controls::Controls; + +const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0]; +const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0]; +const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0]; + +pub struct Game { + player: Ship, + bullets: Vec, + map: Map, + camera: Camera, + pub controls: Controls +} + +fn draw_background(g: &mut G) where G: Graphics { + clear(BLACK, g); +} + +fn draw_player(player: &Ship, ds: &DrawState, trans: Matrix2d, g: &mut G) + where G: Graphics { + + let trans = trans + .append_transform(translate(player.position)) + .rot_rad(player.rotation); + Polygon::new(RED).draw(player.geometry, ds, trans, g); +} + +fn draw_bullet(bullet: &Bullet, ds: &DrawState, trans: Matrix2d, g: &mut G) + where G: Graphics { + + let trans = trans + .append_transform(translate(bullet.position)); + Polygon::new(WHITE).draw(bullet.geometry, &ds, trans, g); +} + +impl Game { + pub fn new(width: Scalar, height: Scalar) -> Self { + let new_map = Map::new(10000.0, 10000.0); + let center = new_map.center(); + Game { + player: Ship::new(center), + bullets: Vec::new(), + map: new_map, + camera: Camera::new(center, width, height), + controls: Controls::new() + } + } + + pub fn render(&mut self, args: RenderArgs, w: PistonWindow) { + + w.draw_2d(|context, gl| { + draw_background(gl); + + let ds = context.draw_state.blend(Blend::Alpha); + + let ct = context.transform.trans((args.width / 2) as Scalar, + (args.height / 2) as Scalar); + + let cam_pos = self.camera.position; + let cam_width = self.camera.width; + let cam_height = self.camera.height; + + self.map.draw_grid(cam_pos, cam_width, cam_height, &ds, ct, gl); + + let cam_trans = ct.append_transform(translate(mul_scalar(cam_pos, -1.0))); + + for bullet in self.bullets.iter() { + draw_bullet(&bullet, &ds, cam_trans, gl); + } + + draw_player(&self.player, &ds, cam_trans, gl); + }); + } + + pub fn update(&mut self, args: UpdateArgs) { + let dv = self.controls.velocity_change(self.player.rotation, args.dt); + let dr = self.controls.rotation_change(args.dt); + let firing = self.controls.fire_check(); + + self.player.update(dv, dr, &self.map); + for bullet in self.bullets.iter_mut() { bullet.update(args.dt); } + self.bullets.retain(|&ref bullet| bullet.ttl > 0.0); + if firing { + let (nose, dir, vel) = self.player.trajectory(); + let bul = Bullet::new(nose, add(vel,mul_scalar(dir, 3.0)), 2.0); + self.bullets.push(bul); + } + self.camera.follow(self.player.position, &self.map); + } + + pub fn input(&mut self, inp: Input) { + self.controls.update(inp); + } +} diff --git a/src/game/ship.rs b/src/game/ship.rs new file mode 100644 index 0000000..91d6e37 --- /dev/null +++ b/src/game/ship.rs @@ -0,0 +1,58 @@ +use piston_window::math::*; +use std::f64::consts::*; + +use super::map::Map; + +const SHIP_POLY: &'static [[Scalar; 2]] = &[ + [-10.0, -8.0], + [10.0, 0.0], + [-10.0, 8.0] +]; + +pub struct Ship { + pub rotation: Scalar, + pub position: Vec2d, + pub velocity: Vec2d, + pub geometry: &'static [[Scalar; 2]] +} + +impl Ship { + pub fn new(loc: Vec2d) -> Self { + Ship { + rotation: -FRAC_PI_2, + position: loc, + velocity: [0.0, 0.0], + geometry: SHIP_POLY + } + } + + pub fn update(&mut self, dv: Vec2d, dr: Scalar, map: &Map) { + self.rotation += dr; + self.velocity = add(self.velocity, dv); + self.position = add(self.position, self.velocity); + if self.position[0] > map.width { + self.velocity[0] = 0.0; + self.position[0] = map.width; + } + if self.position[0] < 0.0 { + self.velocity[0] = 0.0; + self.position[0] = 0.0; + } + if self.position[1] > map.height { + self.velocity[1] = 0.0; + self.position[1] = map.height; + } + if self.position[1] < 0.0 { + self.velocity[1] = 0.0; + self.position[1] = 0.0; + } + } + + pub fn trajectory(&self) -> (Vec2d, Vec2d, Vec2d) { + let nose = self.geometry[1]; + let rot = rotate_radians(self.rotation); + let trans = translate(self.position); + let tmat = multiply(trans, rot); + (transform_pos(tmat, nose), transform_vec(rot, [1.0,0.0]), self.velocity) + } +} diff --git a/src/main.rs b/src/main.rs index dbf8dbc..73ade3e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ const YDIM: u32 = 600; fn main() { let window: PistonWindow = WindowSettings::new( - "spinning-square", + "rust-pilot", [XDIM, YDIM] ) .exit_on_esc(true)