Galactica/src/game/game.rs
2023-12-29 18:34:30 -08:00

141 lines
3.5 KiB
Rust

use cgmath::Point2;
use std::time::Instant;
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
use super::{camera::Camera, outfits, system::System};
use crate::{
consts,
content::Content,
inputstatus::InputStatus,
physics::{util, Physics, ShipHandle},
render::Sprite,
shipbehavior::{self, ShipBehavior},
};
pub struct Game {
pub input: InputStatus,
pub last_update: Instant,
pub player: ShipHandle,
pub system: System,
pub camera: Camera,
paused: bool,
pub time_scale: f32,
physics: Physics,
shipbehaviors: Vec<Box<dyn ShipBehavior>>,
}
impl Game {
pub fn new(ct: Content) -> Self {
let mut physics = Physics::new();
let h1 = physics.add_ship(
&ct.ships[0],
vec![
outfits::ShipOutfit::Gun(outfits::ShipGun::new(ct.guns[0].clone(), 1)),
outfits::ShipOutfit::Gun(outfits::ShipGun::new(ct.guns[0].clone(), 2)),
outfits::ShipOutfit::Engine(ct.engines[0].clone()),
],
Point2 { x: 0.0, y: 0.0 },
);
let h2 = physics.add_ship(&ct.ships[0], vec![], Point2 { x: 300.0, y: 300.0 });
let h3 = physics.add_ship(
&ct.ships[0],
vec![outfits::ShipOutfit::Gun(outfits::ShipGun::new(
ct.guns[0].clone(),
0,
))],
Point2 {
x: -300.0,
y: 300.0,
},
);
let mut shipbehaviors: Vec<Box<dyn ShipBehavior>> = Vec::new();
shipbehaviors.push(shipbehavior::Player::new(h1));
shipbehaviors.push(shipbehavior::Point::new(h3));
shipbehaviors.push(shipbehavior::Dummy::new(h2));
Game {
last_update: Instant::now(),
input: InputStatus::new(),
player: h1,
camera: Camera {
pos: (0.0, 0.0).into(),
zoom: 500.0,
},
system: System::new(&ct.systems[0]),
paused: false,
time_scale: 1.0,
physics,
shipbehaviors,
}
}
pub fn process_key(&mut self, state: &ElementState, key: &VirtualKeyCode) {
self.input.process_key(state, key)
}
pub fn process_click(&mut self, state: &ElementState, key: &MouseButton) {
self.input.process_click(state, key)
}
pub fn process_scroll(&mut self, delta: &MouseScrollDelta, phase: &TouchPhase) {
self.input.process_scroll(delta, phase)
}
pub fn set_paused(&mut self, pause: bool) {
if pause {
self.paused = true;
self.input.release_all()
} else {
self.paused = false;
}
}
pub fn update(&mut self) {
let t: f32 = self.last_update.elapsed().as_secs_f32() * self.time_scale;
for b in &mut self.shipbehaviors {
b.update_controls(&mut self.physics, &self.input, self.player);
}
self.physics.step(t);
if self.input.v_scroll != 0.0 {
self.camera.zoom =
(self.camera.zoom + self.input.v_scroll).clamp(consts::ZOOM_MIN, consts::ZOOM_MAX);
self.input.v_scroll = 0.0;
}
// TODO: Camera physics
let r = self.physics.get_ship_mut(&self.player).physics_handle;
let r = self.physics.get_rigid_body(r.0); // TODO: r.0 shouldn't be public
let ship_pos = util::rigidbody_position(r);
self.camera.pos = ship_pos;
self.last_update = Instant::now();
}
pub fn get_sprites(&self) -> Vec<Sprite> {
let mut sprites: Vec<Sprite> = Vec::new();
sprites.append(&mut self.system.get_sprites());
sprites.extend(self.physics.get_ship_sprites());
// Make sure sprites are drawn in the correct order
// (note the reversed a, b in the comparator)
//
// TODO: maybe use a gpu depth buffer instead?
// 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));
// Don't waste time sorting these, they should always be on top.
sprites.extend(self.physics.get_projectile_sprites());
return sprites;
}
}