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