diff --git a/crates/galactica/src/main.rs b/crates/galactica/src/main.rs index 8ae3f17..e06880b 100644 --- a/crates/galactica/src/main.rs +++ b/crates/galactica/src/main.rs @@ -97,6 +97,11 @@ fn main() -> Result<()> { None } } + ShipState::UnLanding { .. } => { + let pos = + o.data.get_state().unlanding_position(&content).unwrap(); + Some(Point2 { x: pos.x, y: pos.y }) + } ShipState::Landing { .. } => { let pos = o.data.get_state().landing_position(&content).unwrap(); diff --git a/crates/render/src/gpustate/phys.rs b/crates/render/src/gpustate/phys.rs index e9ae430..90d2151 100644 --- a/crates/render/src/gpustate/phys.rs +++ b/crates/render/src/gpustate/phys.rs @@ -1,7 +1,7 @@ //! GPUState routines for drawing items in a systemsim use bytemuck; -use cgmath::{EuclideanSpace, InnerSpace, Point2, Point3, Vector2}; +use cgmath::{EuclideanSpace, InnerSpace, Point2, Point3, Rad, Vector2}; use galactica_system::{data::ShipState, phys::util}; use galactica_util::constants::OBJECT_SPRITE_INSTANCE_LIMIT; @@ -60,6 +60,14 @@ impl GPUState { ship_ang = from_angle + ((target_angle - from_angle) * 1f32.min(elapsed / 1.0)); ship_cnt = state.ct.get_ship(ship.data.get_content()); } + + ShipState::UnLanding { + to_angle, elapsed, .. + } => { + ship_pos = ship.data.get_state().unlanding_position(state.ct).unwrap(); + ship_ang = Rad(0.0) + ((to_angle - Rad(0.0)) * 1f32.min(elapsed / 1.0)); + ship_cnt = state.ct.get_ship(ship.data.get_content()); + } } // Position adjusted for parallax diff --git a/crates/render/src/ui/radar.rs b/crates/render/src/ui/radar.rs index 39a4ee6..a14ec63 100644 --- a/crates/render/src/ui/radar.rs +++ b/crates/render/src/ui/radar.rs @@ -41,7 +41,6 @@ impl Radar { match player_ship.data.get_state() { ShipState::Dead => {} - // TODO: radar follows while landing ShipState::Landing { .. } => { let pos = player_ship .data @@ -51,6 +50,15 @@ impl Radar { self.last_player_position = Point2 { x: pos.x, y: pos.y } } + ShipState::UnLanding { .. } => { + let pos = player_ship + .data + .get_state() + .unlanding_position(&input.ct) + .unwrap(); + self.last_player_position = Point2 { x: pos.x, y: pos.y } + } + ShipState::Landed { target } => { let landed_body = input.ct.get_system_object(*target); self.last_player_position = Point2 { @@ -150,7 +158,9 @@ impl Radar { } // TODO: different color for landing? - ShipState::Landing { .. } | ShipState::Collapsing { .. } => { + ShipState::UnLanding { .. } + | ShipState::Landing { .. } + | ShipState::Collapsing { .. } => { // TODO: configurable [0.2, 0.2, 0.2, 1.0] } diff --git a/crates/render/src/ui/status.rs b/crates/render/src/ui/status.rs index da47569..8934637 100644 --- a/crates/render/src/ui/status.rs +++ b/crates/render/src/ui/status.rs @@ -43,7 +43,8 @@ impl Status { max_shields = player_ship.data.get_outfits().get_shield_strength(); max_hull = input.ct.get_ship(player_ship.data.get_content()).hull; } - ShipState::Landing { .. } + ShipState::UnLanding { .. } + | ShipState::Landing { .. } | ShipState::Landed { .. } | ShipState::Collapsing { .. } | ShipState::Flying => { diff --git a/crates/system/src/data/ship/ship.rs b/crates/system/src/data/ship/ship.rs index 8ebcc37..61c2c8c 100644 --- a/crates/system/src/data/ship/ship.rs +++ b/crates/system/src/data/ship/ship.rs @@ -47,7 +47,26 @@ pub enum ShipState { /// The total amount of time, in seconds, we will spend landing total: f32, - /// The amount of time we've already spent playing the landing sequence + /// The amount of time we've already spent playing this landing sequence + elapsed: f32, + }, + + /// This ship is taking off from a planet + /// (playing the animation) + UnLanding { + /// The point, in world coordinates, to which we're going + to_position: Point2, + + /// The angle we'll be at when we arrive + to_angle: Rad, + + /// The planet we're taking off from + from: SystemObjectHandle, + + /// The total amount of time, in seconds, we will spend taking off + total: f32, + + /// The amount of time we've already spent playing this unlanding sequence elapsed: f32, }, } @@ -96,6 +115,8 @@ impl ShipState { // TODO: atmosphere burn // TODO: land at random point // TODO: don't jump camera + // TODO: time by distance + // TODO: keep momentum let pos = from_position + (diff * (elapsed / total)); @@ -108,6 +129,48 @@ impl ShipState { _ => None, } } + + /// Compute position of this ship's sprite during its unlanding sequence + pub fn unlanding_position(&self, ct: &Content) -> Option> { + match self { + Self::UnLanding { + to_position, + from, + total, + elapsed, + .. + } => Some({ + let from = ct.get_system_object(*from); + + let diff = to_position + - Point2 { + x: from.pos.x, + y: from.pos.y, + }; + //let diff = diff - diff.normalize() * (target.size / 2.0) * 0.8; + + // TODO: improve animation + // TODO: fade + // TODO: atmosphere burn + // TODO: land at random point + // TODO: don't jump camera + // TODO: time by distance + // TODO: keep momentum + + let pos = Point2 { + x: from.pos.x, + y: from.pos.y, + } + (diff * (elapsed / total)); + + Point3 { + x: pos.x, + y: pos.y, + z: from.pos.z + ((1.0 - from.pos.z) * (elapsed / total)), + } + }), + _ => None, + } + } } /// Represents all attributes of a single ship @@ -189,10 +252,16 @@ impl ShipData { } /// Take off from `target` - pub fn unland(&mut self) { + pub fn unland(&mut self, to_position: Point2) { match self.state { - ShipState::Landed { .. } => { - self.state = ShipState::Flying; + ShipState::Landed { target } => { + self.state = ShipState::UnLanding { + to_position, + to_angle: Rad(1.0), + from: target, + total: 5.0, + elapsed: 0.0, + }; } _ => { unreachable!("Called `unland` on a ship that isn't landed!") @@ -276,6 +345,17 @@ impl ShipData { } } + ShipState::UnLanding { + ref mut elapsed, + total, + .. + } => { + *elapsed += t; + if *elapsed >= total { + self.state = ShipState::Flying; + } + } + ShipState::Landed { .. } => { // Cooldown guns for (_, c) in &mut self.gun_cooldowns { diff --git a/crates/system/src/phys/objects/ship.rs b/crates/system/src/phys/objects/ship.rs index bd06e04..c4b7dd9 100644 --- a/crates/system/src/phys/objects/ship.rs +++ b/crates/system/src/phys/objects/ship.rs @@ -99,7 +99,10 @@ impl PhysSimShip { ShipState::Flying => { return self.step_live(res, rigid_body, collider); } - ShipState::Dead | ShipState::Landing { .. } | ShipState::Landed { .. } => {} + ShipState::UnLanding { .. } + | ShipState::Dead + | ShipState::Landing { .. } + | ShipState::Landed { .. } => {} } } diff --git a/crates/system/src/phys/systemsim.rs b/crates/system/src/phys/systemsim.rs index 6b50b99..51f6d35 100644 --- a/crates/system/src/phys/systemsim.rs +++ b/crates/system/src/phys/systemsim.rs @@ -77,10 +77,11 @@ impl<'a> PhysSim { -util::rigidbody_rotation(r).angle(Vector2 { x: 0.0, y: 1.0 }), ); - self.rigid_body_set - .get_mut(ship.rigid_body) - .unwrap() - .set_enabled(false); + let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap(); + r.set_enabled(false); + r.set_angvel(0.0, false); + r.set_linvel(nalgebra::Vector2::new(0.0, 0.0), false); + self.collider_set .get_mut(ship.collider) .unwrap() @@ -91,16 +92,24 @@ impl<'a> PhysSim { let ship = self.ships.get_mut(&collider).unwrap(); let obj = ship.data.get_state().landed_on().unwrap(); let obj = ct.get_system_object(obj); - ship.data.unland(); - self.rigid_body_set - .get_mut(ship.rigid_body) - .unwrap() - .set_position(point![obj.pos.x, obj.pos.y].into(), true); - self.rigid_body_set - .get_mut(ship.rigid_body) - .unwrap() - .set_enabled(true); + let target_pos = Point2 { + x: obj.pos.x + 100.0, + y: obj.pos.y + 100.0, + }; + + ship.data.unland(target_pos); + + let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap(); + r.set_enabled(true); + + r.set_position( + nalgebra::Vector2::new(target_pos.x, target_pos.y).into(), + true, + ); + + r.set_rotation(nalgebra::Rotation2::new(1.0).into(), false); + self.collider_set .get_mut(ship.collider) .unwrap() @@ -306,7 +315,8 @@ impl PhysSim { to_remove.push(collider); } - ShipState::Landing { .. } + ShipState::UnLanding { .. } + | ShipState::Landing { .. } | ShipState::Landed { .. } | ShipState::Collapsing { .. } => { let ship = self.ships.get_mut(&collider).unwrap();