Added basic ship behaviors
parent
bffc7b9f23
commit
0184418394
|
@ -9,6 +9,7 @@ use crate::{
|
||||||
inputstatus::InputStatus,
|
inputstatus::InputStatus,
|
||||||
physics::{util, Physics, ShipHandle},
|
physics::{util, Physics, ShipHandle},
|
||||||
render::Sprite,
|
render::Sprite,
|
||||||
|
shipbehavior::{self, ShipBehavior},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
|
@ -20,14 +21,15 @@ pub struct Game {
|
||||||
paused: bool,
|
paused: bool,
|
||||||
pub time_scale: f32,
|
pub time_scale: f32,
|
||||||
|
|
||||||
world: Physics,
|
physics: Physics,
|
||||||
|
shipbehaviors: Vec<Box<dyn ShipBehavior>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
pub fn new(ct: Content) -> Self {
|
pub fn new(ct: Content) -> Self {
|
||||||
let mut world = Physics::new();
|
let mut physics = Physics::new();
|
||||||
|
|
||||||
let c = world.add_ship(
|
let h1 = physics.add_ship(
|
||||||
&ct.ships[0],
|
&ct.ships[0],
|
||||||
vec![
|
vec![
|
||||||
outfits::ShipOutfit::Gun(outfits::ShipGun::new(ct.guns[0].clone(), 1)),
|
outfits::ShipOutfit::Gun(outfits::ShipGun::new(ct.guns[0].clone(), 1)),
|
||||||
|
@ -37,20 +39,28 @@ impl Game {
|
||||||
Point2 { x: 0.0, y: 0.0 },
|
Point2 { x: 0.0, y: 0.0 },
|
||||||
);
|
);
|
||||||
|
|
||||||
world.add_ship(&ct.ships[0], vec![], Point2 { x: 300.0, y: 300.0 });
|
let h2 = physics.add_ship(&ct.ships[0], vec![], Point2 { x: 300.0, y: 300.0 });
|
||||||
world.add_ship(
|
let h3 = physics.add_ship(
|
||||||
&ct.ships[0],
|
&ct.ships[0],
|
||||||
vec![],
|
vec![outfits::ShipOutfit::Gun(outfits::ShipGun::new(
|
||||||
|
ct.guns[0].clone(),
|
||||||
|
0,
|
||||||
|
))],
|
||||||
Point2 {
|
Point2 {
|
||||||
x: -300.0,
|
x: -300.0,
|
||||||
y: 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 {
|
Game {
|
||||||
last_update: Instant::now(),
|
last_update: Instant::now(),
|
||||||
input: InputStatus::new(),
|
input: InputStatus::new(),
|
||||||
player: c,
|
player: h1,
|
||||||
|
|
||||||
camera: Camera {
|
camera: Camera {
|
||||||
pos: (0.0, 0.0).into(),
|
pos: (0.0, 0.0).into(),
|
||||||
|
@ -60,7 +70,8 @@ impl Game {
|
||||||
|
|
||||||
paused: false,
|
paused: false,
|
||||||
time_scale: 1.0,
|
time_scale: 1.0,
|
||||||
world,
|
physics,
|
||||||
|
shipbehaviors,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,11 +99,11 @@ 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.world
|
for b in &mut self.shipbehaviors {
|
||||||
.get_ship_mut(&self.player)
|
b.update_controls(&mut self.physics, &self.input, self.player);
|
||||||
.update_controls(&self.input);
|
}
|
||||||
|
|
||||||
self.world.tick(t);
|
self.physics.step(t);
|
||||||
|
|
||||||
if self.input.v_scroll != 0.0 {
|
if self.input.v_scroll != 0.0 {
|
||||||
self.camera.zoom =
|
self.camera.zoom =
|
||||||
|
@ -101,8 +112,8 @@ impl Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Camera physics
|
// TODO: Camera physics
|
||||||
let r = self.world.get_ship_mut(&self.player).physics_handle;
|
let r = self.physics.get_ship_mut(&self.player).physics_handle;
|
||||||
let r = self.world.get_rigid_body(r.0); // TODO: r.0 shouldn't be public
|
let r = self.physics.get_rigid_body(r.0); // TODO: r.0 shouldn't be public
|
||||||
let ship_pos = util::rigidbody_position(r);
|
let ship_pos = util::rigidbody_position(r);
|
||||||
self.camera.pos = ship_pos;
|
self.camera.pos = ship_pos;
|
||||||
self.last_update = Instant::now();
|
self.last_update = Instant::now();
|
||||||
|
@ -112,7 +123,7 @@ impl Game {
|
||||||
let mut sprites: Vec<Sprite> = Vec::new();
|
let mut sprites: Vec<Sprite> = Vec::new();
|
||||||
|
|
||||||
sprites.append(&mut self.system.get_sprites());
|
sprites.append(&mut self.system.get_sprites());
|
||||||
sprites.extend(self.world.get_ship_sprites());
|
sprites.extend(self.physics.get_ship_sprites());
|
||||||
|
|
||||||
// Make sure sprites are drawn in the correct order
|
// Make sure sprites are drawn in the correct order
|
||||||
// (note the reversed a, b in the comparator)
|
// (note the reversed a, b in the comparator)
|
||||||
|
@ -122,7 +133,7 @@ impl Game {
|
||||||
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.
|
// Don't waste time sorting these, they should always be on top.
|
||||||
sprites.extend(self.world.get_projectile_sprites());
|
sprites.extend(self.physics.get_projectile_sprites());
|
||||||
|
|
||||||
return sprites;
|
return sprites;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ mod inputstatus;
|
||||||
mod objects;
|
mod objects;
|
||||||
mod physics;
|
mod physics;
|
||||||
mod render;
|
mod render;
|
||||||
|
mod shipbehavior;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use galactica_content as content;
|
use galactica_content as content;
|
||||||
|
|
|
@ -11,11 +11,14 @@ use super::ProjectileBuilder;
|
||||||
use crate::{
|
use crate::{
|
||||||
content,
|
content,
|
||||||
game::outfits,
|
game::outfits,
|
||||||
inputstatus::InputStatus,
|
|
||||||
physics::{util, ShipHandle},
|
physics::{util, ShipHandle},
|
||||||
render::{Sprite, SpriteTexture},
|
render::{Sprite, SpriteTexture},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub struct ShipTickResult {
|
||||||
|
pub projectiles: Vec<ProjectileBuilder>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ShipControls {
|
pub struct ShipControls {
|
||||||
pub left: bool,
|
pub left: bool,
|
||||||
pub right: bool,
|
pub right: bool,
|
||||||
|
@ -34,10 +37,6 @@ impl ShipControls {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ShipTickResult {
|
|
||||||
pub projectiles: Vec<ProjectileBuilder>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Ship {
|
pub struct Ship {
|
||||||
pub physics_handle: ShipHandle,
|
pub physics_handle: ShipHandle,
|
||||||
outfits: outfits::ShipOutfits,
|
outfits: outfits::ShipOutfits,
|
||||||
|
@ -45,8 +44,6 @@ pub struct Ship {
|
||||||
sprite: SpriteTexture,
|
sprite: SpriteTexture,
|
||||||
size: f32,
|
size: f32,
|
||||||
pub hull: f32,
|
pub hull: f32,
|
||||||
|
|
||||||
// TODO: replace with AI enum
|
|
||||||
pub controls: ShipControls,
|
pub controls: ShipControls,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,20 +61,13 @@ impl Ship {
|
||||||
Ship {
|
Ship {
|
||||||
physics_handle,
|
physics_handle,
|
||||||
outfits: o,
|
outfits: o,
|
||||||
controls: ShipControls::new(),
|
|
||||||
sprite: SpriteTexture(c.sprite.clone()),
|
sprite: SpriteTexture(c.sprite.clone()),
|
||||||
size: c.size,
|
size: c.size,
|
||||||
hull: c.hull,
|
hull: c.hull,
|
||||||
|
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, r: &RigidBody) -> Vec<ProjectileBuilder> {
|
pub fn fire_guns(&mut self, r: &RigidBody) -> Vec<ProjectileBuilder> {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
|
@ -130,10 +120,11 @@ impl Ship {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, r: &mut RigidBody, t: f32) -> ShipTickResult {
|
/// Apply the effects of all active controls
|
||||||
|
pub fn apply_controls(&mut self, r: &mut RigidBody, t: f32) -> ShipTickResult {
|
||||||
let ship_ang = util::rigidbody_angle(r);
|
let ship_ang = util::rigidbody_angle(r);
|
||||||
|
|
||||||
let engine_force = Matrix2::from_angle(ship_ang) * Vector2 { x: 0.0, y: 1.0 } * t;
|
let engine_force = Matrix2::from_angle(ship_ang) * Vector2 { x: 0.0, y: 1.0 } * t;
|
||||||
|
|
||||||
if self.controls.thrust {
|
if self.controls.thrust {
|
||||||
for e in self.outfits.iter_engines() {
|
for e in self.outfits.iter_engines() {
|
||||||
r.apply_impulse(vector![engine_force.x, engine_force.y] * e.thrust, true);
|
r.apply_impulse(vector![engine_force.x, engine_force.y] * e.thrust, true);
|
||||||
|
|
|
@ -101,7 +101,7 @@ impl Physics {
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, t: f32) {
|
pub fn step(&mut self, t: f32) {
|
||||||
// Run ship updates
|
// Run ship updates
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
let mut to_remove = Vec::new();
|
let mut to_remove = Vec::new();
|
||||||
|
@ -111,7 +111,7 @@ impl Physics {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let r = &mut self.wrapper.rigid_body_set[s.physics_handle.0];
|
let r = &mut self.wrapper.rigid_body_set[s.physics_handle.0];
|
||||||
res.push(s.tick(r, t));
|
res.push(s.apply_controls(r, t));
|
||||||
}
|
}
|
||||||
for r in to_remove {
|
for r in to_remove {
|
||||||
self.remove_ship(r);
|
self.remove_ship(r);
|
||||||
|
@ -170,6 +170,14 @@ impl Physics {
|
||||||
self.ships.get_mut(&s.1).unwrap()
|
self.ships.get_mut(&s.1).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_ship_body(&self, s: &ShipHandle) -> (&objects::Ship, &RigidBody) {
|
||||||
|
// TODO: handle dead handles
|
||||||
|
(
|
||||||
|
self.ships.get(&s.1).unwrap(),
|
||||||
|
self.wrapper.rigid_body_set.get(s.0).unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_ship_sprites(&self) -> impl Iterator<Item = Sprite> + '_ {
|
pub fn get_ship_sprites(&self) -> impl Iterator<Item = Sprite> + '_ {
|
||||||
self.ships
|
self.ships
|
||||||
.values()
|
.values()
|
||||||
|
|
|
@ -18,6 +18,13 @@ pub fn rigidbody_angle(r: &RigidBody) -> Deg<f32> {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rigidbody_rotation(r: &RigidBody) -> Vector2<f32> {
|
||||||
|
Vector2 {
|
||||||
|
x: r.rotation().im,
|
||||||
|
y: r.rotation().re,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rigidbody_velocity(r: &RigidBody) -> cgmath::Vector2<f32> {
|
pub fn rigidbody_velocity(r: &RigidBody) -> cgmath::Vector2<f32> {
|
||||||
let v = r.velocity_at_point(&nalgebra::Point2::new(
|
let v = r.velocity_at_point(&nalgebra::Point2::new(
|
||||||
r.translation()[0],
|
r.translation()[0],
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
use cgmath::{Deg, InnerSpace};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
inputstatus::InputStatus,
|
||||||
|
physics::{util, Physics, ShipHandle},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait ShipBehavior
|
||||||
|
where
|
||||||
|
Self: Send,
|
||||||
|
{
|
||||||
|
fn update_controls(&mut self, physics: &mut Physics, input: &InputStatus, player: ShipHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Dummy {
|
||||||
|
_handle: ShipHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dummy {
|
||||||
|
pub fn new(handle: ShipHandle) -> Box<Self> {
|
||||||
|
Box::new(Self { _handle: handle })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShipBehavior for Dummy {
|
||||||
|
fn update_controls(
|
||||||
|
&mut self,
|
||||||
|
_physics: &mut Physics,
|
||||||
|
_input: &InputStatus,
|
||||||
|
_player: ShipHandle,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Player {
|
||||||
|
handle: ShipHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Player {
|
||||||
|
pub fn new(handle: ShipHandle) -> Box<Self> {
|
||||||
|
Box::new(Self { handle })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShipBehavior for Player {
|
||||||
|
fn update_controls(&mut self, physics: &mut Physics, input: &InputStatus, _player: ShipHandle) {
|
||||||
|
let s = physics.get_ship_mut(&self.handle);
|
||||||
|
s.controls.left = input.key_left;
|
||||||
|
s.controls.right = input.key_right;
|
||||||
|
s.controls.guns = input.key_guns;
|
||||||
|
s.controls.thrust = input.key_thrust;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Point {
|
||||||
|
handle: ShipHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
pub fn new(handle: ShipHandle) -> Box<Self> {
|
||||||
|
Box::new(Self { handle })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShipBehavior for Point {
|
||||||
|
fn update_controls(&mut self, physics: &mut Physics, _input: &InputStatus, player: ShipHandle) {
|
||||||
|
let (_, r) = physics.get_ship_body(&player);
|
||||||
|
let p = util::rigidbody_position(r);
|
||||||
|
|
||||||
|
let (_, r) = physics.get_ship_body(&self.handle);
|
||||||
|
let t = util::rigidbody_position(r);
|
||||||
|
let pa = util::rigidbody_rotation(r);
|
||||||
|
let v = r.angvel();
|
||||||
|
|
||||||
|
let d: Deg<f32> = (t - p).angle(pa).into();
|
||||||
|
println!("{:?}", d);
|
||||||
|
|
||||||
|
let s = physics.get_ship_mut(&self.handle);
|
||||||
|
|
||||||
|
s.controls.left = false;
|
||||||
|
s.controls.right = false;
|
||||||
|
|
||||||
|
if d < Deg(0.0) && v < 0.1 {
|
||||||
|
s.controls.left = false;
|
||||||
|
s.controls.right = true;
|
||||||
|
println!("r")
|
||||||
|
} else if d > Deg(0.0) && v > -0.1 {
|
||||||
|
println!("l");
|
||||||
|
s.controls.left = true;
|
||||||
|
s.controls.right = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.controls.guns = true;
|
||||||
|
s.controls.thrust = false;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue