213 lines
5.9 KiB
Rust
213 lines
5.9 KiB
Rust
use galactica_content::{Content, Relationship, SystemObjectHandle};
|
|
use nalgebra::{Isometry2, Point2, Rotation2, Vector2};
|
|
use rand::Rng;
|
|
use rapier2d::{
|
|
dynamics::RigidBody,
|
|
geometry::{ColliderHandle, Group, InteractionGroups},
|
|
};
|
|
|
|
use crate::{
|
|
data::ShipState,
|
|
phys::{objects::PhysProjectile, ParticleBuilder, PhysStepResources},
|
|
};
|
|
|
|
use super::PhysSim;
|
|
|
|
// Private methods
|
|
impl PhysSim {
|
|
pub(super) fn remove_projectile(
|
|
&mut self,
|
|
res: &mut PhysStepResources,
|
|
c: ColliderHandle,
|
|
) -> Option<(RigidBody, PhysProjectile)> {
|
|
let p = match self.projectiles.remove(&c) {
|
|
Some(p) => p,
|
|
None => return None,
|
|
};
|
|
let r = self
|
|
.rigid_body_set
|
|
.remove(
|
|
p.rigid_body,
|
|
&mut res.wrapper.im,
|
|
&mut self.collider_set,
|
|
&mut res.wrapper.ij,
|
|
&mut res.wrapper.mj,
|
|
true,
|
|
)
|
|
.unwrap();
|
|
|
|
return Some((r, p));
|
|
}
|
|
|
|
/// Try to land the given ship on the given planet.
|
|
/// State changes on success, and nothing happens on failure.
|
|
/// returns `true` if landing was successful.
|
|
pub(super) fn try_land_ship(
|
|
&mut self,
|
|
ct: &Content,
|
|
collider: ColliderHandle,
|
|
target_handle: SystemObjectHandle,
|
|
) -> bool {
|
|
let ship = self.ships.get_mut(&collider).unwrap();
|
|
let r = self.rigid_body_set.get(ship.rigid_body).unwrap();
|
|
|
|
let target = ct.get_system_object(target_handle);
|
|
let t_pos = Vector2::new(target.pos.x, target.pos.y);
|
|
let s_pos = Vector2::new(r.position().translation.x, r.position().translation.y);
|
|
|
|
// TODO: deactivate collider when landing.
|
|
// Can't just set_active(false), since we still need that collider's mass.
|
|
|
|
// We're in land range...
|
|
if (t_pos - s_pos).magnitude() > target.size / 2.0 {
|
|
return false;
|
|
}
|
|
|
|
// And we'll stay in land range long enough.
|
|
if (t_pos - (s_pos + r.velocity_at_point(r.center_of_mass()) * 2.0)).magnitude()
|
|
> target.size / 2.0
|
|
{
|
|
return false;
|
|
}
|
|
|
|
let collider = self.collider_set.get_mut(collider).unwrap();
|
|
collider.set_collision_groups(InteractionGroups::new(Group::GROUP_1, Group::empty()));
|
|
ship.data.start_land_on(target_handle);
|
|
return true;
|
|
}
|
|
|
|
/// Finish landing this ship on a planet.
|
|
/// Called after the landing animation finishes.
|
|
pub(super) fn finish_land_ship(&mut self, collider: ColliderHandle) {
|
|
let ship = self.ships.get_mut(&collider).unwrap();
|
|
ship.data.finish_land_on();
|
|
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);
|
|
}
|
|
|
|
pub(super) fn start_unland_ship(&mut self, ct: &Content, collider: ColliderHandle) {
|
|
let ship = self.ships.get_mut(&collider).unwrap();
|
|
let obj = ship.data.get_state().landed_on().unwrap();
|
|
let obj = ct.get_system_object(obj);
|
|
|
|
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.start_unland_to(ct, target_pos);
|
|
|
|
let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap();
|
|
r.set_enabled(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
|
|
.get_mut(ship.collider)
|
|
.unwrap()
|
|
.set_collision_groups(InteractionGroups::new(
|
|
Group::GROUP_1,
|
|
Group::GROUP_1 | Group::GROUP_2,
|
|
));
|
|
}
|
|
|
|
pub(super) fn remove_ship(
|
|
&mut self,
|
|
res: &mut PhysStepResources,
|
|
colliderhandle: ColliderHandle,
|
|
) {
|
|
let ship = match self.ships.get(&colliderhandle) {
|
|
None => return,
|
|
Some(s) => s,
|
|
};
|
|
|
|
self.rigid_body_set.remove(
|
|
ship.rigid_body,
|
|
&mut res.wrapper.im,
|
|
&mut self.collider_set,
|
|
&mut res.wrapper.ij,
|
|
&mut res.wrapper.mj,
|
|
true,
|
|
);
|
|
self.ships.remove(&colliderhandle).unwrap();
|
|
self.ship_behaviors.remove(&colliderhandle);
|
|
}
|
|
|
|
pub(super) fn collide_projectile_ship(
|
|
&mut self,
|
|
res: &mut PhysStepResources,
|
|
projectile_h: ColliderHandle,
|
|
ship_h: ColliderHandle,
|
|
) {
|
|
let projectile = self.projectiles.get(&projectile_h);
|
|
let ship = self.ships.get_mut(&ship_h);
|
|
if projectile.is_none() || ship.is_none() {
|
|
return;
|
|
}
|
|
let projectile = projectile.unwrap();
|
|
let ship = ship.unwrap();
|
|
|
|
let f = res.ct.get_faction(projectile.faction);
|
|
let r = f.relationships.get(&ship.data.get_faction()).unwrap();
|
|
let destory_projectile = match r {
|
|
Relationship::Hostile => match ship.data.get_state() {
|
|
ShipState::Flying { .. } => {
|
|
ship.data.apply_damage(projectile.content.damage);
|
|
true
|
|
}
|
|
ShipState::Collapsing { .. } => true,
|
|
_ => false,
|
|
},
|
|
_ => false,
|
|
};
|
|
|
|
if destory_projectile {
|
|
let pr = self.rigid_body_set.get(projectile.rigid_body).unwrap();
|
|
let v =
|
|
pr.velocity_at_point(pr.center_of_mass()).normalize() * projectile.content.force;
|
|
let pos = *pr.translation();
|
|
let _ = pr;
|
|
|
|
let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap();
|
|
r.apply_impulse_at_point(Vector2::new(v.x, v.y), Point2::new(pos.x, pos.y), true);
|
|
|
|
// Borrow again, we can only have one at a time
|
|
let pr = self.rigid_body_set.get(projectile.rigid_body).unwrap();
|
|
let pos = *pr.translation();
|
|
let angle = pr.rotation().angle();
|
|
|
|
match &projectile.content.impact_effect {
|
|
None => {}
|
|
Some(x) => {
|
|
let effect = res.ct.get_effect(*x);
|
|
let r = ship.rigid_body;
|
|
let sr = self.get_rigid_body(r).unwrap();
|
|
let parent_velocity = pr.velocity_at_point(pr.center_of_mass());
|
|
let target_velocity =
|
|
sr.velocity_at_point(&nalgebra::Point2::new(pos.x, pos.y));
|
|
|
|
res.particles.push(ParticleBuilder::from_content(
|
|
effect,
|
|
pos.into(),
|
|
-angle,
|
|
parent_velocity,
|
|
target_velocity,
|
|
));
|
|
}
|
|
};
|
|
|
|
self.remove_projectile(res, projectile.collider);
|
|
}
|
|
}
|
|
}
|