Added basic ship guns

master
Mark 2023-12-27 20:14:53 -08:00
parent 3f92e62724
commit 389803eae9
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
3 changed files with 147 additions and 20 deletions

View File

@ -1,9 +1,33 @@
use cgmath::Deg; use cgmath::{Deg, Point2, Point3, Vector2};
use std::time::Instant; use std::time::Instant;
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode}; use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
use super::{Camera, InputStatus, Ship, System}; use super::{Camera, InputStatus, Ship, System};
use crate::{consts, content::Content, render::Sprite, render::Spriteable}; use crate::{
consts,
content::Content,
render::Spriteable,
render::{Sprite, SpriteTexture},
};
pub struct Projectile {
pub position: Point2<f32>,
pub velocity: Vector2<f32>,
pub sprite: SpriteTexture,
pub angle: Deg<f32>,
pub lifetime: f32,
}
impl Projectile {
pub fn tick(&mut self, t: f32) {
self.position += self.velocity * t;
self.lifetime -= t;
}
pub fn is_expired(&self) -> bool {
return self.lifetime < 0.0;
}
}
pub struct Game { pub struct Game {
pub input: InputStatus, pub input: InputStatus,
@ -13,6 +37,7 @@ pub struct Game {
pub system: System, pub system: System,
pub camera: Camera, pub camera: Camera,
paused: bool, paused: bool,
pub projectiles: Vec<Projectile>,
pub time_scale: f32, pub time_scale: f32,
} }
@ -21,12 +46,14 @@ impl Game {
Game { Game {
last_update: Instant::now(), last_update: Instant::now(),
input: InputStatus::new(), input: InputStatus::new(),
projectiles: Vec::new(),
player: Ship::new(&ct.ships[0], (0.0, 0.0).into()), player: Ship::new(&ct.ships[0], (0.0, 0.0).into()),
camera: Camera { camera: Camera {
pos: (0.0, 0.0).into(), pos: (0.0, 0.0).into(),
zoom: 500.0, zoom: 500.0,
}, },
system: System::new(&ct.systems[0]), system: System::new(&ct.systems[0]),
paused: false, paused: false,
time_scale: 1.0, time_scale: 1.0,
test: Ship::new(&ct.ships[0], (100.0, 100.0).into()), test: Ship::new(&ct.ships[0], (100.0, 100.0).into()),
@ -57,17 +84,16 @@ impl Game {
pub fn update(&mut self) { pub fn update(&mut self) {
let t: f32 = self.last_update.elapsed().as_secs_f32() * self.time_scale; let t: f32 = self.last_update.elapsed().as_secs_f32() * self.time_scale;
self.player.engines_on = self.input.key_thrust; self.projectiles.retain_mut(|p| {
if self.input.key_thrust { p.tick(t);
self.player.physicsbody.thrust(50.0 * t); !p.is_expired()
} });
if self.input.key_right { // Update player and handle result
self.player.physicsbody.rot(Deg(35.0) * t); self.player.update_controls(&self.input);
} let mut p = self.player.tick(t);
if p.projectiles.len() != 0 {
if self.input.key_left { self.projectiles.append(&mut p.projectiles);
self.player.physicsbody.rot(Deg(-35.0) * t);
} }
if self.input.v_scroll != 0.0 { if self.input.v_scroll != 0.0 {
@ -76,7 +102,6 @@ impl Game {
self.input.v_scroll = 0.0; self.input.v_scroll = 0.0;
} }
self.player.physicsbody.tick(t);
self.camera.pos = self.player.physicsbody.pos; self.camera.pos = self.player.physicsbody.pos;
self.last_update = Instant::now(); self.last_update = Instant::now();
@ -96,6 +121,21 @@ impl Game {
// I've tried this, but it doesn't seem to work with transparent textures. // I've tried this, but it doesn't seem to work with transparent textures.
sprites.sort_by(|a, b| b.pos.z.total_cmp(&a.pos.z)); sprites.sort_by(|a, b| b.pos.z.total_cmp(&a.pos.z));
// Don't waste time sorting these, they should always be on top.
for p in &self.projectiles {
sprites.push(Sprite {
texture: p.sprite.clone(),
pos: Point3 {
x: p.position.x,
y: p.position.y,
z: 1.0,
},
size: 10.0,
angle: p.angle,
children: None,
})
}
return sprites; return sprites;
} }
} }

View File

@ -5,6 +5,7 @@ pub struct InputStatus {
pub key_left: bool, pub key_left: bool,
pub key_right: bool, pub key_right: bool,
pub key_thrust: bool, pub key_thrust: bool,
pub key_guns: bool,
pub v_scroll: f32, pub v_scroll: f32,
} }
@ -14,6 +15,7 @@ impl InputStatus {
key_left: false, key_left: false,
key_right: false, key_right: false,
key_thrust: false, key_thrust: false,
key_guns: false,
v_scroll: 0.0, v_scroll: 0.0,
scroll_speed: 10.0, scroll_speed: 10.0,
} }
@ -23,6 +25,7 @@ impl InputStatus {
self.key_left = false; self.key_left = false;
self.key_right = false; self.key_right = false;
self.key_thrust = false; self.key_thrust = false;
self.key_guns = false;
} }
pub fn process_key(&mut self, state: &ElementState, key: &VirtualKeyCode) { pub fn process_key(&mut self, state: &ElementState, key: &VirtualKeyCode) {
@ -31,6 +34,7 @@ impl InputStatus {
VirtualKeyCode::Left => self.key_left = down, VirtualKeyCode::Left => self.key_left = down,
VirtualKeyCode::Right => self.key_right = down, VirtualKeyCode::Right => self.key_right = down,
VirtualKeyCode::Up => self.key_thrust = down, VirtualKeyCode::Up => self.key_thrust = down,
VirtualKeyCode::Space => self.key_guns = down,
_ => {} _ => {}
} }
} }

View File

@ -1,35 +1,118 @@
use cgmath::{Deg, Point2, Point3}; use cgmath::{Deg, EuclideanSpace, Matrix2, Point2, Point3, Vector2};
use crate::{ use crate::{
content::{self, ship::Engine}, content,
physics::PhysicsBody, physics::PhysicsBody,
render::{Sprite, SpriteTexture, Spriteable, SubSprite}, render::{Sprite, SpriteTexture, Spriteable, SubSprite},
}; };
use super::{game::Projectile, InputStatus};
pub struct ShipControls {
pub left: bool,
pub right: bool,
pub thrust: bool,
pub guns: bool,
}
impl ShipControls {
pub fn new() -> Self {
ShipControls {
left: false,
right: false,
thrust: false,
guns: false,
}
}
}
pub struct ShipTickResult {
pub projectiles: Vec<Projectile>,
}
pub struct Ship { pub struct Ship {
pub physicsbody: PhysicsBody, pub physicsbody: PhysicsBody,
pub engines_on: bool, pub controls: ShipControls,
sprite: SpriteTexture, sprite: SpriteTexture,
size: f32, size: f32,
engines: Vec<Engine>, engines: Vec<content::Engine>,
guns: Vec<content::ShipGun>,
} }
impl Ship { impl Ship {
pub fn new(ct: &content::ship::Ship, pos: Point2<f32>) -> Self { pub fn new(ct: &content::Ship, pos: Point2<f32>) -> Self {
Ship { Ship {
physicsbody: PhysicsBody::new(pos), physicsbody: PhysicsBody::new(pos),
sprite: SpriteTexture(ct.sprite.clone()), sprite: SpriteTexture(ct.sprite.clone()),
size: ct.size, size: ct.size,
engines: ct.engines.clone(), engines: ct.engines.clone(),
engines_on: false, guns: ct.guns.clone(),
controls: ShipControls::new(),
} }
} }
pub fn update_controls(&mut self, input: &InputStatus) {
self.controls.thrust = input.key_thrust;
self.controls.right = input.key_right;
self.controls.left = input.key_left;
self.controls.guns = input.key_guns;
}
pub fn fire_guns(&mut self) -> Vec<Projectile> {
let mut out = Vec::new();
for i in &mut self.guns {
if i.active_cooldown > 0.0 {
continue;
}
i.active_cooldown = i.cooldown;
let p = self.physicsbody.pos
+ (Matrix2::from_angle(self.physicsbody.angle) * i.pos.to_vec());
out.push(Projectile {
position: p,
velocity: self.physicsbody.vel
+ (Matrix2::from_angle(self.physicsbody.angle) * Vector2 { x: 0.0, y: 400.0 }),
angle: self.physicsbody.angle,
sprite: SpriteTexture("projectile::blaster".into()),
lifetime: 5.0,
})
}
return out;
}
pub fn tick(&mut self, t: f32) -> ShipTickResult {
if self.controls.thrust {
self.physicsbody.thrust(50.0 * t);
}
if self.controls.right {
self.physicsbody.rot(Deg(35.0) * t);
}
if self.controls.left {
self.physicsbody.rot(Deg(-35.0) * t);
}
let p = if self.controls.guns {
self.fire_guns()
} else {
Vec::new()
};
self.physicsbody.tick(t);
for i in &mut self.guns {
i.active_cooldown -= t;
}
return ShipTickResult { projectiles: p };
}
} }
impl Spriteable for Ship { impl Spriteable for Ship {
fn get_sprite(&self) -> Sprite { fn get_sprite(&self) -> Sprite {
let engines = if self.engines_on { let engines = if self.controls.thrust {
Some( Some(
self.engines self.engines
.iter() .iter()