Renamed a few objects
parent
5ceff9f039
commit
eaa8a7383c
|
@ -581,9 +581,9 @@ dependencies = [
|
|||
"cgmath",
|
||||
"galactica-constants",
|
||||
"galactica-content",
|
||||
"galactica-gameobject",
|
||||
"galactica-galaxy",
|
||||
"galactica-render",
|
||||
"galactica-world",
|
||||
"galactica-systemsim",
|
||||
"pollster",
|
||||
"wgpu",
|
||||
"winit",
|
||||
|
@ -608,7 +608,7 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "galactica-gameobject"
|
||||
name = "galactica-galaxy"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cgmath",
|
||||
|
@ -637,9 +637,9 @@ dependencies = [
|
|||
"cgmath",
|
||||
"galactica-constants",
|
||||
"galactica-content",
|
||||
"galactica-gameobject",
|
||||
"galactica-galaxy",
|
||||
"galactica-packer",
|
||||
"galactica-world",
|
||||
"galactica-systemsim",
|
||||
"image",
|
||||
"rand",
|
||||
"wgpu",
|
||||
|
@ -647,13 +647,13 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "galactica-world"
|
||||
name = "galactica-systemsim"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cgmath",
|
||||
"crossbeam",
|
||||
"galactica-content",
|
||||
"galactica-gameobject",
|
||||
"galactica-galaxy",
|
||||
"nalgebra",
|
||||
"rand",
|
||||
"rapier2d",
|
||||
|
|
|
@ -45,8 +45,8 @@ readme = ""
|
|||
galactica-constants = { path = "crates/constants" }
|
||||
galactica-content = { path = "crates/content" }
|
||||
galactica-render = { path = "crates/render" }
|
||||
galactica-world = { path = "crates/world" }
|
||||
galactica-gameobject = { path = "crates/gameobject" }
|
||||
galactica-systemsim = { path = "crates/systemsim" }
|
||||
galactica-galaxy = { path = "crates/galaxy" }
|
||||
galactica-packer = { path = "crates/packer" }
|
||||
galactica = { path = "crates/galactica" }
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ workspace = true
|
|||
galactica-content = { workspace = true }
|
||||
galactica-render = { workspace = true }
|
||||
galactica-constants = { workspace = true }
|
||||
galactica-world = { workspace = true }
|
||||
galactica-gameobject = { workspace = true }
|
||||
galactica-systemsim = { workspace = true }
|
||||
galactica-galaxy = { workspace = true }
|
||||
|
||||
winit = { workspace = true }
|
||||
wgpu = { workspace = true }
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use object::{ship::ShipPersonality, GameData, GameShipHandle};
|
||||
use galactica_content::{Content, FactionHandle, OutfitHandle, ShipHandle, SystemHandle};
|
||||
use galactica_galaxy::{ship::ShipPersonality, Galaxy, GxShipHandle};
|
||||
use std::time::Instant;
|
||||
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
||||
|
||||
|
@ -6,70 +7,66 @@ use crate::camera::Camera;
|
|||
use crate::inputstatus::InputStatus;
|
||||
|
||||
use galactica_constants;
|
||||
use galactica_content as content;
|
||||
use galactica_gameobject as object;
|
||||
use galactica_render::RenderState;
|
||||
use galactica_world::{objects::ShipControls, util, ParticleBuilder, StepResources, World};
|
||||
use galactica_systemsim::{objects::ShipControls, util, ParticleBuilder, StepResources, SystemSim};
|
||||
|
||||
pub struct Game {
|
||||
input: InputStatus,
|
||||
last_update: Instant,
|
||||
player: GameShipHandle,
|
||||
player: GxShipHandle,
|
||||
paused: bool,
|
||||
time_scale: f32,
|
||||
start_instant: Instant,
|
||||
camera: Camera,
|
||||
|
||||
// TODO: include system in world
|
||||
//system: object::System,
|
||||
gamedata: GameData,
|
||||
galaxy: Galaxy,
|
||||
content: Content,
|
||||
systemsim: SystemSim,
|
||||
|
||||
content: content::Content,
|
||||
world: World,
|
||||
new_particles: Vec<ParticleBuilder>,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
pub fn new(ct: content::Content) -> Self {
|
||||
let mut gamedata = GameData::new(&ct);
|
||||
pub fn new(ct: Content) -> Self {
|
||||
let mut galaxy = Galaxy::new(&ct);
|
||||
|
||||
let player = gamedata.create_ship(
|
||||
let player = galaxy.create_ship(
|
||||
&ct,
|
||||
content::ShipHandle { index: 0 },
|
||||
content::FactionHandle { index: 0 },
|
||||
ShipHandle { index: 0 },
|
||||
FactionHandle { index: 0 },
|
||||
ShipPersonality::Player,
|
||||
&content::SystemHandle { index: 0 },
|
||||
&SystemHandle { index: 0 },
|
||||
);
|
||||
let s = gamedata.get_ship_mut(player).unwrap();
|
||||
s.add_outfit(&ct.get_outfit(content::OutfitHandle { index: 0 }));
|
||||
s.add_outfit(&ct.get_outfit(content::OutfitHandle { index: 1 }));
|
||||
s.add_outfit(&ct.get_outfit(content::OutfitHandle { index: 2 }));
|
||||
let s = galaxy.get_ship_mut(player).unwrap();
|
||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 0 }));
|
||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 1 }));
|
||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 2 }));
|
||||
|
||||
let a = gamedata.create_ship(
|
||||
let a = galaxy.create_ship(
|
||||
&ct,
|
||||
content::ShipHandle { index: 0 },
|
||||
content::FactionHandle { index: 1 },
|
||||
ShipHandle { index: 0 },
|
||||
FactionHandle { index: 1 },
|
||||
ShipPersonality::Dummy,
|
||||
&content::SystemHandle { index: 0 },
|
||||
&SystemHandle { index: 0 },
|
||||
);
|
||||
let s = gamedata.get_ship_mut(a).unwrap();
|
||||
s.add_outfit(&ct.get_outfit(content::OutfitHandle { index: 0 }));
|
||||
s.add_outfit(&ct.get_outfit(content::OutfitHandle { index: 1 }));
|
||||
s.add_outfit(&ct.get_outfit(content::OutfitHandle { index: 2 }));
|
||||
let s = galaxy.get_ship_mut(a).unwrap();
|
||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 0 }));
|
||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 1 }));
|
||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 2 }));
|
||||
|
||||
let a = gamedata.create_ship(
|
||||
let a = galaxy.create_ship(
|
||||
&ct,
|
||||
content::ShipHandle { index: 0 },
|
||||
content::FactionHandle { index: 0 },
|
||||
ShipHandle { index: 0 },
|
||||
FactionHandle { index: 0 },
|
||||
ShipPersonality::Point,
|
||||
&content::SystemHandle { index: 0 },
|
||||
&SystemHandle { index: 0 },
|
||||
);
|
||||
let s = gamedata.get_ship_mut(a).unwrap();
|
||||
s.add_outfit(&ct.get_outfit(content::OutfitHandle { index: 0 }));
|
||||
s.add_outfit(&ct.get_outfit(content::OutfitHandle { index: 1 }));
|
||||
s.add_outfit(&ct.get_outfit(content::OutfitHandle { index: 2 }));
|
||||
let s = galaxy.get_ship_mut(a).unwrap();
|
||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 0 }));
|
||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 1 }));
|
||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 2 }));
|
||||
|
||||
let physics = World::new(&ct, &gamedata, content::SystemHandle { index: 0 });
|
||||
let physics = SystemSim::new(&ct, &galaxy, SystemHandle { index: 0 });
|
||||
|
||||
Game {
|
||||
last_update: Instant::now(),
|
||||
|
@ -85,8 +82,8 @@ impl Game {
|
|||
//system: object::System::new(&ct, SystemHandle { index: 0 }),
|
||||
paused: false,
|
||||
time_scale: 1.0,
|
||||
world: physics,
|
||||
gamedata,
|
||||
systemsim: physics,
|
||||
galaxy,
|
||||
content: ct,
|
||||
new_particles: Vec::new(),
|
||||
}
|
||||
|
@ -120,9 +117,9 @@ impl Game {
|
|||
pub fn update(&mut self) {
|
||||
let t: f32 = self.last_update.elapsed().as_secs_f32() * self.time_scale;
|
||||
|
||||
self.gamedata.step(t);
|
||||
self.galaxy.step(t);
|
||||
|
||||
self.world.step(StepResources {
|
||||
self.systemsim.step(StepResources {
|
||||
player: self.player,
|
||||
player_controls: ShipControls {
|
||||
left: self.input.key_left,
|
||||
|
@ -131,7 +128,7 @@ impl Game {
|
|||
guns: self.input.key_guns,
|
||||
},
|
||||
ct: &self.content,
|
||||
dt: &mut self.gamedata,
|
||||
gx: &mut self.galaxy,
|
||||
particles: &mut self.new_particles,
|
||||
t,
|
||||
});
|
||||
|
@ -143,8 +140,8 @@ impl Game {
|
|||
}
|
||||
|
||||
self.camera.pos = {
|
||||
let o = self.world.get_ship(self.player).unwrap();
|
||||
let r = self.world.get_rigid_body(o.rigid_body).unwrap();
|
||||
let o = self.systemsim.get_ship(self.player).unwrap();
|
||||
let r = self.systemsim.get_rigid_body(o.rigid_body).unwrap();
|
||||
util::rigidbody_position(r)
|
||||
};
|
||||
|
||||
|
@ -157,11 +154,11 @@ impl Game {
|
|||
camera_zoom: self.camera.zoom,
|
||||
current_time: self.start_instant.elapsed().as_secs_f32(),
|
||||
content: &self.content,
|
||||
world: &self.world, // TODO: maybe system should be stored here?
|
||||
systemsim: &self.systemsim, // TODO: maybe system should be stored here?
|
||||
particles: &mut self.new_particles,
|
||||
player_data: self.player,
|
||||
data: &self.gamedata,
|
||||
current_system: content::SystemHandle { index: 0 },
|
||||
data: &self.galaxy,
|
||||
current_system: SystemHandle { index: 0 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,9 @@ mod camera;
|
|||
mod game;
|
||||
mod inputstatus;
|
||||
|
||||
pub use galactica_content as content;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use galactica_constants::{self, ASSET_CACHE};
|
||||
use galactica_constants::{ASSET_CACHE, CONTENT_ROOT, IMAGE_ROOT, STARFIELD_SPRITE_NAME};
|
||||
use galactica_content::Content;
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
|
@ -27,11 +26,11 @@ fn main() -> Result<()> {
|
|||
}
|
||||
|
||||
// TODO: pretty error if missing
|
||||
let content = content::Content::load_dir(
|
||||
PathBuf::from(galactica_constants::CONTENT_ROOT),
|
||||
PathBuf::from(galactica_constants::IMAGE_ROOT),
|
||||
let content = Content::load_dir(
|
||||
PathBuf::from(CONTENT_ROOT),
|
||||
PathBuf::from(IMAGE_ROOT),
|
||||
atlas_index,
|
||||
galactica_constants::STARFIELD_SPRITE_NAME.to_owned(),
|
||||
STARFIELD_SPRITE_NAME.to_owned(),
|
||||
)?;
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "galactica-gameobject"
|
||||
name = "galactica-galaxy"
|
||||
description = "Galactica's game data manager"
|
||||
categories = { workspace = true }
|
||||
keywords = { workspace = true }
|
|
@ -1,30 +1,30 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{handles::GameShipHandle, ship::Ship, ship::ShipPersonality};
|
||||
use galactica_content as content;
|
||||
use crate::{handles::GxShipHandle, ship::GxShip, ship::ShipPersonality};
|
||||
use galactica_content::{Content, FactionHandle, ShipHandle, SystemHandle};
|
||||
|
||||
/// Keeps track of all objects in the galaxy.
|
||||
/// This struct does NO physics, it keeps track of data exclusively.
|
||||
#[derive(Debug)]
|
||||
pub struct GameData {
|
||||
pub struct Galaxy {
|
||||
/// Universal counter.
|
||||
/// Used to create unique handles for game objects.
|
||||
index: u64,
|
||||
|
||||
/// All ships in the galaxy
|
||||
ships: HashMap<GameShipHandle, Ship>,
|
||||
ships: HashMap<GxShipHandle, GxShip>,
|
||||
|
||||
/// Ships indexed by the system they're in.
|
||||
/// A ship must always be in exactly one system.
|
||||
system_ship_table: HashMap<content::SystemHandle, Vec<GameShipHandle>>,
|
||||
system_ship_table: HashMap<SystemHandle, Vec<GxShipHandle>>,
|
||||
|
||||
/// Systems indexed by which ships they contain.
|
||||
/// A ship must always be in exactly one system.
|
||||
ship_system_table: HashMap<GameShipHandle, content::SystemHandle>,
|
||||
ship_system_table: HashMap<GxShipHandle, SystemHandle>,
|
||||
}
|
||||
|
||||
impl GameData {
|
||||
pub fn new(ct: &content::Content) -> Self {
|
||||
impl Galaxy {
|
||||
pub fn new(ct: &Content) -> Self {
|
||||
Self {
|
||||
system_ship_table: ct.iter_systems().map(|s| (s, Vec::new())).collect(),
|
||||
ship_system_table: HashMap::new(),
|
||||
|
@ -36,20 +36,20 @@ impl GameData {
|
|||
/// Spawn a ship
|
||||
pub fn create_ship(
|
||||
&mut self,
|
||||
ct: &content::Content,
|
||||
ship: content::ShipHandle,
|
||||
faction: content::FactionHandle,
|
||||
ct: &Content,
|
||||
ship: ShipHandle,
|
||||
faction: FactionHandle,
|
||||
personality: ShipPersonality,
|
||||
system: &content::SystemHandle,
|
||||
) -> GameShipHandle {
|
||||
let handle = GameShipHandle {
|
||||
system: &SystemHandle,
|
||||
) -> GxShipHandle {
|
||||
let handle = GxShipHandle {
|
||||
index: self.index,
|
||||
content: ship,
|
||||
};
|
||||
self.index += 1;
|
||||
|
||||
self.ships
|
||||
.insert(handle, Ship::new(ct, handle, ship, faction, personality));
|
||||
.insert(handle, GxShip::new(ct, handle, ship, faction, personality));
|
||||
self.system_ship_table.get_mut(system).unwrap().push(handle);
|
||||
self.ship_system_table.insert(handle, *system);
|
||||
|
||||
|
@ -59,7 +59,7 @@ impl GameData {
|
|||
pub fn step(&mut self, t: f32) {
|
||||
// TODO: don't allocate on step, need a better
|
||||
// way to satisfy the borrow checker.
|
||||
// Same needs to be done in the `world` crate.
|
||||
// Same needs to be done in the `systemsim` crate.
|
||||
let mut to_remove = Vec::new();
|
||||
for (_, s) in &mut self.ships {
|
||||
s.step(t);
|
||||
|
@ -83,16 +83,16 @@ impl GameData {
|
|||
}
|
||||
|
||||
// Public getters
|
||||
impl GameData {
|
||||
pub fn get_ship(&self, handle: GameShipHandle) -> Option<&Ship> {
|
||||
impl Galaxy {
|
||||
pub fn get_ship(&self, handle: GxShipHandle) -> Option<&GxShip> {
|
||||
self.ships.get(&handle)
|
||||
}
|
||||
|
||||
pub fn get_ship_mut(&mut self, handle: GameShipHandle) -> Option<&mut Ship> {
|
||||
pub fn get_ship_mut(&mut self, handle: GxShipHandle) -> Option<&mut GxShip> {
|
||||
self.ships.get_mut(&handle)
|
||||
}
|
||||
|
||||
pub fn iter_ships(&self) -> impl Iterator<Item = &Ship> {
|
||||
pub fn iter_ships(&self) -> impl Iterator<Item = &GxShip> {
|
||||
self.ships.values()
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ use galactica_content::ShipHandle;
|
|||
|
||||
/// A lightweight representation of a ship in the galaxy
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct GameShipHandle {
|
||||
pub struct GxShipHandle {
|
||||
/// This ship's unique index
|
||||
pub(crate) index: u64,
|
||||
|
||||
|
@ -13,20 +13,20 @@ pub struct GameShipHandle {
|
|||
pub(crate) content: ShipHandle,
|
||||
}
|
||||
|
||||
impl GameShipHandle {
|
||||
impl GxShipHandle {
|
||||
pub fn content_handle(&self) -> ShipHandle {
|
||||
self.content
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for GameShipHandle {
|
||||
impl Hash for GxShipHandle {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.index.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for GameShipHandle {}
|
||||
impl PartialEq for GameShipHandle {
|
||||
impl Eq for GxShipHandle {}
|
||||
impl PartialEq for GxShipHandle {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.index.eq(&other.index)
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
//! This module keeps track of the galaxy state.
|
||||
//! It is also responsible for ship stats, outfits, etc.
|
||||
//!
|
||||
//! `galaxy` does not provide any simulation logic---that is done in seperate crates.
|
||||
|
||||
mod galaxy;
|
||||
mod handles;
|
||||
pub mod ship;
|
||||
|
||||
pub use galaxy::*;
|
||||
pub use handles::*;
|
|
@ -1,7 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use content::{GunPoint, OutfitHandle, OutfitSpace, SpriteHandle};
|
||||
use galactica_content as content;
|
||||
use galactica_content::{Content, GunPoint, Outfit, OutfitHandle, OutfitSpace, SpriteHandle};
|
||||
|
||||
/// Possible outcomes when adding an outfit
|
||||
pub enum OutfitAddResult {
|
||||
|
@ -89,7 +88,7 @@ impl OutfitSet {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn add(&mut self, o: &content::Outfit) -> OutfitAddResult {
|
||||
pub(super) fn add(&mut self, o: &Outfit) -> OutfitAddResult {
|
||||
if !(self.total_space - self.used_space).can_contain(&o.space) {
|
||||
return OutfitAddResult::NotEnoughSpace("TODO".to_string());
|
||||
}
|
||||
|
@ -129,7 +128,7 @@ impl OutfitSet {
|
|||
return OutfitAddResult::Ok;
|
||||
}
|
||||
|
||||
pub(super) fn remove(&mut self, o: &content::Outfit) -> OutfitRemoveResult {
|
||||
pub(super) fn remove(&mut self, o: &Outfit) -> OutfitRemoveResult {
|
||||
if !self.outfits.contains_key(&o.handle) {
|
||||
return OutfitRemoveResult::NotExist;
|
||||
} else {
|
||||
|
@ -161,7 +160,7 @@ impl OutfitSet {
|
|||
}
|
||||
|
||||
// TODO: pick these better
|
||||
pub fn get_flare_sprite(&self, ct: &content::Content) -> Option<SpriteHandle> {
|
||||
pub fn get_flare_sprite(&self, ct: &Content) -> Option<SpriteHandle> {
|
||||
for i in self.outfits.keys() {
|
||||
let c = ct.get_outfit(*i);
|
||||
if c.engine_flare_sprite.is_some() {
|
|
@ -1,6 +1,5 @@
|
|||
/// Computer-controlled ship behavior variants.
|
||||
/// This is just a list, actual physics-aware
|
||||
/// behaviors are implemented in [`galactica-behavior`]
|
||||
/// This is just a list, actual state-aware behaviors are implemented in each simulation crate.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ShipPersonality {
|
||||
/// This ship is controlled by a player
|
|
@ -1,18 +1,17 @@
|
|||
use std::{collections::HashMap, time::Instant};
|
||||
|
||||
use crate::GameShipHandle;
|
||||
use crate::GxShipHandle;
|
||||
|
||||
use super::{OutfitSet, ShipPersonality};
|
||||
use content::GunPoint;
|
||||
use galactica_content as content;
|
||||
use galactica_content::{Content, FactionHandle, GunPoint, Outfit, ShipHandle};
|
||||
use rand::{rngs::ThreadRng, Rng};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Ship {
|
||||
pub struct GxShip {
|
||||
// Metadata values
|
||||
handle: GameShipHandle,
|
||||
ct_handle: content::ShipHandle,
|
||||
faction: content::FactionHandle,
|
||||
handle: GxShipHandle,
|
||||
ct_handle: ShipHandle,
|
||||
faction: FactionHandle,
|
||||
outfits: OutfitSet,
|
||||
|
||||
personality: ShipPersonality,
|
||||
|
@ -29,16 +28,16 @@ pub struct Ship {
|
|||
last_hit: Instant,
|
||||
}
|
||||
|
||||
impl Ship {
|
||||
impl GxShip {
|
||||
pub(crate) fn new(
|
||||
ct: &content::Content,
|
||||
handle: GameShipHandle,
|
||||
ct_handle: content::ShipHandle,
|
||||
faction: content::FactionHandle,
|
||||
ct: &Content,
|
||||
handle: GxShipHandle,
|
||||
ct_handle: ShipHandle,
|
||||
faction: FactionHandle,
|
||||
personality: ShipPersonality,
|
||||
) -> Self {
|
||||
let s = ct.get_ship(ct_handle);
|
||||
Ship {
|
||||
GxShip {
|
||||
handle,
|
||||
ct_handle,
|
||||
faction,
|
||||
|
@ -55,14 +54,14 @@ impl Ship {
|
|||
}
|
||||
|
||||
/// Add an outfit to this ship
|
||||
pub fn add_outfit(&mut self, o: &content::Outfit) -> super::OutfitAddResult {
|
||||
pub fn add_outfit(&mut self, o: &Outfit) -> super::OutfitAddResult {
|
||||
let r = self.outfits.add(o);
|
||||
self.shields = self.outfits.get_shield_strength();
|
||||
return r;
|
||||
}
|
||||
|
||||
/// Remove an outfit from this ship
|
||||
pub fn remove_outfit(&mut self, o: &content::Outfit) -> super::OutfitRemoveResult {
|
||||
pub fn remove_outfit(&mut self, o: &Outfit) -> super::OutfitRemoveResult {
|
||||
self.outfits.remove(o)
|
||||
}
|
||||
|
||||
|
@ -75,7 +74,7 @@ impl Ship {
|
|||
/// Will panic if `which` isn't a point on this ship.
|
||||
/// Returns `true` if this gun was fired,
|
||||
/// and `false` if it is on cooldown or empty.
|
||||
pub fn fire_gun(&mut self, ct: &content::Content, which: &GunPoint) -> bool {
|
||||
pub fn fire_gun(&mut self, ct: &Content, which: &GunPoint) -> bool {
|
||||
let c = self.gun_cooldowns.get_mut(which).unwrap();
|
||||
|
||||
if *c > 0.0 {
|
||||
|
@ -134,14 +133,14 @@ impl Ship {
|
|||
}
|
||||
|
||||
// Misc getters, so internal state is untouchable
|
||||
impl Ship {
|
||||
impl GxShip {
|
||||
/// Get a handle to this ship game object
|
||||
pub fn get_handle(&self) -> GameShipHandle {
|
||||
pub fn get_handle(&self) -> GxShipHandle {
|
||||
self.handle
|
||||
}
|
||||
|
||||
/// Get a handle to this ship's content
|
||||
pub fn get_content(&self) -> content::ShipHandle {
|
||||
pub fn get_content(&self) -> ShipHandle {
|
||||
self.ct_handle
|
||||
}
|
||||
|
||||
|
@ -168,12 +167,12 @@ impl Ship {
|
|||
}
|
||||
|
||||
/// Get this ship's faction
|
||||
pub fn get_faction(&self) -> content::FactionHandle {
|
||||
pub fn get_faction(&self) -> FactionHandle {
|
||||
self.faction
|
||||
}
|
||||
|
||||
/// Get this ship's content handle
|
||||
pub fn get_ship(&self) -> content::ShipHandle {
|
||||
pub fn get_ship(&self) -> ShipHandle {
|
||||
self.ct_handle
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
//! This module handles all game data: ship damage, outfit stats, etc.
|
||||
//!
|
||||
//! The code here handles game *data* exclusively: it keeps track of the status
|
||||
//! of every ship in the game, but it has no understanding of physics.
|
||||
//! That is done in `galactica_world`.
|
||||
|
||||
mod gamedata;
|
||||
mod handles;
|
||||
pub mod ship;
|
||||
|
||||
pub use gamedata::*;
|
||||
pub use handles::*;
|
|
@ -20,8 +20,8 @@ workspace = true
|
|||
galactica-content = { workspace = true }
|
||||
galactica-constants = { workspace = true }
|
||||
galactica-packer = { workspace = true }
|
||||
galactica-world = { workspace = true }
|
||||
galactica-gameobject = { workspace = true }
|
||||
galactica-systemsim = { workspace = true }
|
||||
galactica-galaxy = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
cgmath = { workspace = true }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use std::f32::consts::TAU;
|
||||
|
||||
use cgmath::{Deg, InnerSpace, Point2, Rad, Vector2};
|
||||
use galactica_world::util;
|
||||
use galactica_systemsim::util;
|
||||
|
||||
use crate::{
|
||||
vertexbuffer::{
|
||||
|
@ -22,9 +22,9 @@ impl GPUState {
|
|||
let system_object_scale = 1.0 / 600.0;
|
||||
let ship_scale = 1.0 / 10.0;
|
||||
|
||||
let player_world_object = state.world.get_ship(state.player_data).unwrap();
|
||||
let player_world_object = state.systemsim.get_ship(state.player_data).unwrap();
|
||||
let player_body = state
|
||||
.world
|
||||
.systemsim
|
||||
.get_rigid_body(player_world_object.rigid_body)
|
||||
.unwrap();
|
||||
|
||||
|
@ -103,7 +103,7 @@ impl GPUState {
|
|||
}
|
||||
|
||||
// Draw ships
|
||||
for (s, r) in state.world.iter_ship_body() {
|
||||
for (s, r) in state.systemsim.iter_ship_body() {
|
||||
// This will be None if this ship is dead.
|
||||
// Stays around while the physics system runs a collapse sequence
|
||||
let color = match state.data.get_ship(s.data_handle) {
|
||||
|
@ -291,7 +291,7 @@ impl GPUState {
|
|||
panic!("UI limit exceeded!")
|
||||
}
|
||||
|
||||
let player_world_object = state.world.get_ship(state.player_data).unwrap();
|
||||
let player_world_object = state.systemsim.get_ship(state.player_data).unwrap();
|
||||
|
||||
let data = state
|
||||
.data
|
||||
|
|
|
@ -3,13 +3,13 @@ use bytemuck;
|
|||
use cgmath::Point2;
|
||||
use galactica_constants;
|
||||
|
||||
use galactica_content::Content;
|
||||
use rand::seq::SliceRandom;
|
||||
use std::{iter, rc::Rc};
|
||||
use wgpu::{self, BufferAddress};
|
||||
use winit::{self, window::Window};
|
||||
|
||||
use crate::{
|
||||
content,
|
||||
globaluniform::{GlobalDataContent, GlobalUniform},
|
||||
pipeline::PipelineBuilder,
|
||||
starfield::Starfield,
|
||||
|
@ -27,7 +27,7 @@ use crate::{
|
|||
|
||||
// Additional implementaitons for GPUState
|
||||
mod hud;
|
||||
mod world;
|
||||
mod systemsim;
|
||||
|
||||
/// A high-level GPU wrapper. Consumes game state,
|
||||
/// produces pretty pictures.
|
||||
|
@ -108,7 +108,7 @@ fn preprocess_shader(
|
|||
|
||||
impl GPUState {
|
||||
/// Make a new GPUState that draws on `window`
|
||||
pub async fn new(window: Window, ct: &content::Content) -> Result<Self> {
|
||||
pub async fn new(window: Window, ct: &Content) -> Result<Self> {
|
||||
let window_size = window.inner_size();
|
||||
let window_aspect = window_size.width as f32 / window_size.height as f32;
|
||||
|
||||
|
@ -364,9 +364,9 @@ impl GPUState {
|
|||
// Order matters, it determines what is drawn on top.
|
||||
// The order inside ships and projectiles doesn't matter,
|
||||
// but ships should always be under projectiles.
|
||||
self.world_push_system(state, (clip_ne, clip_sw));
|
||||
self.world_push_ship(state, (clip_ne, clip_sw));
|
||||
self.world_push_projectile(state, (clip_ne, clip_sw));
|
||||
self.sysim_push_system(state, (clip_ne, clip_sw));
|
||||
self.sysim_push_ship(state, (clip_ne, clip_sw));
|
||||
self.sysim_push_projectile(state, (clip_ne, clip_sw));
|
||||
|
||||
self.hud_add_radar(state);
|
||||
self.hud_add_status(state);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
//! GPUState routines for drawing the world
|
||||
//! GPUState routines for drawing items in a systemsim
|
||||
|
||||
use bytemuck;
|
||||
use cgmath::{EuclideanSpace, InnerSpace, Point2, Vector2};
|
||||
use galactica_world::util;
|
||||
use galactica_systemsim::util;
|
||||
|
||||
use crate::{
|
||||
globaluniform::ObjectData,
|
||||
|
@ -11,14 +11,14 @@ use crate::{
|
|||
};
|
||||
|
||||
impl GPUState {
|
||||
pub(super) fn world_push_ship(
|
||||
pub(super) fn sysim_push_ship(
|
||||
&mut self,
|
||||
state: &RenderState,
|
||||
// NE and SW corners of screen
|
||||
screen_clip: (Point2<f32>, Point2<f32>),
|
||||
) {
|
||||
for s in state.world.iter_ships() {
|
||||
let r = state.world.get_rigid_body(s.rigid_body).unwrap();
|
||||
for s in state.systemsim.iter_ships() {
|
||||
let r = state.systemsim.get_rigid_body(s.rigid_body).unwrap();
|
||||
let ship_pos = util::rigidbody_position(&r);
|
||||
let ship_rot = util::rigidbody_rotation(r);
|
||||
let ship_ang = -ship_rot.angle(Vector2 { x: 0.0, y: 1.0 }); // TODO: inconsistent angles. Fix!
|
||||
|
@ -129,14 +129,14 @@ impl GPUState {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn world_push_projectile(
|
||||
pub(super) fn sysim_push_projectile(
|
||||
&mut self,
|
||||
state: &RenderState,
|
||||
// NE and SW corners of screen
|
||||
screen_clip: (Point2<f32>, Point2<f32>),
|
||||
) {
|
||||
for p in state.world.iter_projectiles() {
|
||||
let r = state.world.get_rigid_body(p.rigid_body).unwrap();
|
||||
for p in state.systemsim.iter_projectiles() {
|
||||
let r = state.systemsim.get_rigid_body(p.rigid_body).unwrap();
|
||||
let proj_pos = util::rigidbody_position(&r);
|
||||
let proj_rot = util::rigidbody_rotation(r);
|
||||
let proj_ang = -proj_rot.angle(Vector2 { x: 1.0, y: 0.0 });
|
||||
|
@ -201,7 +201,7 @@ impl GPUState {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn world_push_system(
|
||||
pub(super) fn sysim_push_system(
|
||||
&mut self,
|
||||
state: &RenderState,
|
||||
// NE and SW corners of screen
|
|
@ -17,7 +17,6 @@ mod texturearray;
|
|||
mod vertexbuffer;
|
||||
|
||||
pub use anchoredposition::PositionAnchor;
|
||||
use galactica_content as content;
|
||||
pub use gpustate::GPUState;
|
||||
pub use renderstate::RenderState;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use cgmath::Point2;
|
||||
use galactica_content::{Content, SystemHandle};
|
||||
use galactica_gameobject::{GameData, GameShipHandle};
|
||||
use galactica_world::{ParticleBuilder, World};
|
||||
use galactica_galaxy::{Galaxy, GxShipHandle};
|
||||
use galactica_systemsim::{ParticleBuilder, SystemSim};
|
||||
|
||||
/// Bundles parameters passed to a single call to GPUState::render
|
||||
pub struct RenderState<'a> {
|
||||
|
@ -9,7 +9,7 @@ pub struct RenderState<'a> {
|
|||
pub camera_pos: Point2<f32>,
|
||||
|
||||
/// Player ship data
|
||||
pub player_data: GameShipHandle,
|
||||
pub player_data: GxShipHandle,
|
||||
|
||||
/// The system we're currently in
|
||||
pub current_system: SystemHandle,
|
||||
|
@ -18,7 +18,7 @@ pub struct RenderState<'a> {
|
|||
pub camera_zoom: f32,
|
||||
|
||||
/// The world state to render
|
||||
pub world: &'a World,
|
||||
pub systemsim: &'a SystemSim,
|
||||
|
||||
// TODO: handle overflow. is it a problem?
|
||||
/// The current time, in seconds
|
||||
|
@ -28,7 +28,7 @@ pub struct RenderState<'a> {
|
|||
pub content: &'a Content,
|
||||
|
||||
/// Game data
|
||||
pub data: &'a GameData,
|
||||
pub data: &'a Galaxy,
|
||||
|
||||
/// Particles to spawn during this frame
|
||||
pub particles: &'a mut Vec<ParticleBuilder>,
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
use crate::{
|
||||
content,
|
||||
globaluniform::{AtlasArray, AtlasImageLocation, SpriteData, SpriteDataArray},
|
||||
};
|
||||
use crate::globaluniform::{AtlasArray, AtlasImageLocation, SpriteData, SpriteDataArray};
|
||||
use anyhow::Result;
|
||||
use bytemuck::Zeroable;
|
||||
use galactica_constants::ASSET_CACHE;
|
||||
use galactica_content::Content;
|
||||
use galactica_packer::SpriteAtlasImage;
|
||||
use image::GenericImageView;
|
||||
use std::{fs::File, io::Read, num::NonZeroU32, path::Path};
|
||||
|
@ -51,7 +49,7 @@ impl RawTexture {
|
|||
view_formats: &[],
|
||||
});
|
||||
|
||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
let view = texture.create_view(&Default::default());
|
||||
|
||||
queue.write_texture(
|
||||
wgpu::ImageCopyTexture {
|
||||
|
@ -91,7 +89,7 @@ pub struct TextureArray {
|
|||
}
|
||||
|
||||
impl TextureArray {
|
||||
pub fn new(device: &wgpu::Device, queue: &wgpu::Queue, ct: &content::Content) -> Result<Self> {
|
||||
pub fn new(device: &wgpu::Device, queue: &wgpu::Queue, ct: &Content) -> Result<Self> {
|
||||
// Load all textures
|
||||
let mut texture_data = Vec::new();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "galactica-world"
|
||||
description = "World interactions for Galactica"
|
||||
name = "galactica-systemsim"
|
||||
description = "Physics interactions for Galactica"
|
||||
categories = { workspace = true }
|
||||
keywords = { workspace = true }
|
||||
version = { workspace = true }
|
||||
|
@ -18,7 +18,7 @@ workspace = true
|
|||
|
||||
[dependencies]
|
||||
galactica-content = { workspace = true }
|
||||
galactica-gameobject = { workspace = true }
|
||||
galactica-galaxy = { workspace = true }
|
||||
|
||||
rapier2d = { workspace = true }
|
||||
nalgebra = { workspace = true }
|
|
@ -3,30 +3,30 @@
|
|||
mod null;
|
||||
mod point;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use galactica_gameobject::GameShipHandle;
|
||||
pub use null::*;
|
||||
pub use point::Point;
|
||||
|
||||
use galactica_galaxy::GxShipHandle;
|
||||
use rapier2d::dynamics::{RigidBodyHandle, RigidBodySet};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
objects::{ShipControls, ShipWorldObject},
|
||||
objects::{ShipControls, SySimShip},
|
||||
StepResources,
|
||||
};
|
||||
|
||||
/// Main behavior trait. Any struct that implements this
|
||||
/// Ship controller trait. Any struct that implements this
|
||||
/// may be used to control a ship.
|
||||
pub trait ShipBehavior {
|
||||
/// Update a ship's controls based on world state.
|
||||
pub trait ShipController {
|
||||
/// Update a ship's controls based on system state.
|
||||
/// This method does not return anything, it modifies
|
||||
/// the ship's controls in-place.
|
||||
fn update_controls(
|
||||
&mut self,
|
||||
res: &StepResources,
|
||||
rigid_bodies: &RigidBodySet,
|
||||
ships: &HashMap<GameShipHandle, ShipWorldObject>,
|
||||
ships: &HashMap<GxShipHandle, SySimShip>,
|
||||
this_ship: RigidBodyHandle,
|
||||
this_data: GameShipHandle,
|
||||
this_data: GxShipHandle,
|
||||
) -> ShipControls;
|
||||
}
|
|
@ -1,16 +1,15 @@
|
|||
use galactica_galaxy::GxShipHandle;
|
||||
use rapier2d::dynamics::{RigidBodyHandle, RigidBodySet};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use galactica_gameobject::GameShipHandle;
|
||||
use rapier2d::dynamics::{RigidBodyHandle, RigidBodySet};
|
||||
|
||||
use super::ShipBehavior;
|
||||
use super::ShipController;
|
||||
use crate::{
|
||||
objects::{ShipControls, ShipWorldObject},
|
||||
objects::{ShipControls, SySimShip},
|
||||
StepResources,
|
||||
};
|
||||
|
||||
/// The Null behaviors is assigned to objects that are not controlled by the computer.
|
||||
/// Most notably, the player's ship has a Null behavior.
|
||||
/// The Null controller is assigned to objects that are static or not controlled by the computer.
|
||||
/// Most notably, the player's ship has a Null controller.
|
||||
pub struct Null {}
|
||||
|
||||
impl Null {
|
||||
|
@ -20,14 +19,14 @@ impl Null {
|
|||
}
|
||||
}
|
||||
|
||||
impl ShipBehavior for Null {
|
||||
impl ShipController for Null {
|
||||
fn update_controls(
|
||||
&mut self,
|
||||
_res: &StepResources,
|
||||
_rigid_bodies: &RigidBodySet,
|
||||
_ships: &HashMap<GameShipHandle, ShipWorldObject>,
|
||||
_ships: &HashMap<GxShipHandle, SySimShip>,
|
||||
_this_ship: RigidBodyHandle,
|
||||
_this_data: GameShipHandle,
|
||||
_this_data: GxShipHandle,
|
||||
) -> ShipControls {
|
||||
ShipControls::new()
|
||||
}
|
|
@ -1,17 +1,16 @@
|
|||
use cgmath::{Deg, InnerSpace};
|
||||
use galactica_content::Relationship;
|
||||
use galactica_galaxy::GxShipHandle;
|
||||
use rapier2d::dynamics::{RigidBodyHandle, RigidBodySet};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::ShipController;
|
||||
use crate::{
|
||||
objects::{ShipControls, ShipWorldObject},
|
||||
objects::{ShipControls, SySimShip},
|
||||
util, StepResources,
|
||||
};
|
||||
use galactica_content as content;
|
||||
use galactica_gameobject::GameShipHandle;
|
||||
|
||||
use super::ShipBehavior;
|
||||
|
||||
/// "Point" ship behavior.
|
||||
/// "Point" ship controller.
|
||||
/// Point and shoot towards the nearest enemy.
|
||||
pub struct Point {}
|
||||
|
||||
|
@ -22,19 +21,19 @@ impl Point {
|
|||
}
|
||||
}
|
||||
|
||||
impl ShipBehavior for Point {
|
||||
impl ShipController for Point {
|
||||
fn update_controls(
|
||||
&mut self,
|
||||
res: &StepResources,
|
||||
rigid_bodies: &RigidBodySet,
|
||||
ships: &HashMap<GameShipHandle, ShipWorldObject>,
|
||||
ships: &HashMap<GxShipHandle, SySimShip>,
|
||||
this_ship: RigidBodyHandle,
|
||||
this_data: GameShipHandle,
|
||||
this_data: GxShipHandle,
|
||||
) -> ShipControls {
|
||||
let mut controls = ShipControls::new();
|
||||
|
||||
let this_rigidbody = rigid_bodies.get(this_ship).unwrap();
|
||||
let my_data = res.dt.get_ship(this_data).unwrap();
|
||||
let my_data = res.gx.get_ship(this_data).unwrap();
|
||||
let my_position = util::rigidbody_position(this_rigidbody);
|
||||
let my_rotation = util::rigidbody_rotation(this_rigidbody);
|
||||
let my_angvel = this_rigidbody.angvel();
|
||||
|
@ -44,10 +43,10 @@ impl ShipBehavior for Point {
|
|||
let mut hostile_ships = ships
|
||||
.values()
|
||||
.filter(|s| {
|
||||
let data = res.dt.get_ship(s.data_handle);
|
||||
let data = res.gx.get_ship(s.data_handle);
|
||||
if let Some(data) = data {
|
||||
match my_faction.relationships.get(&data.get_faction()).unwrap() {
|
||||
content::Relationship::Hostile => true,
|
||||
Relationship::Hostile => true,
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
|
@ -1,16 +1,15 @@
|
|||
#![warn(missing_docs)]
|
||||
|
||||
//! This module keeps track of the visible world.
|
||||
//! Ships, projectiles, collisions, etc.
|
||||
//! This module provides a physics-based simulation of one galaxy system.
|
||||
|
||||
pub mod behavior;
|
||||
pub mod controller;
|
||||
pub mod objects;
|
||||
mod particlebuilder;
|
||||
mod stepresources;
|
||||
mod systemsim;
|
||||
pub mod util;
|
||||
mod world;
|
||||
mod wrapper;
|
||||
|
||||
pub use particlebuilder::*;
|
||||
pub use stepresources::*;
|
||||
pub use world::World;
|
||||
pub use systemsim::SystemSim;
|
|
@ -0,0 +1,143 @@
|
|||
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Rad, Vector2, Zero};
|
||||
use galactica_content::{CollapseEvent, Ship, ShipHandle};
|
||||
use nalgebra::point;
|
||||
use rand::{rngs::ThreadRng, Rng};
|
||||
use rapier2d::{dynamics::RigidBody, geometry::Collider};
|
||||
|
||||
use crate::{util, ParticleBuilder, StepResources};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct ShipCollapseSequence {
|
||||
total_length: f32,
|
||||
time_elapsed: f32,
|
||||
rng: ThreadRng,
|
||||
}
|
||||
|
||||
impl ShipCollapseSequence {
|
||||
pub(super) fn new(total_length: f32) -> Self {
|
||||
Self {
|
||||
total_length,
|
||||
time_elapsed: 0.0,
|
||||
rng: rand::thread_rng(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Has this sequence been fully played out?
|
||||
pub(super) fn is_done(&self) -> bool {
|
||||
self.time_elapsed >= self.total_length
|
||||
}
|
||||
|
||||
/// Pick a random points inside a ship's collider
|
||||
fn random_in_ship(&mut self, ship_content: &Ship, collider: &Collider) -> Vector2<f32> {
|
||||
let mut y = 0.0;
|
||||
let mut x = 0.0;
|
||||
let mut a = false;
|
||||
while !a {
|
||||
y = self.rng.gen_range(-1.0..=1.0) * ship_content.size / 2.0;
|
||||
x = self.rng.gen_range(-1.0..=1.0) * ship_content.size * ship_content.sprite.aspect
|
||||
/ 2.0;
|
||||
a = collider.shape().contains_local_point(&point![x, y]);
|
||||
}
|
||||
Vector2 { x, y }
|
||||
}
|
||||
|
||||
/// Step this sequence `t` seconds
|
||||
pub(super) fn step(
|
||||
&mut self,
|
||||
res: &mut StepResources,
|
||||
ship_handle: ShipHandle,
|
||||
rigid_body: &mut RigidBody,
|
||||
collider: &mut Collider,
|
||||
) {
|
||||
let ship_content = res.ct.get_ship(ship_handle);
|
||||
let ship_pos = util::rigidbody_position(rigid_body);
|
||||
let ship_rot = util::rigidbody_rotation(rigid_body);
|
||||
let ship_ang = ship_rot.angle(Vector2 { x: 1.0, y: 0.0 });
|
||||
|
||||
// The fraction of this collapse sequence that has been played
|
||||
let frac_done = self.time_elapsed / self.total_length;
|
||||
|
||||
// Trigger collapse events
|
||||
for event in &ship_content.collapse.events {
|
||||
match event {
|
||||
CollapseEvent::Effect(event) => {
|
||||
if (event.time > self.time_elapsed && event.time <= self.time_elapsed + res.t)
|
||||
|| (event.time == 0.0 && self.time_elapsed == 0.0)
|
||||
{
|
||||
for spawner in &event.effects {
|
||||
let effect = res.ct.get_effect(spawner.effect);
|
||||
|
||||
for _ in 0..spawner.count as usize {
|
||||
let pos = if let Some(pos) = spawner.pos {
|
||||
pos.to_vec()
|
||||
} else {
|
||||
self.random_in_ship(ship_content, collider)
|
||||
};
|
||||
let pos = ship_pos
|
||||
+ (Matrix2::from_angle(-ship_ang - Rad::from(Deg(90.0))) * pos);
|
||||
|
||||
let velocity = rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
||||
|
||||
res.particles.push(ParticleBuilder::from_content(
|
||||
effect,
|
||||
pos,
|
||||
Rad::zero(),
|
||||
Vector2 {
|
||||
x: velocity.x,
|
||||
y: velocity.y,
|
||||
},
|
||||
Vector2::zero(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create collapse effects
|
||||
for spawner in &ship_content.collapse.effects {
|
||||
let effect = res.ct.get_effect(spawner.effect);
|
||||
|
||||
// Probability of adding a particle this frame.
|
||||
// The area of this function over [0, 1] should be 1.
|
||||
let pdf = |x: f32| {
|
||||
let f = 0.2;
|
||||
let y = if x < (1.0 - f) {
|
||||
let x = x / (1.0 - f);
|
||||
(x * x + 0.2) * 1.8 - f
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
return y;
|
||||
};
|
||||
|
||||
let p_add = (res.t / self.total_length) * pdf(frac_done) * spawner.count;
|
||||
|
||||
if self.rng.gen_range(0.0..=1.0) <= p_add {
|
||||
let pos = if let Some(pos) = spawner.pos {
|
||||
pos.to_vec()
|
||||
} else {
|
||||
self.random_in_ship(ship_content, collider)
|
||||
};
|
||||
|
||||
// Position, adjusted for ship rotation
|
||||
let pos = ship_pos + Matrix2::from_angle(-ship_ang - Rad::from(Deg(90.0))) * pos;
|
||||
let vel = rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
||||
|
||||
res.particles.push(ParticleBuilder {
|
||||
sprite: effect.sprite,
|
||||
pos,
|
||||
velocity: Vector2 { x: vel.x, y: vel.y },
|
||||
angle: Rad::zero(),
|
||||
angvel: Rad::zero(),
|
||||
lifetime: effect.lifetime,
|
||||
size: effect.size,
|
||||
fade: 0.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.time_elapsed += res.t;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
//! This module contains game objects that may interact with the physics engine.
|
||||
mod collapse;
|
||||
mod projectile;
|
||||
mod ship;
|
||||
|
||||
pub use projectile::ProjectileWorldObject;
|
||||
pub use ship::{ShipControls, ShipWorldObject};
|
||||
pub use projectile::SySimProjectile;
|
||||
pub use ship::{ShipControls, SySimShip};
|
|
@ -1,19 +1,18 @@
|
|||
use galactica_content::{FactionHandle, Projectile};
|
||||
use rand::Rng;
|
||||
use rapier2d::{dynamics::RigidBodyHandle, geometry::ColliderHandle};
|
||||
|
||||
use galactica_content as content;
|
||||
|
||||
/// A single projectile in the world
|
||||
/// A single projectile in this sim
|
||||
#[derive(Debug)]
|
||||
pub struct ProjectileWorldObject {
|
||||
pub struct SySimProjectile {
|
||||
/// This projectile's game data
|
||||
pub content: content::Projectile,
|
||||
pub content: Projectile,
|
||||
|
||||
/// The remaining lifetime of this projectile, in seconds
|
||||
pub lifetime: f32,
|
||||
|
||||
/// The faction this projectile belongs to
|
||||
pub faction: content::FactionHandle,
|
||||
pub faction: FactionHandle,
|
||||
|
||||
/// This projectile's rigidbody
|
||||
pub rigid_body: RigidBodyHandle,
|
||||
|
@ -25,18 +24,18 @@ pub struct ProjectileWorldObject {
|
|||
pub size_rng: f32,
|
||||
}
|
||||
|
||||
impl ProjectileWorldObject {
|
||||
impl SySimProjectile {
|
||||
/// Create a new projectile
|
||||
pub fn new(
|
||||
content: content::Projectile, // TODO: use a handle
|
||||
content: Projectile, // TODO: use a handle
|
||||
rigid_body: RigidBodyHandle,
|
||||
faction: content::FactionHandle,
|
||||
faction: FactionHandle,
|
||||
collider: ColliderHandle,
|
||||
) -> Self {
|
||||
let mut rng = rand::thread_rng();
|
||||
let size_rng = content.size_rng;
|
||||
let lifetime = content.lifetime;
|
||||
ProjectileWorldObject {
|
||||
SySimProjectile {
|
||||
rigid_body,
|
||||
collider,
|
||||
content,
|
|
@ -1,16 +1,16 @@
|
|||
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Rad, Vector2, Zero};
|
||||
use content::{FactionHandle, ShipHandle};
|
||||
use galactica_content::{Content, FactionHandle};
|
||||
use galactica_galaxy::GxShipHandle;
|
||||
use nalgebra::{point, vector};
|
||||
use object::GameShipHandle;
|
||||
use rand::{rngs::ThreadRng, Rng};
|
||||
use rand::Rng;
|
||||
use rapier2d::{
|
||||
dynamics::{RigidBody, RigidBodyHandle},
|
||||
geometry::{Collider, ColliderHandle},
|
||||
};
|
||||
|
||||
use crate::{util, ParticleBuilder, StepResources};
|
||||
use galactica_content as content;
|
||||
use galactica_gameobject as object;
|
||||
|
||||
use super::collapse::ShipCollapseSequence;
|
||||
|
||||
/// A ship's controls
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -40,149 +40,9 @@ impl ShipControls {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ShipCollapseSequence {
|
||||
total_length: f32,
|
||||
time_elapsed: f32,
|
||||
rng: ThreadRng,
|
||||
}
|
||||
|
||||
impl ShipCollapseSequence {
|
||||
fn new(total_length: f32) -> Self {
|
||||
Self {
|
||||
total_length,
|
||||
time_elapsed: 0.0,
|
||||
rng: rand::thread_rng(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Has this sequence been fully played out?
|
||||
fn is_done(&self) -> bool {
|
||||
self.time_elapsed >= self.total_length
|
||||
}
|
||||
|
||||
/// Pick a random points inside a ship's collider
|
||||
fn random_in_ship(
|
||||
&mut self,
|
||||
ship_content: &content::Ship,
|
||||
collider: &Collider,
|
||||
) -> Vector2<f32> {
|
||||
let mut y = 0.0;
|
||||
let mut x = 0.0;
|
||||
let mut a = false;
|
||||
while !a {
|
||||
y = self.rng.gen_range(-1.0..=1.0) * ship_content.size / 2.0;
|
||||
x = self.rng.gen_range(-1.0..=1.0) * ship_content.size * ship_content.sprite.aspect
|
||||
/ 2.0;
|
||||
a = collider.shape().contains_local_point(&point![x, y]);
|
||||
}
|
||||
Vector2 { x, y }
|
||||
}
|
||||
|
||||
/// Step this sequence `t` seconds
|
||||
fn step(
|
||||
&mut self,
|
||||
res: &mut StepResources,
|
||||
ship_handle: ShipHandle,
|
||||
rigid_body: &mut RigidBody,
|
||||
collider: &mut Collider,
|
||||
) {
|
||||
let ship_content = res.ct.get_ship(ship_handle);
|
||||
let ship_pos = util::rigidbody_position(rigid_body);
|
||||
let ship_rot = util::rigidbody_rotation(rigid_body);
|
||||
let ship_ang = ship_rot.angle(Vector2 { x: 1.0, y: 0.0 });
|
||||
|
||||
// The fraction of this collapse sequence that has been played
|
||||
let frac_done = self.time_elapsed / self.total_length;
|
||||
|
||||
// Trigger collapse events
|
||||
for event in &ship_content.collapse.events {
|
||||
match event {
|
||||
content::CollapseEvent::Effect(event) => {
|
||||
if (event.time > self.time_elapsed && event.time <= self.time_elapsed + res.t)
|
||||
|| (event.time == 0.0 && self.time_elapsed == 0.0)
|
||||
{
|
||||
for spawner in &event.effects {
|
||||
let effect = res.ct.get_effect(spawner.effect);
|
||||
|
||||
for _ in 0..spawner.count as usize {
|
||||
let pos = if let Some(pos) = spawner.pos {
|
||||
pos.to_vec()
|
||||
} else {
|
||||
self.random_in_ship(ship_content, collider)
|
||||
};
|
||||
let pos = ship_pos
|
||||
+ (Matrix2::from_angle(-ship_ang - Rad::from(Deg(90.0))) * pos);
|
||||
|
||||
let velocity = rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
||||
|
||||
res.particles.push(ParticleBuilder::from_content(
|
||||
effect,
|
||||
pos,
|
||||
Rad::zero(),
|
||||
Vector2 {
|
||||
x: velocity.x,
|
||||
y: velocity.y,
|
||||
},
|
||||
Vector2::zero(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create collapse effects
|
||||
for spawner in &ship_content.collapse.effects {
|
||||
let effect = res.ct.get_effect(spawner.effect);
|
||||
|
||||
// Probability of adding a particle this frame.
|
||||
// The area of this function over [0, 1] should be 1.
|
||||
let pdf = |x: f32| {
|
||||
let f = 0.2;
|
||||
let y = if x < (1.0 - f) {
|
||||
let x = x / (1.0 - f);
|
||||
(x * x + 0.2) * 1.8 - f
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
return y;
|
||||
};
|
||||
|
||||
let p_add = (res.t / self.total_length) * pdf(frac_done) * spawner.count;
|
||||
|
||||
if self.rng.gen_range(0.0..=1.0) <= p_add {
|
||||
let pos = if let Some(pos) = spawner.pos {
|
||||
pos.to_vec()
|
||||
} else {
|
||||
self.random_in_ship(ship_content, collider)
|
||||
};
|
||||
|
||||
// Position, adjusted for ship rotation
|
||||
let pos = ship_pos + Matrix2::from_angle(-ship_ang - Rad::from(Deg(90.0))) * pos;
|
||||
let vel = rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
||||
|
||||
res.particles.push(ParticleBuilder {
|
||||
sprite: effect.sprite,
|
||||
pos,
|
||||
velocity: Vector2 { x: vel.x, y: vel.y },
|
||||
angle: Rad::zero(),
|
||||
angvel: Rad::zero(),
|
||||
lifetime: effect.lifetime,
|
||||
size: effect.size,
|
||||
fade: 0.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.time_elapsed += res.t;
|
||||
}
|
||||
}
|
||||
|
||||
/// A ship instance in the physics system
|
||||
#[derive(Debug)]
|
||||
pub struct ShipWorldObject {
|
||||
pub struct SySimShip {
|
||||
/// This ship's physics handle
|
||||
pub rigid_body: RigidBodyHandle,
|
||||
|
||||
|
@ -190,7 +50,7 @@ pub struct ShipWorldObject {
|
|||
pub collider: ColliderHandle,
|
||||
|
||||
/// This ship's game data
|
||||
pub data_handle: GameShipHandle,
|
||||
pub data_handle: GxShipHandle,
|
||||
|
||||
/// This ship's controls
|
||||
pub(crate) controls: ShipControls,
|
||||
|
@ -205,17 +65,17 @@ pub struct ShipWorldObject {
|
|||
faction: FactionHandle,
|
||||
}
|
||||
|
||||
impl ShipWorldObject {
|
||||
impl SySimShip {
|
||||
/// Make a new ship
|
||||
pub(crate) fn new(
|
||||
ct: &content::Content,
|
||||
data_handle: GameShipHandle,
|
||||
ct: &Content,
|
||||
data_handle: GxShipHandle,
|
||||
faction: FactionHandle,
|
||||
rigid_body: RigidBodyHandle,
|
||||
collider: ColliderHandle,
|
||||
) -> Self {
|
||||
let ship_content = ct.get_ship(data_handle.content_handle());
|
||||
ShipWorldObject {
|
||||
SySimShip {
|
||||
rigid_body,
|
||||
collider,
|
||||
data_handle,
|
||||
|
@ -237,7 +97,7 @@ impl ShipWorldObject {
|
|||
rigid_body: &mut RigidBody,
|
||||
collider: &mut Collider,
|
||||
) {
|
||||
let ship_data = res.dt.get_ship(self.data_handle);
|
||||
let ship_data = res.gx.get_ship(self.data_handle);
|
||||
if ship_data.is_none() {
|
||||
// If ship data is none, it has been removed because the ship has been destroyed.
|
||||
// play collapse sequence.
|
||||
|
@ -259,7 +119,7 @@ impl ShipWorldObject {
|
|||
rigid_body: &mut RigidBody,
|
||||
collider: &mut Collider,
|
||||
) {
|
||||
let ship = res.dt.get_ship(self.data_handle).unwrap();
|
||||
let ship = res.gx.get_ship(self.data_handle).unwrap();
|
||||
let ship_content = res.ct.get_ship(self.data_handle.content_handle());
|
||||
let ship_pos = util::rigidbody_position(&rigid_body);
|
||||
let ship_rot = util::rigidbody_rotation(rigid_body);
|
||||
|
@ -328,7 +188,7 @@ impl ShipWorldObject {
|
|||
}
|
||||
}
|
||||
|
||||
impl ShipWorldObject {
|
||||
impl SySimShip {
|
||||
/// Get this ship's control state
|
||||
pub fn get_controls(&self) -> &ShipControls {
|
||||
&self.controls
|
|
@ -1,12 +1,12 @@
|
|||
use cgmath::{Matrix2, Point2, Rad, Vector2};
|
||||
use galactica_content as content;
|
||||
use galactica_content::{Effect, SpriteHandle};
|
||||
use rand::Rng;
|
||||
|
||||
/// Instructions to create a new particle
|
||||
#[derive(Debug)]
|
||||
pub struct ParticleBuilder {
|
||||
/// The sprite to use for this particle
|
||||
pub sprite: content::SpriteHandle,
|
||||
pub sprite: SpriteHandle,
|
||||
|
||||
/// This object's center, in world coordinates.
|
||||
pub pos: Point2<f32>,
|
||||
|
@ -34,7 +34,7 @@ pub struct ParticleBuilder {
|
|||
impl ParticleBuilder {
|
||||
/// Create a ParticleBuilder from an Effect
|
||||
pub fn from_content(
|
||||
effect: &content::Effect,
|
||||
effect: &Effect,
|
||||
pos: Point2<f32>,
|
||||
parent_angle: Rad<f32>,
|
||||
parent_velocity: Vector2<f32>,
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{objects::ShipControls, ParticleBuilder};
|
||||
use galactica_content::Content;
|
||||
use galactica_gameobject::{GameData, GameShipHandle};
|
||||
use galactica_galaxy::{Galaxy, GxShipHandle};
|
||||
|
||||
/// External resources we need to compute time steps
|
||||
#[derive(Debug)]
|
||||
|
@ -9,7 +9,7 @@ pub struct StepResources<'a> {
|
|||
pub ct: &'a Content,
|
||||
|
||||
/// Game data
|
||||
pub dt: &'a mut GameData,
|
||||
pub gx: &'a mut Galaxy,
|
||||
|
||||
/// Length of time step
|
||||
pub t: f32,
|
||||
|
@ -21,5 +21,5 @@ pub struct StepResources<'a> {
|
|||
pub player_controls: ShipControls,
|
||||
|
||||
/// The ship that the player controls
|
||||
pub player: GameShipHandle,
|
||||
pub player: GxShipHandle,
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Point2, Rad, Vector2, Zero};
|
||||
use content::{GunPoint, OutfitHandle};
|
||||
use crossbeam::channel::Receiver;
|
||||
use galactica_content::{
|
||||
Content, GunPoint, OutfitHandle, ProjectileCollider, Relationship, SystemHandle,
|
||||
};
|
||||
use galactica_galaxy::{ship::GxShip, Galaxy, GxShipHandle};
|
||||
use nalgebra::{point, vector};
|
||||
use object::{ship::Ship, GameData, GameShipHandle};
|
||||
use rand::Rng;
|
||||
use rapier2d::{
|
||||
dynamics::{RigidBody, RigidBodyBuilder, RigidBodyHandle},
|
||||
|
@ -12,37 +14,32 @@ use rapier2d::{
|
|||
use std::{collections::HashMap, f32::consts::PI};
|
||||
|
||||
use crate::{
|
||||
behavior::{self, ShipBehavior},
|
||||
controller::{self, ShipController},
|
||||
objects,
|
||||
objects::{ProjectileWorldObject, ShipWorldObject},
|
||||
objects::{SySimProjectile, SySimShip},
|
||||
util,
|
||||
wrapper::Wrapper,
|
||||
ParticleBuilder, StepResources,
|
||||
};
|
||||
use galactica_content as content;
|
||||
use galactica_gameobject as object;
|
||||
|
||||
/// Manages the physics state of one system
|
||||
pub struct World {
|
||||
/// The system this world is attached to
|
||||
_system: content::SystemHandle,
|
||||
pub struct SystemSim {
|
||||
/// The system this sim is attached to
|
||||
_system: SystemHandle,
|
||||
|
||||
wrapper: Wrapper,
|
||||
projectiles: HashMap<ColliderHandle, objects::ProjectileWorldObject>,
|
||||
ships: HashMap<GameShipHandle, objects::ShipWorldObject>,
|
||||
ship_behaviors: HashMap<GameShipHandle, Box<dyn ShipBehavior>>,
|
||||
collider_ship_table: HashMap<ColliderHandle, GameShipHandle>,
|
||||
projectiles: HashMap<ColliderHandle, objects::SySimProjectile>,
|
||||
ships: HashMap<GxShipHandle, objects::SySimShip>,
|
||||
ship_behaviors: HashMap<GxShipHandle, Box<dyn ShipController>>,
|
||||
collider_ship_table: HashMap<ColliderHandle, GxShipHandle>,
|
||||
|
||||
collision_handler: ChannelEventCollector,
|
||||
collision_queue: Receiver<CollisionEvent>,
|
||||
}
|
||||
|
||||
// Private methods
|
||||
impl<'a> World {
|
||||
fn remove_projectile(
|
||||
&mut self,
|
||||
c: ColliderHandle,
|
||||
) -> Option<(RigidBody, ProjectileWorldObject)> {
|
||||
impl<'a> SystemSim {
|
||||
fn remove_projectile(&mut self, c: ColliderHandle) -> Option<(RigidBody, SySimProjectile)> {
|
||||
let p = match self.projectiles.remove(&c) {
|
||||
Some(p) => p,
|
||||
None => return None,
|
||||
|
@ -104,9 +101,9 @@ impl<'a> World {
|
|||
let f = res.ct.get_faction(projectile.faction);
|
||||
let r = f.relationships.get(&ship.get_faction()).unwrap();
|
||||
let destory_projectile = match r {
|
||||
content::Relationship::Hostile => {
|
||||
Relationship::Hostile => {
|
||||
// We only apply damage if the target ship is alive
|
||||
if let Some(ship_d) = res.dt.get_ship_mut(ship.data_handle) {
|
||||
if let Some(ship_d) = res.gx.get_ship_mut(ship.data_handle) {
|
||||
ship_d.apply_damage(projectile.content.damage);
|
||||
}
|
||||
true
|
||||
|
@ -169,9 +166,9 @@ impl<'a> World {
|
|||
}
|
||||
|
||||
// Public methods
|
||||
impl World {
|
||||
impl SystemSim {
|
||||
/// Create a new physics system
|
||||
pub fn new(ct: &content::Content, dt: &GameData, system: content::SystemHandle) -> Self {
|
||||
pub fn new(ct: &Content, gx: &Galaxy, system: SystemHandle) -> Self {
|
||||
let (collision_send, collision_queue) = crossbeam::channel::unbounded();
|
||||
let (contact_force_send, _) = crossbeam::channel::unbounded();
|
||||
|
||||
|
@ -188,9 +185,9 @@ impl World {
|
|||
|
||||
// TODO: guarantee not touching
|
||||
// TODO: add, remove ships each tick
|
||||
// Maybe store position in gamedata?
|
||||
// Maybe store position in galaxy crate?
|
||||
let mut rng = rand::thread_rng();
|
||||
for s in dt.iter_ships() {
|
||||
for s in gx.iter_ships() {
|
||||
w.add_ship(
|
||||
ct,
|
||||
s,
|
||||
|
@ -205,7 +202,7 @@ impl World {
|
|||
}
|
||||
|
||||
/// Add a ship to this physics system
|
||||
pub fn add_ship(&mut self, ct: &content::Content, ship: &Ship, position: Point2<f32>) {
|
||||
pub fn add_ship(&mut self, ct: &Content, ship: &GxShip, position: Point2<f32>) {
|
||||
let ship_content = ct.get_ship(ship.get_content());
|
||||
let cl = ColliderBuilder::convex_decomposition(
|
||||
&ship_content.collision.points[..],
|
||||
|
@ -232,10 +229,10 @@ impl World {
|
|||
|
||||
self.collider_ship_table.insert(c, ship.get_handle());
|
||||
self.ship_behaviors
|
||||
.insert(ship.get_handle(), Box::new(behavior::Point::new()));
|
||||
.insert(ship.get_handle(), Box::new(controller::Point::new()));
|
||||
self.ships.insert(
|
||||
ship.get_handle(),
|
||||
objects::ShipWorldObject::new(ct, ship.get_handle(), ship.get_faction(), r, c),
|
||||
objects::SySimShip::new(ct, ship.get_handle(), ship.get_faction(), r, c),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -260,7 +257,7 @@ impl World {
|
|||
|
||||
// Short-circuit continue if this ship isn't in game data
|
||||
// (which means it's playing a collapse sequence)
|
||||
if res.dt.get_ship(*handle).is_none() {
|
||||
if res.gx.get_ship(*handle).is_none() {
|
||||
let ship_object = self.ships.get_mut(handle).unwrap();
|
||||
ship_object.step(
|
||||
res,
|
||||
|
@ -296,7 +293,7 @@ impl World {
|
|||
|
||||
// If we're firing, try to fire each gun
|
||||
if ship_object.controls.guns {
|
||||
let ship_data = res.dt.get_ship_mut(ship_object.data_handle).unwrap();
|
||||
let ship_data = res.gx.get_ship_mut(ship_object.data_handle).unwrap();
|
||||
|
||||
// TODO: don't allocate here. This is a hack to satisfy the borrow checker,
|
||||
// convert this to a refcell or do the replace dance.
|
||||
|
@ -329,7 +326,7 @@ impl World {
|
|||
let mut rng = rand::thread_rng();
|
||||
let rigid_body = self.get_rigid_body(rigid_body).unwrap();
|
||||
|
||||
let ship_dat = res.dt.get_ship(ship_dat).unwrap();
|
||||
let ship_dat = res.gx.get_ship(ship_dat).unwrap();
|
||||
let ship_pos = util::rigidbody_position(rigid_body);
|
||||
let ship_rot = util::rigidbody_rotation(rigid_body);
|
||||
let ship_vel = util::rigidbody_velocity(rigid_body);
|
||||
|
@ -361,7 +358,7 @@ impl World {
|
|||
.build();
|
||||
|
||||
let collider = match &outfit.projectile.collider {
|
||||
content::ProjectileCollider::Ball(b) => ColliderBuilder::ball(b.radius)
|
||||
ProjectileCollider::Ball(b) => ColliderBuilder::ball(b.radius)
|
||||
.sensor(true)
|
||||
.active_events(ActiveEvents::COLLISION_EVENTS)
|
||||
.build(),
|
||||
|
@ -376,7 +373,7 @@ impl World {
|
|||
|
||||
self.projectiles.insert(
|
||||
collider.clone(),
|
||||
ProjectileWorldObject::new(
|
||||
SySimProjectile::new(
|
||||
outfit.projectile.clone(),
|
||||
rigid_body,
|
||||
ship_dat.get_faction(),
|
||||
|
@ -464,9 +461,9 @@ impl World {
|
|||
}
|
||||
|
||||
// Public getters
|
||||
impl World {
|
||||
impl SystemSim {
|
||||
/// Get a ship physics object
|
||||
pub fn get_ship(&self, ship: GameShipHandle) -> Option<&ShipWorldObject> {
|
||||
pub fn get_ship(&self, ship: GxShipHandle) -> Option<&SySimShip> {
|
||||
self.ships.get(&ship)
|
||||
}
|
||||
|
||||
|
@ -481,21 +478,19 @@ impl World {
|
|||
}
|
||||
|
||||
/// Iterate over all ships in this physics system
|
||||
pub fn iter_ship_body(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (&objects::ShipWorldObject, &RigidBody)> + '_ {
|
||||
pub fn iter_ship_body(&self) -> impl Iterator<Item = (&objects::SySimShip, &RigidBody)> + '_ {
|
||||
self.ships
|
||||
.values()
|
||||
.map(|x| (x, self.wrapper.rigid_body_set.get(x.rigid_body).unwrap()))
|
||||
}
|
||||
|
||||
/// Iterate over all ships in this physics system
|
||||
pub fn iter_ships(&self) -> impl Iterator<Item = &ShipWorldObject> + '_ {
|
||||
pub fn iter_ships(&self) -> impl Iterator<Item = &SySimShip> + '_ {
|
||||
self.ships.values()
|
||||
}
|
||||
|
||||
/// Iterate over all ships in this physics system
|
||||
pub fn iter_projectiles(&self) -> impl Iterator<Item = &ProjectileWorldObject> + '_ {
|
||||
pub fn iter_projectiles(&self) -> impl Iterator<Item = &SySimProjectile> + '_ {
|
||||
self.projectiles.values()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue