From eaa8a7383c27ab86e2ea398fdbcab6a8fb802220 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 9 Jan 2024 21:45:30 -0800 Subject: [PATCH] Renamed a few objects --- Cargo.lock | 14 +- Cargo.toml | 4 +- crates/galactica/Cargo.toml | 4 +- crates/galactica/src/game.rs | 91 +++++----- crates/galactica/src/main.rs | 13 +- crates/{gameobject => galaxy}/Cargo.toml | 2 +- .../src/gamedata.rs => galaxy/src/galaxy.rs} | 40 ++--- crates/{gameobject => galaxy}/src/handles.rs | 10 +- crates/galaxy/src/lib.rs | 11 ++ crates/{gameobject => galaxy}/src/ship/mod.rs | 0 .../src/ship/outfitset.rs | 9 +- .../src/ship/personality.rs | 3 +- .../{gameobject => galaxy}/src/ship/ship.rs | 41 +++-- crates/gameobject/src/lib.rs | 12 -- crates/render/Cargo.toml | 4 +- crates/render/src/gpustate/hud.rs | 10 +- crates/render/src/gpustate/mod.rs | 12 +- .../src/gpustate/{world.rs => systemsim.rs} | 18 +- crates/render/src/lib.rs | 1 - crates/render/src/renderstate.rs | 10 +- crates/render/src/texturearray.rs | 10 +- crates/{world => systemsim}/Cargo.toml | 6 +- .../src/controller}/mod.rs | 18 +- .../src/controller}/null.rs | 19 +- .../src/controller}/point.rs | 23 ++- crates/{world => systemsim}/src/lib.rs | 9 +- crates/systemsim/src/objects/collapse.rs | 143 +++++++++++++++ .../{world => systemsim}/src/objects/mod.rs | 5 +- .../src/objects/projectile.rs | 19 +- .../{world => systemsim}/src/objects/ship.rs | 168 ++---------------- .../src/particlebuilder.rs | 6 +- .../{world => systemsim}/src/stepresources.rs | 6 +- .../world.rs => systemsim/src/systemsim.rs} | 73 ++++---- crates/{world => systemsim}/src/util.rs | 0 crates/{world => systemsim}/src/wrapper.rs | 0 35 files changed, 399 insertions(+), 415 deletions(-) rename crates/{gameobject => galaxy}/Cargo.toml (94%) rename crates/{gameobject/src/gamedata.rs => galaxy/src/galaxy.rs} (65%) rename crates/{gameobject => galaxy}/src/handles.rs (79%) create mode 100644 crates/galaxy/src/lib.rs rename crates/{gameobject => galaxy}/src/ship/mod.rs (100%) rename crates/{gameobject => galaxy}/src/ship/outfitset.rs (94%) rename crates/{gameobject => galaxy}/src/ship/personality.rs (71%) rename crates/{gameobject => galaxy}/src/ship/ship.rs (80%) delete mode 100644 crates/gameobject/src/lib.rs rename crates/render/src/gpustate/{world.rs => systemsim.rs} (94%) rename crates/{world => systemsim}/Cargo.toml (83%) rename crates/{world/src/behavior => systemsim/src/controller}/mod.rs (62%) rename crates/{world/src/behavior => systemsim/src/controller}/null.rs (51%) rename crates/{world/src/behavior => systemsim/src/controller}/point.rs (82%) rename crates/{world => systemsim}/src/lib.rs (53%) create mode 100644 crates/systemsim/src/objects/collapse.rs rename crates/{world => systemsim}/src/objects/mod.rs (54%) rename crates/{world => systemsim}/src/objects/projectile.rs (75%) rename crates/{world => systemsim}/src/objects/ship.rs (52%) rename crates/{world => systemsim}/src/particlebuilder.rs (95%) rename crates/{world => systemsim}/src/stepresources.rs (80%) rename crates/{world/src/world.rs => systemsim/src/systemsim.rs} (86%) rename crates/{world => systemsim}/src/util.rs (100%) rename crates/{world => systemsim}/src/wrapper.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 2a1d270..1d6acb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 758e115..7d6e05e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } diff --git a/crates/galactica/Cargo.toml b/crates/galactica/Cargo.toml index 635d058..bc1cc8b 100644 --- a/crates/galactica/Cargo.toml +++ b/crates/galactica/Cargo.toml @@ -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 } diff --git a/crates/galactica/src/game.rs b/crates/galactica/src/game.rs index 9a5504c..598de4c 100644 --- a/crates/galactica/src/game.rs +++ b/crates/galactica/src/game.rs @@ -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, } 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 }, } } } diff --git a/crates/galactica/src/main.rs b/crates/galactica/src/main.rs index b874b77..fbfd2f7 100644 --- a/crates/galactica/src/main.rs +++ b/crates/galactica/src/main.rs @@ -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(); diff --git a/crates/gameobject/Cargo.toml b/crates/galaxy/Cargo.toml similarity index 94% rename from crates/gameobject/Cargo.toml rename to crates/galaxy/Cargo.toml index 6b01502..2f8f817 100644 --- a/crates/gameobject/Cargo.toml +++ b/crates/galaxy/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "galactica-gameobject" +name = "galactica-galaxy" description = "Galactica's game data manager" categories = { workspace = true } keywords = { workspace = true } diff --git a/crates/gameobject/src/gamedata.rs b/crates/galaxy/src/galaxy.rs similarity index 65% rename from crates/gameobject/src/gamedata.rs rename to crates/galaxy/src/galaxy.rs index fa7503f..5176956 100644 --- a/crates/gameobject/src/gamedata.rs +++ b/crates/galaxy/src/galaxy.rs @@ -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, + ships: HashMap, /// Ships indexed by the system they're in. /// A ship must always be in exactly one system. - system_ship_table: HashMap>, + system_ship_table: HashMap>, /// Systems indexed by which ships they contain. /// A ship must always be in exactly one system. - ship_system_table: HashMap, + ship_system_table: HashMap, } -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 { + pub fn iter_ships(&self) -> impl Iterator { self.ships.values() } } diff --git a/crates/gameobject/src/handles.rs b/crates/galaxy/src/handles.rs similarity index 79% rename from crates/gameobject/src/handles.rs rename to crates/galaxy/src/handles.rs index 7e8800a..bc51e3f 100644 --- a/crates/gameobject/src/handles.rs +++ b/crates/galaxy/src/handles.rs @@ -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(&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) } diff --git a/crates/galaxy/src/lib.rs b/crates/galaxy/src/lib.rs new file mode 100644 index 0000000..4696b55 --- /dev/null +++ b/crates/galaxy/src/lib.rs @@ -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::*; diff --git a/crates/gameobject/src/ship/mod.rs b/crates/galaxy/src/ship/mod.rs similarity index 100% rename from crates/gameobject/src/ship/mod.rs rename to crates/galaxy/src/ship/mod.rs diff --git a/crates/gameobject/src/ship/outfitset.rs b/crates/galaxy/src/ship/outfitset.rs similarity index 94% rename from crates/gameobject/src/ship/outfitset.rs rename to crates/galaxy/src/ship/outfitset.rs index d7df554..5314faf 100644 --- a/crates/gameobject/src/ship/outfitset.rs +++ b/crates/galaxy/src/ship/outfitset.rs @@ -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 { + pub fn get_flare_sprite(&self, ct: &Content) -> Option { for i in self.outfits.keys() { let c = ct.get_outfit(*i); if c.engine_flare_sprite.is_some() { diff --git a/crates/gameobject/src/ship/personality.rs b/crates/galaxy/src/ship/personality.rs similarity index 71% rename from crates/gameobject/src/ship/personality.rs rename to crates/galaxy/src/ship/personality.rs index 031d8b5..a7d3e34 100644 --- a/crates/gameobject/src/ship/personality.rs +++ b/crates/galaxy/src/ship/personality.rs @@ -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 diff --git a/crates/gameobject/src/ship/ship.rs b/crates/galaxy/src/ship/ship.rs similarity index 80% rename from crates/gameobject/src/ship/ship.rs rename to crates/galaxy/src/ship/ship.rs index db66924..446f790 100644 --- a/crates/gameobject/src/ship/ship.rs +++ b/crates/galaxy/src/ship/ship.rs @@ -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 } } diff --git a/crates/gameobject/src/lib.rs b/crates/gameobject/src/lib.rs deleted file mode 100644 index adfd51b..0000000 --- a/crates/gameobject/src/lib.rs +++ /dev/null @@ -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::*; diff --git a/crates/render/Cargo.toml b/crates/render/Cargo.toml index 125a157..efc9139 100644 --- a/crates/render/Cargo.toml +++ b/crates/render/Cargo.toml @@ -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 } diff --git a/crates/render/src/gpustate/hud.rs b/crates/render/src/gpustate/hud.rs index c71a783..312c5df 100644 --- a/crates/render/src/gpustate/hud.rs +++ b/crates/render/src/gpustate/hud.rs @@ -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 diff --git a/crates/render/src/gpustate/mod.rs b/crates/render/src/gpustate/mod.rs index 65fc0cb..4382ccc 100644 --- a/crates/render/src/gpustate/mod.rs +++ b/crates/render/src/gpustate/mod.rs @@ -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 { + pub async fn new(window: Window, ct: &Content) -> Result { 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); diff --git a/crates/render/src/gpustate/world.rs b/crates/render/src/gpustate/systemsim.rs similarity index 94% rename from crates/render/src/gpustate/world.rs rename to crates/render/src/gpustate/systemsim.rs index 41d98bb..0e1ad4f 100644 --- a/crates/render/src/gpustate/world.rs +++ b/crates/render/src/gpustate/systemsim.rs @@ -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, Point2), ) { - 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, Point2), ) { - 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 diff --git a/crates/render/src/lib.rs b/crates/render/src/lib.rs index 42151c3..85f2c4c 100644 --- a/crates/render/src/lib.rs +++ b/crates/render/src/lib.rs @@ -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; diff --git a/crates/render/src/renderstate.rs b/crates/render/src/renderstate.rs index 811d4f6..797cbf2 100644 --- a/crates/render/src/renderstate.rs +++ b/crates/render/src/renderstate.rs @@ -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, /// 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, diff --git a/crates/render/src/texturearray.rs b/crates/render/src/texturearray.rs index cb46ba2..f239ea4 100644 --- a/crates/render/src/texturearray.rs +++ b/crates/render/src/texturearray.rs @@ -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 { + pub fn new(device: &wgpu::Device, queue: &wgpu::Queue, ct: &Content) -> Result { // Load all textures let mut texture_data = Vec::new(); diff --git a/crates/world/Cargo.toml b/crates/systemsim/Cargo.toml similarity index 83% rename from crates/world/Cargo.toml rename to crates/systemsim/Cargo.toml index f242e92..bd4e13e 100644 --- a/crates/world/Cargo.toml +++ b/crates/systemsim/Cargo.toml @@ -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 } diff --git a/crates/world/src/behavior/mod.rs b/crates/systemsim/src/controller/mod.rs similarity index 62% rename from crates/world/src/behavior/mod.rs rename to crates/systemsim/src/controller/mod.rs index a632d71..27ab057 100644 --- a/crates/world/src/behavior/mod.rs +++ b/crates/systemsim/src/controller/mod.rs @@ -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, + ships: &HashMap, this_ship: RigidBodyHandle, - this_data: GameShipHandle, + this_data: GxShipHandle, ) -> ShipControls; } diff --git a/crates/world/src/behavior/null.rs b/crates/systemsim/src/controller/null.rs similarity index 51% rename from crates/world/src/behavior/null.rs rename to crates/systemsim/src/controller/null.rs index ef64c96..2996d5d 100644 --- a/crates/world/src/behavior/null.rs +++ b/crates/systemsim/src/controller/null.rs @@ -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, + _ships: &HashMap, _this_ship: RigidBodyHandle, - _this_data: GameShipHandle, + _this_data: GxShipHandle, ) -> ShipControls { ShipControls::new() } diff --git a/crates/world/src/behavior/point.rs b/crates/systemsim/src/controller/point.rs similarity index 82% rename from crates/world/src/behavior/point.rs rename to crates/systemsim/src/controller/point.rs index f3ea853..30d4397 100644 --- a/crates/world/src/behavior/point.rs +++ b/crates/systemsim/src/controller/point.rs @@ -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, + ships: &HashMap, 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 { diff --git a/crates/world/src/lib.rs b/crates/systemsim/src/lib.rs similarity index 53% rename from crates/world/src/lib.rs rename to crates/systemsim/src/lib.rs index 3fd894a..0c54b26 100644 --- a/crates/world/src/lib.rs +++ b/crates/systemsim/src/lib.rs @@ -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; diff --git a/crates/systemsim/src/objects/collapse.rs b/crates/systemsim/src/objects/collapse.rs new file mode 100644 index 0000000..28c3d78 --- /dev/null +++ b/crates/systemsim/src/objects/collapse.rs @@ -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 { + 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; + } +} diff --git a/crates/world/src/objects/mod.rs b/crates/systemsim/src/objects/mod.rs similarity index 54% rename from crates/world/src/objects/mod.rs rename to crates/systemsim/src/objects/mod.rs index 6a1522f..d73def0 100644 --- a/crates/world/src/objects/mod.rs +++ b/crates/systemsim/src/objects/mod.rs @@ -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}; diff --git a/crates/world/src/objects/projectile.rs b/crates/systemsim/src/objects/projectile.rs similarity index 75% rename from crates/world/src/objects/projectile.rs rename to crates/systemsim/src/objects/projectile.rs index 5efdd1e..f315158 100644 --- a/crates/world/src/objects/projectile.rs +++ b/crates/systemsim/src/objects/projectile.rs @@ -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, diff --git a/crates/world/src/objects/ship.rs b/crates/systemsim/src/objects/ship.rs similarity index 52% rename from crates/world/src/objects/ship.rs rename to crates/systemsim/src/objects/ship.rs index 67233bc..48c3802 100644 --- a/crates/world/src/objects/ship.rs +++ b/crates/systemsim/src/objects/ship.rs @@ -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 { - 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 diff --git a/crates/world/src/particlebuilder.rs b/crates/systemsim/src/particlebuilder.rs similarity index 95% rename from crates/world/src/particlebuilder.rs rename to crates/systemsim/src/particlebuilder.rs index 41de145..bef138f 100644 --- a/crates/world/src/particlebuilder.rs +++ b/crates/systemsim/src/particlebuilder.rs @@ -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, @@ -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, parent_angle: Rad, parent_velocity: Vector2, diff --git a/crates/world/src/stepresources.rs b/crates/systemsim/src/stepresources.rs similarity index 80% rename from crates/world/src/stepresources.rs rename to crates/systemsim/src/stepresources.rs index 8b2b82e..95d888d 100644 --- a/crates/world/src/stepresources.rs +++ b/crates/systemsim/src/stepresources.rs @@ -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, } diff --git a/crates/world/src/world.rs b/crates/systemsim/src/systemsim.rs similarity index 86% rename from crates/world/src/world.rs rename to crates/systemsim/src/systemsim.rs index 42781c1..eee6515 100644 --- a/crates/world/src/world.rs +++ b/crates/systemsim/src/systemsim.rs @@ -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, - ships: HashMap, - ship_behaviors: HashMap>, - collider_ship_table: HashMap, + projectiles: HashMap, + ships: HashMap, + ship_behaviors: HashMap>, + collider_ship_table: HashMap, collision_handler: ChannelEventCollector, collision_queue: Receiver, } // 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) { + pub fn add_ship(&mut self, ct: &Content, ship: &GxShip, position: Point2) { 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 + '_ { + pub fn iter_ship_body(&self) -> impl Iterator + '_ { 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 + '_ { + pub fn iter_ships(&self) -> impl Iterator + '_ { self.ships.values() } /// Iterate over all ships in this physics system - pub fn iter_projectiles(&self) -> impl Iterator + '_ { + pub fn iter_projectiles(&self) -> impl Iterator + '_ { self.projectiles.values() } } diff --git a/crates/world/src/util.rs b/crates/systemsim/src/util.rs similarity index 100% rename from crates/world/src/util.rs rename to crates/systemsim/src/util.rs diff --git a/crates/world/src/wrapper.rs b/crates/systemsim/src/wrapper.rs similarity index 100% rename from crates/world/src/wrapper.rs rename to crates/systemsim/src/wrapper.rs