Added basic landing
parent
c920ebefbc
commit
3b7ac5bc9a
|
@ -702,6 +702,7 @@ dependencies = [
|
|||
"cgmath",
|
||||
"galactica-content",
|
||||
"galactica-packer",
|
||||
"galactica-playeragent",
|
||||
"galactica-system",
|
||||
"galactica-util",
|
||||
"glyphon",
|
||||
|
|
|
@ -37,6 +37,15 @@ impl PartialEq for SpriteHandle {
|
|||
}
|
||||
}
|
||||
|
||||
/// A lightweight representation of system body
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct SystemObjectHandle {
|
||||
/// TODO: pub in crate
|
||||
pub system_handle: SystemHandle,
|
||||
/// The index of this object in system.objects
|
||||
pub body_index: usize,
|
||||
}
|
||||
|
||||
/// A lightweight representation of an outfit
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct OutfitHandle {
|
||||
|
|
|
@ -18,9 +18,7 @@ use std::{
|
|||
use toml;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
pub use handle::{
|
||||
EffectHandle, FactionHandle, GunHandle, OutfitHandle, ShipHandle, SpriteHandle, SystemHandle,
|
||||
};
|
||||
pub use handle::*;
|
||||
pub use part::*;
|
||||
|
||||
mod syntax {
|
||||
|
@ -333,6 +331,11 @@ impl Content {
|
|||
return &self.systems[h.index];
|
||||
}
|
||||
|
||||
/// Get a system object from a handle
|
||||
pub fn get_system_object(&self, h: SystemObjectHandle) -> &SystemObject {
|
||||
return &self.get_system(h.system_handle).objects[h.body_index];
|
||||
}
|
||||
|
||||
/// Get a faction from a handle
|
||||
pub fn get_faction(&self, h: FactionHandle) -> &Faction {
|
||||
return &self.factions[h.index];
|
||||
|
|
|
@ -19,4 +19,4 @@ pub use ship::{
|
|||
ShipCollapse,
|
||||
};
|
||||
pub use sprite::{RepeatMode, Sprite};
|
||||
pub use system::{Object, System};
|
||||
pub use system::{System, SystemObject};
|
||||
|
|
|
@ -2,7 +2,10 @@ use anyhow::{bail, Context, Result};
|
|||
use cgmath::{Deg, Point3, Rad};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::{handle::SpriteHandle, util::Polar, Content, ContentBuildContext};
|
||||
use crate::{
|
||||
handle::SpriteHandle, util::Polar, Content, ContentBuildContext, SystemHandle,
|
||||
SystemObjectHandle,
|
||||
};
|
||||
|
||||
pub(crate) mod syntax {
|
||||
use serde::Deserialize;
|
||||
|
@ -83,8 +86,11 @@ pub struct System {
|
|||
/// This star system's name
|
||||
pub name: String,
|
||||
|
||||
/// This star system's handle
|
||||
pub handle: SystemHandle,
|
||||
|
||||
/// Objects in this system
|
||||
pub objects: Vec<Object>,
|
||||
pub objects: Vec<SystemObject>,
|
||||
}
|
||||
|
||||
/// Represents an orbiting body in a star system
|
||||
|
@ -92,10 +98,13 @@ pub struct System {
|
|||
/// These may be landable and may be decorative.
|
||||
/// System objects to not interact with the physics engine.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Object {
|
||||
pub struct SystemObject {
|
||||
/// This object's sprite
|
||||
pub sprite: SpriteHandle,
|
||||
|
||||
/// This object's handle
|
||||
pub handle: SystemObjectHandle,
|
||||
|
||||
/// This object's size.
|
||||
/// Measured as height in game units.
|
||||
/// This value is scaled for distance
|
||||
|
@ -185,11 +194,15 @@ impl crate::Build for System {
|
|||
for (system_name, system) in system {
|
||||
let mut objects = Vec::new();
|
||||
|
||||
let system_handle = SystemHandle {
|
||||
index: content.systems.len(),
|
||||
};
|
||||
|
||||
for (label, obj) in &system.object {
|
||||
let mut cycle_detector = HashSet::new();
|
||||
cycle_detector.insert(label.clone());
|
||||
|
||||
let handle = match content.sprite_index.get(&obj.sprite) {
|
||||
let sprite_handle = match content.sprite_index.get(&obj.sprite) {
|
||||
None => bail!(
|
||||
"In system `{}`: sprite `{}` doesn't exist",
|
||||
system_name,
|
||||
|
@ -198,17 +211,33 @@ impl crate::Build for System {
|
|||
Some(t) => *t,
|
||||
};
|
||||
|
||||
objects.push(Object {
|
||||
sprite: handle,
|
||||
objects.push(SystemObject {
|
||||
sprite: sprite_handle,
|
||||
pos: resolve_position(&system.object, &obj, cycle_detector)
|
||||
.with_context(|| format!("In object {:#?}", label))?,
|
||||
size: obj.size,
|
||||
angle: Deg(obj.angle.unwrap_or(0.0)).into(),
|
||||
handle: SystemObjectHandle {
|
||||
system_handle,
|
||||
body_index: 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Sort by z-distance. This is important, since these are
|
||||
// rendered in this order. We need far objects to be behind
|
||||
// near objects!
|
||||
objects.sort_by(|a, b| b.pos.z.total_cmp(&a.pos.z));
|
||||
|
||||
// Update object handles
|
||||
let mut i = 0;
|
||||
for o in &mut objects {
|
||||
o.handle.body_index = i;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
content.systems.push(Self {
|
||||
handle: system_handle,
|
||||
name: system_name,
|
||||
objects,
|
||||
});
|
||||
|
|
|
@ -104,8 +104,10 @@ impl<'a> Game {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update_player_controls(&mut self, player: &PlayerAgent) {
|
||||
self.state.systemsim.update_player_controls(player)
|
||||
pub fn update_player_controls(&mut self, player: &mut PlayerAgent) {
|
||||
self.state
|
||||
.systemsim
|
||||
.update_player_controls(&self.ct, player)
|
||||
}
|
||||
|
||||
pub fn get_state(&self) -> &GameState {
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
mod game;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use cgmath::Point2;
|
||||
use galactica_content::{Content, SystemHandle};
|
||||
use galactica_playeragent::{PlayerAgent, PlayerStatus};
|
||||
use galactica_render::RenderInput;
|
||||
use galactica_system::phys::{util, PhysSimShipHandle};
|
||||
use galactica_system::{
|
||||
data::ShipState,
|
||||
phys::{util, PhysSimShipHandle},
|
||||
};
|
||||
use galactica_util::constants::ASSET_CACHE;
|
||||
use std::{
|
||||
fs,
|
||||
|
@ -56,7 +60,7 @@ fn main() -> Result<()> {
|
|||
ct: &content,
|
||||
systemsim: &game.get_state().systemsim,
|
||||
particles: game.get_particles(),
|
||||
player_ship: PhysSimShipHandle(player.ship.unwrap()),
|
||||
player: &player,
|
||||
current_system: SystemHandle { index: 0 },
|
||||
timing: game.get_state().timing.clone(),
|
||||
};
|
||||
|
@ -71,9 +75,10 @@ fn main() -> Result<()> {
|
|||
}
|
||||
|
||||
Event::MainEventsCleared => {
|
||||
game.update_player_controls(&player);
|
||||
game.update_player_controls(&mut player);
|
||||
game.update();
|
||||
|
||||
// TODO: clean up
|
||||
let player_status = {
|
||||
let pos = {
|
||||
let o = &game
|
||||
|
@ -81,11 +86,23 @@ fn main() -> Result<()> {
|
|||
.systemsim
|
||||
.get_ship(&PhysSimShipHandle(player.ship.unwrap()));
|
||||
if let Some(o) = o {
|
||||
let r = &game.get_state().systemsim.get_rigid_body(o.rigid_body);
|
||||
if let Some(r) = r {
|
||||
Some(util::rigidbody_position(r))
|
||||
} else {
|
||||
None
|
||||
match o.data.get_state() {
|
||||
ShipState::Collapsing { .. } | ShipState::Flying => {
|
||||
let r =
|
||||
&game.get_state().systemsim.get_rigid_body(o.rigid_body);
|
||||
if let Some(r) = r {
|
||||
Some(util::rigidbody_position(r))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ShipState::Landed { target } => {
|
||||
let b = content.get_system_object(*target);
|
||||
Some(Point2 {
|
||||
x: b.pos.x,
|
||||
y: b.pos.y,
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
@ -98,6 +115,7 @@ fn main() -> Result<()> {
|
|||
// This must be updated BEFORE rendering!
|
||||
player.step(&content, player_status);
|
||||
|
||||
player.input.clear_inputs();
|
||||
gpu.window().request_redraw();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
||||
|
||||
pub struct InputStatus {
|
||||
// Parameters
|
||||
scroll_speed: f32,
|
||||
pub key_left: bool,
|
||||
pub key_right: bool,
|
||||
pub key_thrust: bool,
|
||||
pub key_guns: bool,
|
||||
pub v_scroll: f32,
|
||||
|
||||
// Continuous keys
|
||||
key_left: bool,
|
||||
key_right: bool,
|
||||
key_thrust: bool,
|
||||
key_guns: bool,
|
||||
|
||||
// One-shot keys (audomatically released at the end of each frame)
|
||||
key_land: bool,
|
||||
v_scroll: f32,
|
||||
}
|
||||
|
||||
impl InputStatus {
|
||||
|
@ -16,6 +22,7 @@ impl InputStatus {
|
|||
key_right: false,
|
||||
key_thrust: false,
|
||||
key_guns: false,
|
||||
key_land: false,
|
||||
v_scroll: 0.0,
|
||||
scroll_speed: 10.0,
|
||||
}
|
||||
|
@ -26,15 +33,34 @@ impl InputStatus {
|
|||
self.key_right = false;
|
||||
self.key_thrust = false;
|
||||
self.key_guns = false;
|
||||
self.key_land = false;
|
||||
}
|
||||
|
||||
/// Called at the end of every frame,
|
||||
/// resets one-shot keys.
|
||||
pub fn clear_inputs(&mut self) {
|
||||
self.key_land = false;
|
||||
self.v_scroll = 0.0;
|
||||
}
|
||||
|
||||
pub fn process_key(&mut self, state: &ElementState, key: &VirtualKeyCode) {
|
||||
let down = state == &ElementState::Pressed;
|
||||
match key {
|
||||
VirtualKeyCode::Left => self.key_left = down,
|
||||
VirtualKeyCode::Right => self.key_right = down,
|
||||
VirtualKeyCode::Left => {
|
||||
self.key_left = down;
|
||||
if down {
|
||||
self.key_right = false;
|
||||
}
|
||||
}
|
||||
VirtualKeyCode::Right => {
|
||||
self.key_right = down;
|
||||
if down {
|
||||
self.key_left = false;
|
||||
}
|
||||
}
|
||||
VirtualKeyCode::Up => self.key_thrust = down,
|
||||
VirtualKeyCode::Space => self.key_guns = down,
|
||||
VirtualKeyCode::L => self.key_land = down,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -58,3 +84,41 @@ impl InputStatus {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Public get-state methods
|
||||
impl InputStatus {
|
||||
/// Has the player applied vertical scroll?
|
||||
/// This is measured in lines, scaled by scroll_speed
|
||||
///
|
||||
/// A positive value means scroll up, a negative value means scroll down.
|
||||
/// This is reset to zero at the end of each frame.
|
||||
pub fn get_v_scroll(&self) -> f32 {
|
||||
self.v_scroll
|
||||
}
|
||||
|
||||
/// Is the player pressing the "turn left" key?
|
||||
pub fn pressed_left(&self) -> bool {
|
||||
self.key_left
|
||||
}
|
||||
|
||||
/// Is the player pressing the "turn right" key?
|
||||
pub fn pressed_right(&self) -> bool {
|
||||
self.key_right
|
||||
}
|
||||
|
||||
/// Is the player pressing the "fowards" key?
|
||||
pub fn pressed_thrust(&self) -> bool {
|
||||
self.key_thrust
|
||||
}
|
||||
|
||||
/// Is the player pressing the "fire guns" key?
|
||||
pub fn pressed_guns(&self) -> bool {
|
||||
self.key_guns
|
||||
}
|
||||
|
||||
/// Has the player pressed the "land" key?
|
||||
/// (One-shot, reset to false at the start of each frame)
|
||||
pub fn pressed_land(&self) -> bool {
|
||||
self.key_land
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,43 @@
|
|||
use galactica_content::Content;
|
||||
use galactica_content::{Content, SystemHandle, SystemObjectHandle};
|
||||
use rapier2d::geometry::ColliderHandle;
|
||||
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
||||
|
||||
use crate::{camera::Camera, inputstatus::InputStatus, PlayerStatus};
|
||||
|
||||
/// What the player has selected
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum PlayerSelection {
|
||||
/// We have nothing selected
|
||||
None,
|
||||
|
||||
/// We have a system body selected
|
||||
OrbitingBody(SystemObjectHandle),
|
||||
|
||||
/// We have a ship selected
|
||||
Ship(ColliderHandle),
|
||||
}
|
||||
|
||||
impl PlayerSelection {
|
||||
pub fn get_planet(&self) -> Option<SystemObjectHandle> {
|
||||
match self {
|
||||
Self::OrbitingBody(h) => Some(*h),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PlayerAgent {
|
||||
/// Which ship this player is controlling
|
||||
pub ship: Option<ColliderHandle>,
|
||||
|
||||
/// What the player has selected
|
||||
pub selection: PlayerSelection,
|
||||
|
||||
/// This player's camera
|
||||
pub camera: Camera,
|
||||
|
||||
/// What buttons this player is pressing
|
||||
pub input: InputStatus,
|
||||
|
||||
/// What the player currently has selected
|
||||
pub selection: Option<()>,
|
||||
}
|
||||
|
||||
impl PlayerAgent {
|
||||
|
@ -24,7 +46,10 @@ impl PlayerAgent {
|
|||
input: InputStatus::new(),
|
||||
camera: Camera::new(),
|
||||
ship: Some(ship),
|
||||
selection: None,
|
||||
selection: PlayerSelection::OrbitingBody(SystemObjectHandle {
|
||||
system_handle: SystemHandle { index: 0 },
|
||||
body_index: 1,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,10 +70,9 @@ impl PlayerAgent {
|
|||
}
|
||||
|
||||
pub fn step(&mut self, ct: &Content, status: PlayerStatus) {
|
||||
if self.input.v_scroll != 0.0 {
|
||||
self.camera.zoom = (self.camera.zoom + self.input.v_scroll)
|
||||
if self.input.get_v_scroll() != 0.0 {
|
||||
self.camera.zoom = (self.camera.zoom + self.input.get_v_scroll())
|
||||
.clamp(ct.get_config().zoom_min, ct.get_config().zoom_max);
|
||||
self.input.v_scroll = 0.0;
|
||||
}
|
||||
|
||||
if status.pos.is_some() {
|
||||
|
|
|
@ -21,6 +21,7 @@ galactica-content = { workspace = true }
|
|||
galactica-util = { workspace = true }
|
||||
galactica-packer = { workspace = true }
|
||||
galactica-system = { workspace = true }
|
||||
galactica-playeragent = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
cgmath = { workspace = true }
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use cgmath::Point2;
|
||||
use galactica_content::{Content, SystemHandle};
|
||||
use galactica_system::phys::{ParticleBuilder, PhysSim, PhysSimShipHandle};
|
||||
use galactica_playeragent::PlayerAgent;
|
||||
use galactica_system::phys::{ParticleBuilder, PhysSim};
|
||||
use galactica_util::timing::Timing;
|
||||
use glyphon::{FontSystem, SwashCache, TextAtlas, TextRenderer};
|
||||
use std::rc::Rc;
|
||||
|
@ -15,7 +16,7 @@ pub struct RenderInput<'a> {
|
|||
pub camera_pos: Point2<f32>,
|
||||
|
||||
/// Player ship data
|
||||
pub player_ship: PhysSimShipHandle,
|
||||
pub player: &'a PlayerAgent,
|
||||
|
||||
/// The system we're currently in
|
||||
pub current_system: SystemHandle,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use bytemuck;
|
||||
use cgmath::{EuclideanSpace, InnerSpace, Point2, Vector2};
|
||||
use galactica_system::phys::util;
|
||||
use galactica_system::{data::ShipState, phys::util};
|
||||
use galactica_util::constants::OBJECT_SPRITE_INSTANCE_LIMIT;
|
||||
|
||||
use crate::{
|
||||
|
@ -19,6 +19,11 @@ impl GPUState {
|
|||
screen_clip: (Point2<f32>, Point2<f32>),
|
||||
) {
|
||||
for ship in state.systemsim.iter_ships() {
|
||||
match ship.data.get_state() {
|
||||
ShipState::Collapsing { .. } | ShipState::Flying => {}
|
||||
ShipState::Landed { .. } => continue,
|
||||
}
|
||||
|
||||
let r = state.systemsim.get_rigid_body(ship.rigid_body).unwrap();
|
||||
let ship_pos = util::rigidbody_position(&r);
|
||||
let ship_rot = util::rigidbody_rotation(r);
|
||||
|
|
|
@ -31,9 +31,21 @@ impl Radar {
|
|||
|
||||
// TODO: maybe a cleaner solution for last posititon?
|
||||
// This is necessary because the player may be dead or landed
|
||||
let player_ship = input.systemsim.get_ship(&input.player_ship).unwrap();
|
||||
let player_ship = input
|
||||
.systemsim
|
||||
.get_ship(&galactica_system::phys::PhysSimShipHandle(
|
||||
input.player.ship.unwrap(),
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
match player_ship.data.get_state() {
|
||||
ShipState::Landed { target } => {
|
||||
let landed_body = input.ct.get_system_object(*target);
|
||||
self.last_player_position = Point2 {
|
||||
x: landed_body.pos.x,
|
||||
y: landed_body.pos.y,
|
||||
};
|
||||
}
|
||||
ShipState::Flying | ShipState::Collapsing { .. } => {
|
||||
let player_body = input
|
||||
.systemsim
|
||||
|
@ -44,6 +56,7 @@ impl Radar {
|
|||
}
|
||||
};
|
||||
|
||||
// TODO: don't hard-code these, add config options
|
||||
let planet_sprite = input.ct.get_sprite_handle("ui::planetblip");
|
||||
let ship_sprite = input.ct.get_sprite_handle("ui::shipblip");
|
||||
let arrow_sprite = input.ct.get_sprite_handle("ui::centerarrow");
|
||||
|
@ -120,6 +133,9 @@ impl Radar {
|
|||
// This will be None if this ship is dead.
|
||||
// Stays around while the physics system runs a collapse sequence
|
||||
let color = match s.data.get_state() {
|
||||
ShipState::Landed { .. } => {
|
||||
continue;
|
||||
}
|
||||
ShipState::Collapsing { .. } => {
|
||||
// TODO: configurable
|
||||
[0.2, 0.2, 0.2, 1.0]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::f32::consts::TAU;
|
||||
|
||||
use galactica_system::data::ShipState;
|
||||
use galactica_util::constants::{RADIALBAR_SPRITE_INSTANCE_LIMIT, UI_SPRITE_INSTANCE_LIMIT};
|
||||
use std::f32::consts::TAU;
|
||||
|
||||
use crate::{
|
||||
datastructs::RenderState,
|
||||
|
@ -30,10 +29,15 @@ impl Status {
|
|||
let current_shields;
|
||||
let current_hull;
|
||||
let max_hull;
|
||||
let player_ship = input.systemsim.get_ship(&input.player_ship).unwrap();
|
||||
let player_ship = input
|
||||
.systemsim
|
||||
.get_ship(&galactica_system::phys::PhysSimShipHandle(
|
||||
input.player.ship.unwrap(),
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
match player_ship.data.get_state() {
|
||||
ShipState::Collapsing { .. } | ShipState::Flying => {
|
||||
ShipState::Landed { .. } | ShipState::Collapsing { .. } | ShipState::Flying => {
|
||||
max_shields = player_ship.data.get_outfits().get_shield_strength();
|
||||
current_shields = player_ship.data.get_shields();
|
||||
current_hull = player_ship.data.get_hull();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{collections::HashMap, time::Instant};
|
||||
|
||||
use super::{OutfitSet, ShipPersonality};
|
||||
use galactica_content::{Content, FactionHandle, GunPoint, Outfit, ShipHandle};
|
||||
use galactica_content::{Content, FactionHandle, GunPoint, Outfit, ShipHandle, SystemObjectHandle};
|
||||
use rand::{rngs::ThreadRng, Rng};
|
||||
|
||||
/// Ship state machine.
|
||||
|
@ -21,9 +21,38 @@ pub enum ShipState {
|
|||
/// How many seconds of the collapse sequence we've played
|
||||
elapsed: f32,
|
||||
},
|
||||
|
||||
/// This ship is landed on a planet
|
||||
Landed {
|
||||
/// The planet this ship is landed on
|
||||
target: SystemObjectHandle,
|
||||
},
|
||||
}
|
||||
|
||||
impl ShipState {
|
||||
/// Is this ship playing its collapse sequence?
|
||||
pub fn is_collapsing(&self) -> bool {
|
||||
match self {
|
||||
Self::Collapsing { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
/// Is this ship flying in open space?
|
||||
pub fn is_flying(&self) -> bool {
|
||||
match self {
|
||||
Self::Flying => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this ship landed on a planet?
|
||||
pub fn is_landed(&self) -> bool {
|
||||
match self {
|
||||
Self::Landed { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// True if this ship has been destroyed and has finished it's collapse sequence.
|
||||
/// Ships are deleted once this is true.
|
||||
pub fn should_be_removed(&self) -> bool {
|
||||
|
@ -33,11 +62,11 @@ impl ShipState {
|
|||
}
|
||||
}
|
||||
|
||||
/// Is this ship playing its collapse sequence?
|
||||
pub fn is_collapsing(&self) -> bool {
|
||||
/// What planet is this ship landed on?
|
||||
pub fn landed_on(&self) -> Option<SystemObjectHandle> {
|
||||
match self {
|
||||
Self::Collapsing { .. } => true,
|
||||
_ => false,
|
||||
Self::Landed { target } => Some(*target),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,14 +81,6 @@ impl ShipState {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this ship flying in open space?
|
||||
pub fn is_flying(&self) -> bool {
|
||||
match self {
|
||||
Self::Flying => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents all attributes of a single ship
|
||||
|
@ -115,6 +136,28 @@ impl ShipData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Land this ship on `target`
|
||||
pub fn land_on(&mut self, target: SystemObjectHandle) -> bool {
|
||||
if self.state.is_flying() {
|
||||
self.state = ShipState::Landed { target };
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Take off from `target`
|
||||
pub fn unland(&mut self) -> bool {
|
||||
if self.state.is_landed() {
|
||||
self.state = ShipState::Flying;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Add an outfit to this ship
|
||||
pub fn add_outfit(&mut self, o: &Outfit) -> super::OutfitAddResult {
|
||||
let r = self.outfits.add(o);
|
||||
|
@ -181,6 +224,20 @@ impl ShipData {
|
|||
*elapsed += t;
|
||||
}
|
||||
|
||||
ShipState::Landed { .. } => {
|
||||
// Cooldown guns
|
||||
for (_, c) in &mut self.gun_cooldowns {
|
||||
if *c > 0.0 {
|
||||
*c = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Regenerate shields
|
||||
if self.shields != self.outfits.get_shield_strength() {
|
||||
self.shields = self.outfits.get_shield_strength();
|
||||
}
|
||||
}
|
||||
|
||||
ShipState::Flying => {
|
||||
// Cooldown guns
|
||||
for (_, c) in &mut self.gun_cooldowns {
|
||||
|
|
|
@ -99,6 +99,7 @@ impl PhysSimShip {
|
|||
ShipState::Flying => {
|
||||
return self.step_live(res, rigid_body, collider);
|
||||
}
|
||||
ShipState::Landed { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Point2, Rad, Vector2, Zero};
|
||||
use galactica_content::{
|
||||
Content, FactionHandle, GunPoint, OutfitHandle, ProjectileCollider, Relationship, ShipHandle,
|
||||
SystemHandle,
|
||||
SystemHandle, SystemObjectHandle,
|
||||
};
|
||||
use galactica_playeragent::PlayerAgent;
|
||||
use nalgebra::{point, vector};
|
||||
|
@ -13,7 +13,7 @@ use rapier2d::{
|
|||
};
|
||||
use std::{collections::HashMap, f32::consts::PI};
|
||||
|
||||
use crate::data::ShipPersonality;
|
||||
use crate::data::{ShipPersonality, ShipState};
|
||||
|
||||
use super::{
|
||||
controller::ShipController,
|
||||
|
@ -67,6 +67,40 @@ impl<'a> PhysSim {
|
|||
return Some((r, p));
|
||||
}
|
||||
|
||||
fn land_ship(&mut self, collider: ColliderHandle, target: SystemObjectHandle) {
|
||||
let ship = self.ships.get_mut(&collider).unwrap();
|
||||
self.rigid_body_set
|
||||
.get_mut(ship.rigid_body)
|
||||
.unwrap()
|
||||
.set_enabled(false);
|
||||
self.collider_set
|
||||
.get_mut(ship.collider)
|
||||
.unwrap()
|
||||
.set_enabled(false);
|
||||
|
||||
ship.data.land_on(target);
|
||||
}
|
||||
|
||||
fn 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);
|
||||
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);
|
||||
self.collider_set
|
||||
.get_mut(ship.collider)
|
||||
.unwrap()
|
||||
.set_enabled(true);
|
||||
}
|
||||
|
||||
fn remove_ship(&mut self, res: &mut PhysStepResources, colliderhandle: ColliderHandle) {
|
||||
let ship = match self.ships.get(&colliderhandle) {
|
||||
None => return,
|
||||
|
@ -213,16 +247,31 @@ impl PhysSim {
|
|||
}
|
||||
|
||||
/// Update a player ship's controls
|
||||
pub fn update_player_controls(&mut self, player: &PlayerAgent) {
|
||||
pub fn update_player_controls(&mut self, ct: &Content, player: &PlayerAgent) {
|
||||
if player.ship.is_none() {
|
||||
return;
|
||||
}
|
||||
let ship_object = self.ships.get_mut(&player.ship.unwrap());
|
||||
if let Some(ship_object) = ship_object {
|
||||
ship_object.controls.guns = player.input.key_guns;
|
||||
ship_object.controls.left = player.input.key_left;
|
||||
ship_object.controls.right = player.input.key_right;
|
||||
ship_object.controls.thrust = player.input.key_thrust;
|
||||
ship_object.controls.guns = player.input.pressed_guns();
|
||||
ship_object.controls.left = player.input.pressed_left();
|
||||
ship_object.controls.right = player.input.pressed_right();
|
||||
ship_object.controls.thrust = player.input.pressed_thrust();
|
||||
|
||||
if player.input.pressed_land() {
|
||||
match ship_object.data.get_state() {
|
||||
ShipState::Flying => {
|
||||
self.land_ship(
|
||||
player.ship.unwrap(),
|
||||
player.selection.get_planet().unwrap(),
|
||||
);
|
||||
}
|
||||
ShipState::Landed { .. } => {
|
||||
self.unland_ship(ct, player.ship.unwrap());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,48 +296,54 @@ impl PhysSim {
|
|||
continue;
|
||||
}
|
||||
|
||||
// This ship is playing a collapse sequence
|
||||
// and needs no additional logic
|
||||
if ship.data.get_state().is_collapsing() {
|
||||
let ship = self.ships.get_mut(&collider).unwrap();
|
||||
ship.step(
|
||||
res,
|
||||
&mut self.rigid_body_set[ship.rigid_body],
|
||||
&mut self.collider_set[ship.collider],
|
||||
);
|
||||
continue;
|
||||
}
|
||||
match ship.data.get_state() {
|
||||
ShipState::Landed { .. } => {}
|
||||
|
||||
// Compute new controls
|
||||
let controls;
|
||||
let b = self.ship_behaviors.get_mut(&collider).unwrap();
|
||||
controls = b.update_controls(&res, &self.rigid_body_set, &self.ships, ship.collider);
|
||||
ShipState::Collapsing { .. } => {
|
||||
let ship = self.ships.get_mut(&collider).unwrap();
|
||||
ship.step(
|
||||
res,
|
||||
&mut self.rigid_body_set[ship.rigid_body],
|
||||
&mut self.collider_set[ship.collider],
|
||||
);
|
||||
}
|
||||
|
||||
let ship = self.ships.get_mut(&collider).unwrap();
|
||||
ShipState::Flying => {
|
||||
// Compute new controls
|
||||
// This is why we borrow immutably first
|
||||
let controls;
|
||||
let b = self.ship_behaviors.get_mut(&collider).unwrap();
|
||||
controls =
|
||||
b.update_controls(&res, &self.rigid_body_set, &self.ships, ship.collider);
|
||||
|
||||
if let Some(controls) = controls {
|
||||
ship.controls = controls;
|
||||
}
|
||||
ship.step(
|
||||
res,
|
||||
&mut self.rigid_body_set[ship.rigid_body],
|
||||
&mut self.collider_set[ship.collider],
|
||||
);
|
||||
// Re-borrow mutably to apply changes
|
||||
let ship = self.ships.get_mut(&collider).unwrap();
|
||||
|
||||
// If we're firing, try to fire each gun
|
||||
if ship.controls.guns {
|
||||
// TODO: don't allocate here. This is a hack to satisfy the borrow checker,
|
||||
// convert this to a refcell or do the replace dance.
|
||||
let pairs: Vec<(GunPoint, Option<OutfitHandle>)> = ship
|
||||
.data
|
||||
.get_outfits()
|
||||
.iter_gun_points()
|
||||
.map(|(p, o)| (p.clone(), o.clone()))
|
||||
.collect();
|
||||
if let Some(controls) = controls {
|
||||
ship.controls = controls;
|
||||
}
|
||||
ship.step(
|
||||
res,
|
||||
&mut self.rigid_body_set[ship.rigid_body],
|
||||
&mut self.collider_set[ship.collider],
|
||||
);
|
||||
|
||||
for (gun, outfit) in pairs {
|
||||
if ship.data.fire_gun(res.ct, &gun) {
|
||||
projectiles.push((ship.collider, gun.clone(), outfit.unwrap()));
|
||||
// If we're firing, try to fire each gun
|
||||
if ship.controls.guns {
|
||||
// TODO: don't allocate here. This is a hack to satisfy the borrow checker,
|
||||
// convert this to a refcell or do the replace dance.
|
||||
let pairs: Vec<(GunPoint, Option<OutfitHandle>)> = ship
|
||||
.data
|
||||
.get_outfits()
|
||||
.iter_gun_points()
|
||||
.map(|(p, o)| (p.clone(), o.clone()))
|
||||
.collect();
|
||||
|
||||
for (gun, outfit) in pairs {
|
||||
if ship.data.fire_gun(res.ct, &gun) {
|
||||
projectiles.push((ship.collider, gun.clone(), outfit.unwrap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue