Compare commits

...

2 Commits

Author SHA1 Message Date
Mark 7854245a4b
Updated TODO 2024-01-09 18:02:11 -08:00
Mark 749cac6442
Repaired collapse sequences 2024-01-09 18:00:02 -08:00
6 changed files with 119 additions and 24 deletions

View File

@ -1,4 +1,12 @@
## Specific Jobs ## Specific Jobs
- Check for handle leaks
- Rename and crtl-f comments
- gameobject and world
- behavior and personality
- ship (content) / ship (data) / ship (world)
- Fix ship controllers
- Don't allocate each frame
- UI: text arranger - UI: text arranger
- Sound system - Sound system
- Ship death debris - Ship death debris
@ -90,7 +98,6 @@
- Clear all `// TODO:` comments littered in the source - Clear all `// TODO:` comments littered in the source
- CLI options (debug, save location, content location, check content) - CLI options (debug, save location, content location, check content)
- Config file and compile options, remove all those consts. - Config file and compile options, remove all those consts.
- Sprite optimization: do we need to allocate a new `Vec` every frame? Probably not.
- Better error when run outside of directory - Better error when run outside of directory
- Documentation site & front page - Documentation site & front page
- Random animation delay/fps? - Random animation delay/fps?

View File

@ -57,8 +57,27 @@ impl GameData {
} }
pub fn step(&mut self, t: f32) { pub fn step(&mut self, t: f32) {
// TODO: don't allocate on step, need a better
// way to satisfy the borrow checker.
// Same needs to be done in the `world` crate.
let mut to_remove = Vec::new();
for (_, s) in &mut self.ships { for (_, s) in &mut self.ships {
s.step(t); s.step(t);
if s.is_dead() {
to_remove.push(s.get_handle());
}
}
// Remove dead ships
// No fancy animation here, that's handled by the physics system.
for i in to_remove {
let system = self.ship_system_table.remove(&i).unwrap();
self.system_ship_table
.get_mut(&system)
.unwrap()
.retain(|x| *x != i);
self.ships.remove(&i);
} }
} }
} }

View File

@ -93,7 +93,18 @@ impl GPUState {
// Draw ships // Draw ships
for (s, r) in state.world.iter_ship_body() { for (s, r) in state.world.iter_ship_body() {
let data = state.data.get_ship(s.data_handle).unwrap(); // This will be None if this ship is dead.
// Stays around while the physics system runs a collapse sequence
let color = match state.data.get_ship(s.data_handle) {
None => {
// TODO: configurable
[0.2, 0.2, 0.2, 1.0]
}
Some(data) => {
let c = state.content.get_faction(data.get_faction()).color;
[c[0], c[1], c[2], 1.0]
}
};
let ship = state.content.get_ship(s.data_handle.content_handle()); let ship = state.content.get_ship(s.data_handle.content_handle());
let size = (ship.size * ship.sprite.aspect) * ship_scale; let size = (ship.size * ship.sprite.aspect) * ship_scale;
let p = util::rigidbody_position(r); let p = util::rigidbody_position(r);
@ -105,8 +116,6 @@ impl GPUState {
continue; continue;
} }
let angle = util::rigidbody_rotation(r).angle(Vector2 { x: 0.0, y: 1.0 }); let angle = util::rigidbody_rotation(r).angle(Vector2 { x: 0.0, y: 1.0 });
let f = state.content.get_faction(data.get_faction()).color;
let f = [f[0], f[1], f[2], 1.0];
let position = Point2 { let position = Point2 {
x: radar_size / 2.0 + 10.0, x: radar_size / 2.0 + 10.0,
@ -130,7 +139,7 @@ impl GPUState {
position: position.into(), position: position.into(),
angle: -angle.0, // TODO: consistent angles angle: -angle.0, // TODO: consistent angles
size, size,
color: f.into(), color,
sprite_index: ship_sprite.get_index(), sprite_index: ship_sprite.get_index(),
}]), }]),
); );

View File

@ -22,7 +22,6 @@ impl GPUState {
s: &ShipWorldObject, s: &ShipWorldObject,
) { ) {
let r = state.world.get_rigid_body(s.rigid_body).unwrap(); let r = state.world.get_rigid_body(s.rigid_body).unwrap();
let ship = state.data.get_ship(s.data_handle).unwrap();
let ship_pos = util::rigidbody_position(&r); let ship_pos = util::rigidbody_position(&r);
let ship_rot = util::rigidbody_rotation(r); let ship_rot = util::rigidbody_rotation(r);
let ship_ang = -ship_rot.angle(Vector2 { x: 0.0, y: 1.0 }); // TODO: inconsistent angles. Fix! let ship_ang = -ship_rot.angle(Vector2 { x: 0.0, y: 1.0 }); // TODO: inconsistent angles. Fix!
@ -85,8 +84,16 @@ impl GPUState {
); );
self.vertex_buffers.object_counter += 1; self.vertex_buffers.object_counter += 1;
// This will be None if this ship is dead.
// (physics object stays around to complete the death animation)
// If that is the case, we're done, no flares to draw anyway!
let ship = match state.data.get_ship(s.data_handle) {
None => return,
Some(s) => s,
};
let flare = ship.get_outfits().get_flare_sprite(state.content); let flare = ship.get_outfits().get_flare_sprite(state.content);
if s.get_controls().thrust && flare.is_some() && !ship.is_dead() { if s.get_controls().thrust && flare.is_some() {
for engine_point in &ship_cnt.engines { for engine_point in &ship_cnt.engines {
self.queue.write_buffer( self.queue.write_buffer(
&self.global_uniform.object_buffer, &self.global_uniform.object_buffer,

View File

@ -1,4 +1,5 @@
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Rad, Vector2, Zero}; use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Rad, Vector2, Zero};
use content::{FactionHandle, ShipHandle};
use nalgebra::{point, vector}; use nalgebra::{point, vector};
use object::GameShipHandle; use object::GameShipHandle;
@ -29,6 +30,7 @@ pub struct ShipControls {
} }
impl ShipControls { impl ShipControls {
/// Create a new, empty ShipControls
pub fn new() -> Self { pub fn new() -> Self {
ShipControls { ShipControls {
left: false, left: false,
@ -81,12 +83,11 @@ impl ShipCollapseSequence {
fn step( fn step(
&mut self, &mut self,
res: &mut StepResources, res: &mut StepResources,
ship: GameShipHandle, ship_handle: ShipHandle,
rigid_body: &mut RigidBody, rigid_body: &mut RigidBody,
collider: &mut Collider, collider: &mut Collider,
) { ) {
let h = ship.content_handle(); let ship_content = res.ct.get_ship(ship_handle);
let ship_content = res.ct.get_ship(h);
let ship_pos = util::rigidbody_position(rigid_body); let ship_pos = util::rigidbody_position(rigid_body);
let ship_rot = util::rigidbody_rotation(rigid_body); let ship_rot = util::rigidbody_rotation(rigid_body);
let ship_ang = ship_rot.angle(Vector2 { x: 1.0, y: 0.0 }); let ship_ang = ship_rot.angle(Vector2 { x: 1.0, y: 0.0 });
@ -198,6 +199,12 @@ pub struct ShipWorldObject {
/// This ship's collapse sequence /// This ship's collapse sequence
collapse_sequence: ShipCollapseSequence, collapse_sequence: ShipCollapseSequence,
/// This ship's faction.
/// This is technically redundant, faction is also stored in
/// game data, but that's destroyed once the ship dies.
/// We need the faction for the collapse sequence!
faction: FactionHandle,
} }
impl ShipWorldObject { impl ShipWorldObject {
@ -206,6 +213,7 @@ impl ShipWorldObject {
ct: &content::Content, ct: &content::Content,
data_handle: GameShipHandle, data_handle: GameShipHandle,
behavior: Box<dyn ShipBehavior>, behavior: Box<dyn ShipBehavior>,
faction: FactionHandle,
rigid_body: RigidBodyHandle, rigid_body: RigidBodyHandle,
collider: ColliderHandle, collider: ColliderHandle,
) -> Self { ) -> Self {
@ -216,6 +224,7 @@ impl ShipWorldObject {
data_handle, data_handle,
behavior, behavior,
controls: ShipControls::new(), controls: ShipControls::new(),
faction,
collapse_sequence: ShipCollapseSequence::new(ship_content.collapse.length), collapse_sequence: ShipCollapseSequence::new(ship_content.collapse.length),
} }
} }
@ -225,12 +234,39 @@ impl ShipWorldObject {
self.controls = self.behavior.update_controls(res); self.controls = self.behavior.update_controls(res);
} }
/// If this is true, remove this ship from the physics system.
pub fn should_be_removed(&self) -> bool {
self.collapse_sequence.is_done()
}
/// Step this ship's state by t seconds /// Step this ship's state by t seconds
pub fn step( pub fn step(
&mut self, &mut self,
res: &mut StepResources, res: &mut StepResources,
rigid_body: &mut RigidBody, rigid_body: &mut RigidBody,
collider: &mut Collider, collider: &mut Collider,
) {
let ship_data = res.dt.get_ship(self.data_handle);
if ship_data.is_none() {
// If ship data is none, it has been removed because the ship has been destroyed.
// play collapse sequence.
self.collapse_sequence.step(
res,
self.data_handle.content_handle(),
rigid_body,
collider,
);
} else {
return self.step_live(res, rigid_body, collider);
}
}
/// Step this ship's state by t seconds (called when alive)
fn step_live(
&mut self,
res: &mut StepResources,
rigid_body: &mut RigidBody,
collider: &mut Collider,
) { ) {
let ship = res.dt.get_ship(self.data_handle).unwrap(); let ship = res.dt.get_ship(self.data_handle).unwrap();
let ship_content = res.ct.get_ship(self.data_handle.content_handle()); let ship_content = res.ct.get_ship(self.data_handle.content_handle());
@ -306,4 +342,9 @@ impl ShipWorldObject {
pub fn get_controls(&self) -> &ShipControls { pub fn get_controls(&self) -> &ShipControls {
&self.controls &self.controls
} }
/// Get this ship's faction
pub fn get_faction(&self) -> FactionHandle {
self.faction
}
} }

View File

@ -61,7 +61,15 @@ impl<'a> World {
return Some((r, p)); return Some((r, p));
} }
fn remove_ship(&mut self, s: &ShipWorldObject) { fn remove_ship(&mut self, s: ColliderHandle) {
let s = match self.collider_ship_table.get(&s) {
None => return,
Some(s) => match self.ships.get(s) {
None => return,
Some(s) => s,
},
};
self.wrapper.rigid_body_set.remove( self.wrapper.rigid_body_set.remove(
s.rigid_body, s.rigid_body,
&mut self.wrapper.im, &mut self.wrapper.im,
@ -90,13 +98,14 @@ impl<'a> World {
let projectile = projectile.unwrap(); let projectile = projectile.unwrap();
let ship = ship.unwrap(); let ship = ship.unwrap();
let ship_d = res.dt.get_ship_mut(ship.data_handle).unwrap();
let f = res.ct.get_faction(projectile.faction); let f = res.ct.get_faction(projectile.faction);
let r = f.relationships.get(&ship_d.get_faction()).unwrap(); let r = f.relationships.get(&ship.get_faction()).unwrap();
let destory_projectile = match r { let destory_projectile = match r {
content::Relationship::Hostile => { content::Relationship::Hostile => {
// We only apply damage if the target ship is alive
if let Some(ship_d) = res.dt.get_ship_mut(ship.data_handle) {
ship_d.apply_damage(projectile.content.damage); ship_d.apply_damage(projectile.content.damage);
}
true true
} }
_ => false, _ => false,
@ -224,6 +233,7 @@ impl World {
ct, ct,
ship.get_handle(), ship.get_handle(),
Box::new(behavior::Null::new()), Box::new(behavior::Null::new()),
ship.get_faction(),
r, r,
c, c,
), ),
@ -238,10 +248,10 @@ impl World {
let mut projectiles = Vec::new(); let mut projectiles = Vec::new();
let mut to_remove = Vec::new(); let mut to_remove = Vec::new();
for (_, ship_object) in &mut self.ships { for (_, ship_object) in &mut self.ships {
//if s.remove_from_world() { if ship_object.should_be_removed() {
// to_remove.push(s.physics_handle); to_remove.push(ship_object.collider);
// continue; continue;
//} }
let rigid_body = &mut self.wrapper.rigid_body_set[ship_object.rigid_body]; let rigid_body = &mut self.wrapper.rigid_body_set[ship_object.rigid_body];
let collider = &mut self.wrapper.collider_set[ship_object.collider]; let collider = &mut self.wrapper.collider_set[ship_object.collider];
@ -279,8 +289,8 @@ impl World {
} }
// Remove ships that don't exist // Remove ships that don't exist
for s in to_remove { for c in to_remove {
self.remove_ship(s); self.remove_ship(c);
} }
// Create projectiles // Create projectiles
@ -367,9 +377,11 @@ impl World {
}; };
let p = self.projectiles.get(&a); let p = self.projectiles.get(&a);
let s = self let s = self.ships.get_mut(match self.collider_ship_table.get(&b) {
.ships // If none, this ship is dead.
.get_mut(self.collider_ship_table.get(&b).unwrap()); Some(x) => x,
None => continue,
});
if p.is_none() || s.is_none() { if p.is_none() || s.is_none() {
continue; continue;
} }