Added animation automata to ships and projectiles
parent
f4c0e91851
commit
132148fee3
|
@ -2,7 +2,7 @@ use crate::{AnimSectionHandle, Content, SectionEdge, SpriteHandle};
|
||||||
|
|
||||||
/// A single frame's state
|
/// A single frame's state
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SpriteAnimationFrame {
|
pub struct AnimationState {
|
||||||
/// The index of the texture we're fading from
|
/// The index of the texture we're fading from
|
||||||
pub texture_a: u32,
|
pub texture_a: u32,
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ pub struct SpriteAnimationFrame {
|
||||||
pub fade: f32,
|
pub fade: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpriteAnimationFrame {
|
impl AnimationState {
|
||||||
/// Convenience method.
|
/// Convenience method.
|
||||||
/// Get texture index as an array
|
/// Get texture index as an array
|
||||||
pub fn texture_index(&self) -> [u32; 2] {
|
pub fn texture_index(&self) -> [u32; 2] {
|
||||||
|
@ -224,8 +224,8 @@ impl AnimAutomaton {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current frame of this animation
|
/// Get the current frame of this animation
|
||||||
pub fn get_texture_idx(&self) -> SpriteAnimationFrame {
|
pub fn get_texture_idx(&self) -> AnimationState {
|
||||||
return SpriteAnimationFrame {
|
return AnimationState {
|
||||||
texture_a: self.last_texture,
|
texture_a: self.last_texture,
|
||||||
texture_b: self.next_texture,
|
texture_b: self.next_texture,
|
||||||
fade: self.current_fade,
|
fade: self.current_fade,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use galactica_content::{FactionHandle, Projectile};
|
use galactica_content::{AnimAutomaton, AnimationState, Content, FactionHandle, Projectile};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rapier2d::{dynamics::RigidBodyHandle, geometry::ColliderHandle};
|
use rapier2d::{dynamics::RigidBodyHandle, geometry::ColliderHandle};
|
||||||
|
|
||||||
|
@ -8,6 +8,9 @@ pub struct PhysProjectile {
|
||||||
/// This projectile's game data
|
/// This projectile's game data
|
||||||
pub content: Projectile,
|
pub content: Projectile,
|
||||||
|
|
||||||
|
/// This projectile's sprite animation state
|
||||||
|
anim: AnimAutomaton,
|
||||||
|
|
||||||
/// The remaining lifetime of this projectile, in seconds
|
/// The remaining lifetime of this projectile, in seconds
|
||||||
pub lifetime: f32,
|
pub lifetime: f32,
|
||||||
|
|
||||||
|
@ -27,7 +30,8 @@ pub struct PhysProjectile {
|
||||||
impl PhysProjectile {
|
impl PhysProjectile {
|
||||||
/// Create a new projectile
|
/// Create a new projectile
|
||||||
pub fn new(
|
pub fn new(
|
||||||
content: Projectile, // TODO: use a handle
|
ct: &Content,
|
||||||
|
content: Projectile, // TODO: use a handle?
|
||||||
rigid_body: RigidBodyHandle,
|
rigid_body: RigidBodyHandle,
|
||||||
faction: FactionHandle,
|
faction: FactionHandle,
|
||||||
collider: ColliderHandle,
|
collider: ColliderHandle,
|
||||||
|
@ -36,6 +40,7 @@ impl PhysProjectile {
|
||||||
let size_rng = content.size_rng;
|
let size_rng = content.size_rng;
|
||||||
let lifetime = content.lifetime;
|
let lifetime = content.lifetime;
|
||||||
PhysProjectile {
|
PhysProjectile {
|
||||||
|
anim: AnimAutomaton::new(ct, content.sprite),
|
||||||
rigid_body,
|
rigid_body,
|
||||||
collider,
|
collider,
|
||||||
content,
|
content,
|
||||||
|
@ -46,8 +51,9 @@ impl PhysProjectile {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process this projectile's state after `t` seconds
|
/// Process this projectile's state after `t` seconds
|
||||||
pub fn tick(&mut self, t: f32) {
|
pub fn tick(&mut self, ct: &Content, t: f32) {
|
||||||
self.lifetime -= t;
|
self.lifetime -= t;
|
||||||
|
self.anim.step(ct, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Has this projectile expired?
|
/// Has this projectile expired?
|
||||||
|
@ -55,3 +61,10 @@ impl PhysProjectile {
|
||||||
return self.lifetime < 0.0;
|
return self.lifetime < 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PhysProjectile {
|
||||||
|
/// Get this projectile's animation state
|
||||||
|
pub fn get_anim_state(&self) -> AnimationState {
|
||||||
|
self.anim.get_texture_idx()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use galactica_content::{Content, FactionHandle, ShipHandle};
|
use galactica_content::{
|
||||||
|
AnimAutomaton, AnimationState, Content, EnginePoint, FactionHandle, OutfitHandle, ShipHandle,
|
||||||
|
};
|
||||||
use nalgebra::{point, vector, Rotation2, Vector2};
|
use nalgebra::{point, vector, Rotation2, Vector2};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rapier2d::{
|
use rapier2d::{
|
||||||
|
@ -51,7 +53,13 @@ pub struct PhysSimShip {
|
||||||
pub collider: ColliderHandle,
|
pub collider: ColliderHandle,
|
||||||
|
|
||||||
/// This ship's game data
|
/// This ship's game data
|
||||||
pub data: ShipData,
|
pub(crate) data: ShipData,
|
||||||
|
|
||||||
|
/// This ship's sprite animation state
|
||||||
|
anim: AnimAutomaton,
|
||||||
|
|
||||||
|
/// Animation state for each of this ship's engines
|
||||||
|
engine_anim: Vec<(EnginePoint, AnimAutomaton)>,
|
||||||
|
|
||||||
/// This ship's controls
|
/// This ship's controls
|
||||||
pub(crate) controls: ShipControls,
|
pub(crate) controls: ShipControls,
|
||||||
|
@ -72,9 +80,11 @@ impl PhysSimShip {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let ship_ct = ct.get_ship(handle);
|
let ship_ct = ct.get_ship(handle);
|
||||||
PhysSimShip {
|
PhysSimShip {
|
||||||
|
anim: AnimAutomaton::new(ct, ship_ct.sprite),
|
||||||
rigid_body,
|
rigid_body,
|
||||||
collider,
|
collider,
|
||||||
data: ShipData::new(ct, handle, faction, personality),
|
data: ShipData::new(ct, handle, faction, personality),
|
||||||
|
engine_anim: Vec::new(),
|
||||||
controls: ShipControls::new(),
|
controls: ShipControls::new(),
|
||||||
collapse_sequence: Some(ShipCollapseSequence::new(ship_ct.collapse.length)),
|
collapse_sequence: Some(ShipCollapseSequence::new(ship_ct.collapse.length)),
|
||||||
}
|
}
|
||||||
|
@ -88,6 +98,18 @@ impl PhysSimShip {
|
||||||
collider: &mut Collider,
|
collider: &mut Collider,
|
||||||
) {
|
) {
|
||||||
self.data.step(res.t);
|
self.data.step(res.t);
|
||||||
|
self.anim.step(res.ct, res.t);
|
||||||
|
|
||||||
|
if self.controls.thrust {
|
||||||
|
for (_, e) in &mut self.engine_anim {
|
||||||
|
e.step(res.ct, res.t);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (_, e) in &mut self.engine_anim {
|
||||||
|
e.reset(res.ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match self.data.get_state() {
|
match self.data.get_state() {
|
||||||
ShipState::Collapsing { .. } => {
|
ShipState::Collapsing { .. } => {
|
||||||
// Borrow checker hack, so we may pass self.data
|
// Borrow checker hack, so we may pass self.data
|
||||||
|
@ -197,9 +219,69 @@ impl PhysSimShip {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Public mutable
|
||||||
|
impl PhysSimShip {
|
||||||
|
/// Re-create this ship's engine flare animations
|
||||||
|
/// Should be called whenever we change outfits
|
||||||
|
fn update_flares(&mut self, ct: &Content) {
|
||||||
|
// TODO: better way to pick flare sprite
|
||||||
|
let mut flare = None;
|
||||||
|
for (h, _) in self.data.get_outfits().iter_outfits() {
|
||||||
|
let c = ct.get_outfit(*h);
|
||||||
|
if c.engine_flare_sprite.is_some() {
|
||||||
|
flare = c.engine_flare_sprite;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if flare.is_none() {
|
||||||
|
self.engine_anim = Vec::new();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let flare = flare.unwrap();
|
||||||
|
self.engine_anim = ct
|
||||||
|
.get_ship(self.data.get_content())
|
||||||
|
.engines
|
||||||
|
.iter()
|
||||||
|
.map(|e| (e.clone(), AnimAutomaton::new(ct, flare)))
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add one outfit to this ship
|
||||||
|
pub fn add_outfit(&mut self, ct: &Content, o: OutfitHandle) {
|
||||||
|
self.data.add_outfit(ct.get_outfit(o));
|
||||||
|
self.update_flares(ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add many outfits to this ship
|
||||||
|
pub fn add_outfits(&mut self, ct: &Content, outfits: impl IntoIterator<Item = OutfitHandle>) {
|
||||||
|
for o in outfits {
|
||||||
|
self.data.add_outfit(ct.get_outfit(o));
|
||||||
|
}
|
||||||
|
self.update_flares(ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Public immutable
|
||||||
impl PhysSimShip {
|
impl PhysSimShip {
|
||||||
/// Get this ship's control state
|
/// Get this ship's control state
|
||||||
pub fn get_controls(&self) -> &ShipControls {
|
pub fn get_controls(&self) -> &ShipControls {
|
||||||
&self.controls
|
&self.controls
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get this ship's engine animations
|
||||||
|
pub fn iter_engine_anim(&self) -> impl Iterator<Item = &(EnginePoint, AnimAutomaton)> {
|
||||||
|
self.engine_anim.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get this ship's animation state
|
||||||
|
pub fn get_anim_state(&self) -> AnimationState {
|
||||||
|
self.anim.get_texture_idx()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get this ship's game data struct
|
||||||
|
pub fn get_data(&self) -> &ShipData {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue