Compare commits

...

7 Commits

Author SHA1 Message Date
Mark 1493a97f01
Updated TODO 2024-01-14 11:14:09 -08:00
Mark c62fa0b4d5
Tweaked test ship positioning 2024-01-14 11:11:38 -08:00
Mark e850a13f71
Improved ship unlanding 2024-01-14 11:11:29 -08:00
Mark bbf47e29d5
Dependencies 2024-01-14 11:10:13 -08:00
Mark 7e41383ea9
Fixed radar arrow 2024-01-14 11:10:04 -08:00
Mark 129b134114
Added util function 2024-01-14 11:09:51 -08:00
Mark 0289031c88
Fixed sprite rotation 2024-01-14 10:38:07 -08:00
15 changed files with 166 additions and 143 deletions

3
Cargo.lock generated
View File

@ -710,6 +710,9 @@ dependencies = [
[[package]] [[package]]
name = "galactica-util" name = "galactica-util"
version = "0.0.0" version = "0.0.0"
dependencies = [
"nalgebra",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"

18
TODO.md
View File

@ -2,7 +2,10 @@
- Fix angles (point, land) - Fix angles (point, land)
- Land from farther away - Land from farther away
- Take off - Take off
- Prevent collisions on unlanding
- UI: text arranger - UI: text arranger
- loading screen, menus
- Indicators (planet names, enemy ship stats)
- Start documenting - Start documenting
- Check for handle leaks - Check for handle leaks
- Don't allocate each frame - Don't allocate each frame
@ -55,10 +58,6 @@
- Debris (ship death, destructible, physics) - Debris (ship death, destructible, physics)
- Orbiting debris (asteroids) - Orbiting debris (asteroids)
- Collectibles (flotsam) - Collectibles (flotsam)
- UI
- loading screen, menus
- Indicators (planet names, enemy ship stats)
- Landable planets
- Back arrow: reverse thruster or reverse ship - Back arrow: reverse thruster or reverse ship
- Multiplayer? (how does that fit into gameplay?) - Multiplayer? (how does that fit into gameplay?)
- On-screen text - On-screen text
@ -66,7 +65,8 @@
- Save games - Save games
- Date system -> planet position - Date system -> planet position
- AI fleets - AI fleets
- More ship behaviors - More ship behaviors, improved ai
- Collision avoidance
- Jump between systems - Jump between systems
- Government color, ship tint - Government color, ship tint
- Different kinds of ship behaviors: - Different kinds of ship behaviors:
@ -75,8 +75,7 @@
- where to go - where to go
- etc, extra flags - etc, extra flags
- Advanced particle physics (must move to cpu. Maybe both?) - Advanced particle physics (must move to cpu. Maybe both?)
- Background simulation (two modes: physics-what's visible, data-everything else) - Background simulation (two modes)
## Faction interaction ## Faction interaction
- Targeting overrides hitscan rules (only for player) - Targeting overrides hitscan rules (only for player)
@ -99,11 +98,14 @@
- Random animation delay/fps? - Random animation delay/fps?
- Better WGSL preprocessor - Better WGSL preprocessor
- Depth buffer (z-axis when landing!) - Depth buffer (z-axis when landing!)
- Compute shader for particles
- Better performance for projectiles
## Content ## Content
- Angled engines - Angled engines
- Angled guns - Angled guns
- Turn engine flares - Turn engine flares
- Turn engine physics?
- Reverse engine & flares - Reverse engine & flares
- Better ship colliders (need a tool or an algorithm) - Better ship colliders (need a tool or an algorithm)
- Turrets - Turrets
@ -159,7 +161,7 @@
- How big should sprite resolutions be? How about frame rate? - How big should sprite resolutions be? How about frame rate?
- Naming: atlas, sprite, image, frame, texture - Naming: atlas, sprite, image, frame, texture
- Outfits may not change unless you've landed. They might not change ever for CC ships! - Outfits may not change unless you've landed. They might not change ever for CC ships!
- All angle adjustments happen in content - All angle adjustments happen in content & shaders
## Ideas ## Ideas

View File

@ -66,7 +66,7 @@ impl<'a> Game {
ShipHandle { index: 0 }, ShipHandle { index: 0 },
FactionHandle { index: 1 }, FactionHandle { index: 1 },
ShipPersonality::Point, ShipPersonality::Point,
Point2::new(400.0, 0.0), Point2::new(1000.0, 0.0),
); );
let s = systemsim.get_ship_mut(&a).unwrap(); let s = systemsim.get_ship_mut(&a).unwrap();
@ -79,7 +79,7 @@ impl<'a> Game {
ShipHandle { index: 0 }, ShipHandle { index: 0 },
FactionHandle { index: 0 }, FactionHandle { index: 0 },
ShipPersonality::Dummy, ShipPersonality::Dummy,
Point2::new(0.0, 4000.0), Point2::new(200.0, 2000.0),
); );
let s = systemsim.get_ship_mut(&a).unwrap(); let s = systemsim.get_ship_mut(&a).unwrap();

View File

@ -86,6 +86,7 @@ fn main() -> Result<()> {
if let Some(o) = o { if let Some(o) = o {
match o.data.get_state() { match o.data.get_state() {
ShipState::Landing { .. } ShipState::Landing { .. }
| ShipState::UnLanding { .. }
| ShipState::Collapsing { .. } | ShipState::Collapsing { .. }
| ShipState::Flying { .. } => { | ShipState::Flying { .. } => {
let r = let r =
@ -96,11 +97,6 @@ fn main() -> Result<()> {
None None
} }
} }
ShipState::UnLanding { .. } => {
let pos =
o.data.get_state().unlanding_position(&content).unwrap();
Some(Vector2::new(pos.x, pos.y))
}
ShipState::Landed { target } => { ShipState::Landed { target } => {
let b = content.get_system_object(*target); let b = content.get_system_object(*target);

View File

@ -48,10 +48,10 @@ fn vertex_main(
vertex.position.y * scale vertex.position.y * scale
); );
// Apply rotation // Apply rotation (and adjust sprite angle, since sprites point north)
pos = mat2x2( pos = mat2x2(
vec2(cos(instance.angle), sin(instance.angle)), vec2(cos(instance.angle - 1.5708), sin(instance.angle - 1.5708)),
vec2(-sin(instance.angle), cos(instance.angle)) vec2(-sin(instance.angle - 1.5708), cos(instance.angle - 1.5708))
) * pos; ) * pos;
// Correct for screen aspect, preserving height // Correct for screen aspect, preserving height

View File

@ -36,7 +36,7 @@ impl GPUState {
ship_cnt = state.ct.get_ship(ship.data.get_content()); ship_cnt = state.ct.get_ship(ship.data.get_content());
} }
ShipState::Landing { current_z, .. } => { ShipState::UnLanding { current_z, .. } | ShipState::Landing { current_z, .. } => {
let r = state.systemsim.get_rigid_body(ship.rigid_body).unwrap(); let r = state.systemsim.get_rigid_body(ship.rigid_body).unwrap();
let pos = *r.translation(); let pos = *r.translation();
ship_pos = Point3::new(pos.x, pos.y, *current_z); ship_pos = Point3::new(pos.x, pos.y, *current_z);
@ -44,13 +44,6 @@ impl GPUState {
ship_ang = ship_rot.angle(); ship_ang = ship_rot.angle();
ship_cnt = state.ct.get_ship(ship.data.get_content()); ship_cnt = state.ct.get_ship(ship.data.get_content());
} }
ShipState::UnLanding { .. } => {
ship_pos = ship.data.get_state().unlanding_position(state.ct).unwrap();
//ship_ang = 0.0 + ((to_angle - 0.0) * 1f32.min(elapsed / 1.0));
ship_ang = 0.0;
ship_cnt = state.ct.get_ship(ship.data.get_content());
}
} }
// Position adjusted for parallax // Position adjusted for parallax
@ -112,8 +105,9 @@ impl GPUState {
let flare = ship.data.get_outfits().get_flare_sprite(state.ct); let flare = ship.data.get_outfits().get_flare_sprite(state.ct);
if { if {
let is_flying = match ship.data.get_state() { let is_flying = match ship.data.get_state() {
ShipState::Flying { .. } => true, ShipState::Flying { .. }
ShipState::Landing { .. } => true, | ShipState::UnLanding { .. }
| ShipState::Landing { .. } => true,
_ => false, _ => false,
}; };
ship.get_controls().thrust && flare.is_some() && is_flying ship.get_controls().thrust && flare.is_some() && is_flying

View File

@ -1,6 +1,6 @@
use galactica_system::data::ShipState; use galactica_system::data::ShipState;
use galactica_util::{constants::UI_SPRITE_INSTANCE_LIMIT, to_radians}; use galactica_util::{clockwise_angle, constants::UI_SPRITE_INSTANCE_LIMIT, to_radians};
use nalgebra::{Point2, Vector2}; use nalgebra::{Point2, Rotation2, Vector2};
use crate::{ use crate::{
datastructs::RenderState, datastructs::RenderState,
@ -41,21 +41,15 @@ impl Radar {
match player_ship.data.get_state() { match player_ship.data.get_state() {
ShipState::Dead => {} ShipState::Dead => {}
ShipState::UnLanding { .. } => {
let pos = player_ship
.data
.get_state()
.unlanding_position(&input.ct)
.unwrap();
self.last_player_position = Point2::new(pos.x, pos.y)
}
ShipState::Landed { target } => { ShipState::Landed { target } => {
let landed_body = input.ct.get_system_object(*target); let landed_body = input.ct.get_system_object(*target);
self.last_player_position = Point2::new(landed_body.pos.x, landed_body.pos.y); self.last_player_position = Point2::new(landed_body.pos.x, landed_body.pos.y);
} }
ShipState::Landing { .. } | ShipState::Flying { .. } | ShipState::Collapsing { .. } => { ShipState::UnLanding { .. }
| ShipState::Landing { .. }
| ShipState::Flying { .. }
| ShipState::Collapsing { .. } => {
let player_body = input let player_body = input
.systemsim .systemsim
.get_rigid_body(player_ship.rigid_body) .get_rigid_body(player_ship.rigid_body)
@ -227,7 +221,7 @@ impl Radar {
(radar_size / -2.0 - 10.0) + d.y, (radar_size / -2.0 - 10.0) + d.y,
) )
.into(), .into(),
angle: 0.0, angle: to_radians(90.0),
size, size,
color, color,
sprite_index: sprite.get_index(), sprite_index: sprite.get_index(),
@ -245,7 +239,7 @@ impl Radar {
(radar_size / -2.0 - 10.0) - d.y, (radar_size / -2.0 - 10.0) - d.y,
) )
.into(), .into(),
angle: to_radians(90.0), angle: to_radians(180.0),
size, size,
color, color,
sprite_index: sprite.get_index(), sprite_index: sprite.get_index(),
@ -263,7 +257,7 @@ impl Radar {
(radar_size / -2.0 - 10.0) - d.y, (radar_size / -2.0 - 10.0) - d.y,
) )
.into(), .into(),
angle: to_radians(180.0), angle: to_radians(270.0),
size, size,
color, color,
sprite_index: sprite.get_index(), sprite_index: sprite.get_index(),
@ -281,7 +275,7 @@ impl Radar {
(radar_size / -2.0 - 10.0) + d.y, (radar_size / -2.0 - 10.0) + d.y,
) )
.into(), .into(),
angle: to_radians(270.0), angle: to_radians(0.0),
size, size,
color, color,
sprite_index: sprite.get_index(), sprite_index: sprite.get_index(),
@ -294,11 +288,9 @@ impl Radar {
let q = Point2::new(0.0, 0.0) - self.last_player_position; let q = Point2::new(0.0, 0.0) - self.last_player_position;
let m = q.magnitude(); let m = q.magnitude();
if m > 200.0 { if m > 200.0 {
let player_angle = q.angle(&Vector2::new(0.0, 1.0)); let angle = clockwise_angle(&Vector2::new(1.0, 0.0), &q);
let position = Point2::new(10.0 + (radar_size / 2.0), -10.0 - (radar_size / 2.0))
let position: Point2<f32> = + Rotation2::new(angle) * Vector2::new(0.915 * (radar_size / 2.0), 0.0);
Point2::new(radar_size / 2.0 + 10.0, radar_size / -2.0 - 10.0)
+ ((q.normalize() * 0.865) * (radar_size / 2.0));
if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT { if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT {
// TODO: no panic, handle this better. // TODO: no panic, handle this better.
@ -311,7 +303,7 @@ impl Radar {
bytemuck::cast_slice(&[UiInstance { bytemuck::cast_slice(&[UiInstance {
anchor: PositionAnchor::NwC.to_int(), anchor: PositionAnchor::NwC.to_int(),
position: position.into(), position: position.into(),
angle: -player_angle, angle,
size: 10.0, size: 10.0,
color: [1.0, 1.0, 1.0, 1f32.min((m - 200.0) / 400.0)], color: [1.0, 1.0, 1.0, 1f32.min((m - 200.0) / 400.0)],
sprite_index: arrow_sprite.get_index(), sprite_index: arrow_sprite.get_index(),

View File

@ -1,5 +1,5 @@
use galactica_content::{Content, FactionHandle, GunPoint, Outfit, ShipHandle, SystemObjectHandle}; use galactica_content::{Content, FactionHandle, GunPoint, Outfit, ShipHandle, SystemObjectHandle};
use nalgebra::{Point2, Point3}; use nalgebra::Isometry2;
use rand::{rngs::ThreadRng, Rng}; use rand::{rngs::ThreadRng, Rng};
use rapier2d::math::Isometry; use rapier2d::math::Isometry;
use std::{collections::HashMap, time::Instant}; use std::{collections::HashMap, time::Instant};
@ -65,17 +65,14 @@ pub enum ShipState {
/// This ship is taking off from a planet /// This ship is taking off from a planet
/// (playing the animation) /// (playing the animation)
UnLanding { UnLanding {
/// The point, in world coordinates, to which we're going /// The point to which we're going, in world coordinates
to_position: Isometry<f32>, to_position: Isometry<f32>,
/// The planet we're taking off from /// The planet we're taking off from
from: SystemObjectHandle, from: SystemObjectHandle,
/// The total amount of time, in seconds, we will spend taking off /// Our current z-coordinate
total: f32, current_z: f32,
/// The amount of time we've already spent playing this unlanding sequence
elapsed: f32,
}, },
} }
@ -99,42 +96,6 @@ impl ShipState {
_ => None, _ => None,
} }
} }
/// Compute position of this ship's sprite during its unlanding sequence
pub fn unlanding_position(&self, ct: &Content) -> Option<Point3<f32>> {
match self {
Self::UnLanding {
to_position,
from,
total,
elapsed,
..
} => Some({
let from = ct.get_system_object(*from);
let t = Point2::new(to_position.translation.x, to_position.translation.y);
let diff = t - Point2::new(from.pos.x, 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::new(from.pos.x, from.pos.y) + (diff * (elapsed / total));
Point3::new(
pos.x,
pos.y,
from.pos.z + ((1.0 - from.pos.z) * (elapsed / total)),
)
}),
_ => None,
}
}
} }
/// Represents all attributes of a single ship /// Represents all attributes of a single ship
@ -245,28 +206,57 @@ impl ShipData {
self.state = ShipState::Landed { target }; self.state = ShipState::Landed { target };
} }
_ => { _ => {
unreachable!("Called `finish_land_on` on a ship that isn't flying!") unreachable!("Called `finish_land_on` on a ship that isn't landing!")
} }
}; };
} }
/// Take off from `target` /// Land this ship on `target`
pub fn unland(&mut self, to_position: Isometry<f32>) { /// This does NO checks (speed, range, etc).
/// That is the simulation's responsiblity.
///
/// Will panic if we're not flying.
pub fn start_unland_to(&mut self, ct: &Content, to_position: Isometry2<f32>) {
match self.state { match self.state {
ShipState::Landed { target } => { ShipState::Landed { target } => {
let obj = ct.get_system_object(target);
self.state = ShipState::UnLanding { self.state = ShipState::UnLanding {
to_position, to_position,
from: target, from: target,
total: 2.0, current_z: obj.pos.z,
elapsed: 0.0,
}; };
} }
_ => { _ => {
unreachable!("Called `unland` on a ship that isn't landed!") unreachable!("Called `start_unland_to` on a ship that isn't landed!")
} }
}; };
} }
/// When unlanding, update z position.
/// Will panic if we're not unlanding
pub fn set_unlanding_z(&mut self, z: f32) {
match &mut self.state {
ShipState::UnLanding {
ref mut current_z, ..
} => *current_z = z,
_ => unreachable!("Called `set_unlanding_z` on a ship that isn't unlanding!"),
}
}
/// Finish unlanding sequence
/// Will panic if we're not unlanding
pub fn finish_unland_to(&mut self) {
match self.state {
ShipState::UnLanding { .. } => {
self.state = ShipState::Flying {
autopilot: ShipAutoPilot::None,
}
}
_ => {
unreachable!("Called `finish_unland_to` on a ship that isn't unlanding!")
}
};
}
/// Add an outfit to this ship /// Add an outfit to this ship
pub fn add_outfit(&mut self, o: &Outfit) -> super::OutfitAddResult { pub fn add_outfit(&mut self, o: &Outfit) -> super::OutfitAddResult {
let r = self.outfits.add(o); let r = self.outfits.add(o);
@ -331,20 +321,7 @@ impl ShipData {
/// Update this ship's state by `t` seconds /// Update this ship's state by `t` seconds
pub(crate) fn step(&mut self, t: f32) { pub(crate) fn step(&mut self, t: f32) {
match self.state { match self.state {
ShipState::Landing { .. } => {} ShipState::UnLanding { .. } | ShipState::Landing { .. } => {}
ShipState::UnLanding {
ref mut elapsed,
total,
..
} => {
*elapsed += t;
if *elapsed >= total {
self.state = ShipState::Flying {
autopilot: ShipAutoPilot::None,
};
}
}
ShipState::Landed { .. } => { ShipState::Landed { .. } => {
// Cooldown guns // Cooldown guns

View File

@ -1,7 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use galactica_content::SystemObjectHandle; use galactica_util::{clockwise_angle, to_radians};
use galactica_util::to_radians;
use nalgebra::Vector2; use nalgebra::Vector2;
use rapier2d::{dynamics::RigidBodySet, geometry::ColliderHandle}; use rapier2d::{dynamics::RigidBodySet, geometry::ColliderHandle};
@ -16,23 +15,21 @@ use crate::phys::{
/// Land this ship on the given object /// Land this ship on the given object
pub fn auto_landing( pub fn auto_landing(
res: &PhysStepResources, _res: &PhysStepResources,
rigid_bodies: &RigidBodySet, rigid_bodies: &RigidBodySet,
ships: &HashMap<ColliderHandle, PhysSimShip>, ships: &HashMap<ColliderHandle, PhysSimShip>,
this_ship: ColliderHandle, this_ship: ColliderHandle,
target_handle: SystemObjectHandle, target_pos: Vector2<f32>,
) -> Option<ShipControls> { ) -> Option<ShipControls> {
let rigid_body_handle = ships.get(&this_ship).unwrap().rigid_body; let rigid_body_handle = ships.get(&this_ship).unwrap().rigid_body;
let rigid_body = rigid_bodies.get(rigid_body_handle).unwrap(); let rigid_body = rigid_bodies.get(rigid_body_handle).unwrap();
let target_obj = res.ct.get_system_object(target_handle);
let target_pos = Vector2::new(target_obj.pos.x, target_obj.pos.y);
let my_pos = *rigid_body.translation(); let my_pos = *rigid_body.translation();
let my_rot = rigid_body.rotation() * Vector2::new(1.0, 0.0); let my_rot = rigid_body.rotation() * Vector2::new(1.0, 0.0);
let my_vel = rigid_body.linvel(); let my_vel = rigid_body.linvel();
let my_angvel = rigid_body.angvel(); let my_angvel = rigid_body.angvel();
let v_t = target_pos - my_pos; // Vector to target let v_t = target_pos - my_pos; // Vector to target
let v_d = v_t - my_vel; // Desired thrust vector let v_d = v_t - my_vel; // Desired thrust vector
let angle_delta = (my_rot.x * v_d.y - v_d.x * my_rot.y).atan2(my_rot.dot(&v_d)); let angle_delta = clockwise_angle(&my_rot, &v_d);
let mut controls = ShipControls::new(); let mut controls = ShipControls::new();
if angle_delta < 0.0 && my_angvel > -0.3 { if angle_delta < 0.0 && my_angvel > -0.3 {

View File

@ -100,11 +100,11 @@ impl PhysSimShip {
self.step_effects(res, rigid_body, collider); self.step_effects(res, rigid_body, collider);
} }
ShipState::Landing { .. } => { ShipState::UnLanding { .. } | ShipState::Landing { .. } => {
self.step_physics(res, rigid_body, collider); self.step_physics(res, rigid_body, collider);
} }
ShipState::UnLanding { .. } | ShipState::Dead | ShipState::Landed { .. } => {} ShipState::Dead | ShipState::Landed { .. } => {}
} }
} }

View File

@ -138,7 +138,7 @@ impl PhysSim {
ShipState::Landed { .. } => { ShipState::Landed { .. } => {
if player.input.pressed_land() { if player.input.pressed_land() {
self.unland_ship(ct, player.ship.unwrap()); self.start_unland_ship(ct, player.ship.unwrap());
} }
} }
}; };

View File

@ -9,7 +9,11 @@ use rapier2d::{
use crate::{ use crate::{
data::{ShipAutoPilot, ShipState}, data::{ShipAutoPilot, ShipState},
phys::{controller::autopilot, objects::PhysProjectile, ParticleBuilder, PhysStepResources}, phys::{
controller::autopilot,
objects::{PhysProjectile, ShipControls},
ParticleBuilder, PhysStepResources,
},
}; };
use super::PhysSim; use super::PhysSim;
@ -36,9 +40,7 @@ impl PhysSim {
to_remove.push(collider); to_remove.push(collider);
} }
ShipState::UnLanding { .. } ShipState::Landed { .. } | ShipState::Collapsing { .. } => {
| ShipState::Landed { .. }
| ShipState::Collapsing { .. } => {
let ship = self.ships.get_mut(&collider).unwrap(); let ship = self.ships.get_mut(&collider).unwrap();
ship.step( ship.step(
res, res,
@ -47,6 +49,48 @@ impl PhysSim {
); );
} }
ShipState::UnLanding {
to_position,
current_z,
from,
} => {
let from_obj = res.ct.get_system_object(*from);
let controls = autopilot::auto_landing(
&res,
&self.rigid_body_set,
&self.ships,
ship.collider,
Vector2::new(to_position.translation.x, to_position.translation.y),
);
let r = &mut self.rigid_body_set[ship.rigid_body];
let max_d = (Vector2::new(from_obj.pos.x, from_obj.pos.y)
- Vector2::new(to_position.translation.x, to_position.translation.y))
.magnitude();
let now_d = (r.translation()
- Vector2::new(to_position.translation.x, to_position.translation.y))
.magnitude();
let f = now_d / max_d;
let current_z = *current_z;
let ship = self.ships.get_mut(&collider).unwrap();
let zdist = 1.0 - from_obj.pos.z;
if current_z <= 1.0 {
self.finish_unland_ship(collider);
} else if current_z <= 1.5 {
ship.data
.set_unlanding_z(1f32.max(current_z - (0.5 * res.t) / 0.5));
ship.controls = ShipControls::new();
} else {
ship.data.set_unlanding_z(1.0 - zdist * f);
if let Some(controls) = controls {
ship.controls = controls;
}
ship.step(res, r, &mut self.collider_set[ship.collider])
};
}
ShipState::Landing { target, current_z } => { ShipState::Landing { target, current_z } => {
let target_obj = res.ct.get_system_object(*target); let target_obj = res.ct.get_system_object(*target);
let controls = autopilot::auto_landing( let controls = autopilot::auto_landing(
@ -54,17 +98,16 @@ impl PhysSim {
&self.rigid_body_set, &self.rigid_body_set,
&self.ships, &self.ships,
ship.collider, ship.collider,
*target, Vector2::new(target_obj.pos.x, target_obj.pos.y),
); );
let current_z = *current_z; let current_z = *current_z;
let target = *target;
let ship = self.ships.get_mut(&collider).unwrap(); let ship = self.ships.get_mut(&collider).unwrap();
let r = &mut self.rigid_body_set[ship.rigid_body]; let r = &mut self.rigid_body_set[ship.rigid_body];
let zdist = target_obj.pos.z - 1.0; let zdist = target_obj.pos.z - 1.0;
if current_z >= target_obj.pos.z { if current_z >= target_obj.pos.z {
self.finish_land_ship(res.ct, collider, target); self.finish_land_ship(collider);
} else { } else {
ship.data.set_landing_z(current_z + zdist * res.t / 2.0); ship.data.set_landing_z(current_z + zdist * res.t / 2.0);
@ -82,12 +125,13 @@ impl PhysSim {
ShipAutoPilot::Landing { ShipAutoPilot::Landing {
target: target_handle, target: target_handle,
} => { } => {
let target_obj = res.ct.get_system_object(*target_handle);
let controls = autopilot::auto_landing( let controls = autopilot::auto_landing(
&res, &res,
&self.rigid_body_set, &self.rigid_body_set,
&self.ships, &self.ships,
ship.collider, ship.collider,
*target_handle, Vector2::new(target_obj.pos.x, target_obj.pos.y),
); );
let landed = self.try_land_ship(res.ct, collider, *target_handle); let landed = self.try_land_ship(res.ct, collider, *target_handle);

View File

@ -1,5 +1,6 @@
use galactica_content::{Content, Relationship, SystemObjectHandle}; use galactica_content::{Content, Relationship, SystemObjectHandle};
use nalgebra::{Isometry2, Point2, Vector2}; use nalgebra::{Isometry2, Point2, Rotation2, Vector2};
use rand::Rng;
use rapier2d::{ use rapier2d::{
dynamics::RigidBody, dynamics::RigidBody,
geometry::{ColliderHandle, Group, InteractionGroups}, geometry::{ColliderHandle, Group, InteractionGroups},
@ -70,7 +71,6 @@ impl PhysSim {
} }
let collider = self.collider_set.get_mut(collider).unwrap(); let collider = self.collider_set.get_mut(collider).unwrap();
println!("{:?}", collider.collision_groups());
collider.set_collision_groups(InteractionGroups::new(Group::GROUP_1, Group::empty())); collider.set_collision_groups(InteractionGroups::new(Group::GROUP_1, Group::empty()));
ship.data.start_land_on(target_handle); ship.data.start_land_on(target_handle);
return true; return true;
@ -78,12 +78,7 @@ impl PhysSim {
/// Finish landing this ship on a planet. /// Finish landing this ship on a planet.
/// Called after the landing animation finishes. /// Called after the landing animation finishes.
pub(super) fn finish_land_ship( pub(super) fn finish_land_ship(&mut self, collider: ColliderHandle) {
&mut self,
_ct: &Content,
collider: ColliderHandle,
_target: SystemObjectHandle,
) {
let ship = self.ships.get_mut(&collider).unwrap(); let ship = self.ships.get_mut(&collider).unwrap();
ship.data.finish_land_on(); ship.data.finish_land_on();
let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap(); let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap();
@ -92,19 +87,31 @@ impl PhysSim {
r.set_linvel(nalgebra::Vector2::new(0.0, 0.0), false); r.set_linvel(nalgebra::Vector2::new(0.0, 0.0), false);
} }
pub(super) fn unland_ship(&mut self, ct: &Content, collider: ColliderHandle) { pub(super) fn start_unland_ship(&mut self, ct: &Content, collider: ColliderHandle) {
let ship = self.ships.get_mut(&collider).unwrap(); let ship = self.ships.get_mut(&collider).unwrap();
let obj = ship.data.get_state().landed_on().unwrap(); let obj = ship.data.get_state().landed_on().unwrap();
let obj = ct.get_system_object(obj); let obj = ct.get_system_object(obj);
let target_pos = Isometry2::new(Vector2::new(obj.pos.x + 100.0, obj.pos.y + 100.0), 1.0); let mut rng = rand::thread_rng();
let radius = rng.gen_range(500.0..=1500.0);
let angle = rng.gen_range(0.0..std::f32::consts::TAU);
let target_offset = Rotation2::new(angle) * Vector2::new(radius, 0.0);
let target_trans = Vector2::new(obj.pos.x, obj.pos.y) + target_offset;
let target_pos = Isometry2::new(target_trans, angle);
ship.data.unland(target_pos); ship.data.start_unland_to(ct, target_pos);
let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap(); let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap();
r.set_enabled(true); r.set_enabled(true);
r.set_position(target_pos, true); r.set_position(
Isometry2::new(Vector2::new(obj.pos.x, obj.pos.y), angle),
true,
);
}
pub(super) fn finish_unland_ship(&mut self, collider: ColliderHandle) {
let ship = self.ships.get_mut(&collider).unwrap();
ship.data.finish_unland_to();
self.collider_set self.collider_set
.get_mut(ship.collider) .get_mut(ship.collider)
.unwrap() .unwrap()

View File

@ -15,3 +15,6 @@ readme = { workspace = true }
[lints] [lints]
workspace = true workspace = true
[dependencies]
nalgebra = { workspace = true }

View File

@ -2,6 +2,8 @@
//! Various utilities //! Various utilities
use nalgebra::Vector2;
pub mod constants; pub mod constants;
pub mod timing; pub mod timing;
@ -9,3 +11,9 @@ pub mod timing;
pub fn to_radians(degrees: f32) -> f32 { pub fn to_radians(degrees: f32) -> f32 {
return (degrees / 360.0) * std::f32::consts::TAU; return (degrees / 360.0) * std::f32::consts::TAU;
} }
/// Compute the clockwise angle between two vectors
/// Returns a value in [0, 2pi]
pub fn clockwise_angle(a: &Vector2<f32>, b: &Vector2<f32>) -> f32 {
(a.x * b.y - b.x * a.y).atan2(a.dot(&b))
}