From 35c6676e9545be25e8956b2b369d0d47fefee2a8 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 9 Jan 2024 11:38:47 -0800 Subject: [PATCH] Rework world crate --- crates/galactica/src/game.rs | 94 +++++------- crates/world/src/objects/mod.rs | 2 +- crates/world/src/objects/projectile.rs | 32 +++- crates/world/src/objects/ship.rs | 119 ++++++++------- crates/world/src/world.rs | 194 +++++++++++++++---------- 5 files changed, 248 insertions(+), 193 deletions(-) diff --git a/crates/galactica/src/game.rs b/crates/galactica/src/game.rs index 292bd55..6d45114 100644 --- a/crates/galactica/src/game.rs +++ b/crates/galactica/src/game.rs @@ -1,23 +1,23 @@ -use cgmath::Point2; -use content::Ship; -use object::{ship::ShipPersonality, GameData}; +use object::{ + ship::{OutfitSet, ShipPersonality}, + GameData, GameShipHandle, +}; use std::time::Instant; use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode}; use crate::camera::Camera; use crate::inputstatus::InputStatus; -use galactica_behavior::{behavior, ShipBehavior}; use galactica_constants; use galactica_content as content; use galactica_gameobject as object; use galactica_render::RenderState; -use galactica_world::{util, ParticleBuilder, ShipPhysicsHandle, World}; +use galactica_world::{objects::ShipControls, ParticleBuilder, StepResources, World}; pub struct Game { input: InputStatus, last_update: Instant, - player: ShipPhysicsHandle, + player: GameShipHandle, paused: bool, time_scale: f32, start_instant: Instant, @@ -25,9 +25,6 @@ pub struct Game { // TODO: include system in world //system: object::System, - shipbehaviors: Vec>, - playerbehavior: behavior::Player, - gamedata: GameData, content: content::Content, @@ -37,28 +34,28 @@ pub struct Game { impl Game { pub fn new(ct: content::Content) -> Self { - let mut physics = World::new(); - let mut gamedata = GameData::new(); + let mut gamedata = GameData::new(&ct); let ss = ct.get_ship(content::ShipHandle { index: 0 }); - let mut o1 = object::OutfitSet::new(ss); - o1.add(&ct, content::OutfitHandle { index: 0 }); - o1.add(&ct, content::OutfitHandle { index: 1 }); - o1.add_gun(&ct, content::GunHandle { index: 0 }); - o1.add_gun(&ct, content::GunHandle { index: 0 }); - o1.add_gun(&ct, content::GunHandle { index: 0 }); + let mut o1 = OutfitSet::new(ss.space, &[]); + o1.add(&ct.get_outfit(content::OutfitHandle { index: 0 })); + o1.add(&ct.get_outfit(content::OutfitHandle { index: 1 })); + //o1.add_gun(&ct, content::GunHandle { index: 0 }); + //o1.add_gun(&ct, content::GunHandle { index: 0 }); + //o1.add_gun(&ct, content::GunHandle { index: 0 }); - let mut o1 = object::OutfitSet::new(ss); - o1.add(&ct, content::OutfitHandle { index: 0 }); - o1.add_gun(&ct, content::GunHandle { index: 0 }); + let mut o1 = OutfitSet::new(ss.space, &[]); + o1.add(&ct.get_outfit(content::OutfitHandle { index: 0 })); + //o1.add_gun(&ct, content::GunHandle { index: 0 }); - gamedata.create_ship( + let player = gamedata.create_ship( &ct, content::ShipHandle { index: 0 }, content::FactionHandle { index: 0 }, ShipPersonality::Player, - o1, + o1.clone(), + &content::SystemHandle { index: 0 }, ); gamedata.create_ship( @@ -66,7 +63,8 @@ impl Game { content::ShipHandle { index: 0 }, content::FactionHandle { index: 1 }, ShipPersonality::Dummy, - object::OutfitSet::new(ss), + OutfitSet::new(ss.space, &[]), + &content::SystemHandle { index: 0 }, ); gamedata.create_ship( @@ -75,16 +73,15 @@ impl Game { content::FactionHandle { index: 1 }, ShipPersonality::Point, o1, + &content::SystemHandle { index: 0 }, ); - //let mut shipbehaviors: Vec> = Vec::new(); - //shipbehaviors.push(Box::new(behavior::Dummy::new(h2))); - //shipbehaviors.push(Box::new(behavior::Point::new(h3))); + let physics = World::new(&ct, &gamedata, content::SystemHandle { index: 0 }); Game { last_update: Instant::now(), input: InputStatus::new(), - player: h1, + player, start_instant: Instant::now(), camera: Camera { @@ -96,10 +93,8 @@ impl Game { paused: false, time_scale: 1.0, world: physics, - shipbehaviors, gamedata, content: ct, - playerbehavior: behavior::Player::new(h1), new_particles: Vec::new(), } } @@ -132,39 +127,27 @@ impl Game { pub fn update(&mut self) { let t: f32 = self.last_update.elapsed().as_secs_f32() * self.time_scale; - self.playerbehavior.key_guns = self.input.key_guns; - self.playerbehavior.key_thrust = self.input.key_thrust; - self.playerbehavior.key_right = self.input.key_right; - self.playerbehavior.key_left = self.input.key_left; - self.playerbehavior - .update_controls(&mut self.world, &self.content); - - self.shipbehaviors.retain_mut(|b| { - // Remove shipbehaviors of destroyed ships - if self.world.get_ship_mut(&b.get_handle()).is_none() { - false - } else { - b.update_controls(&mut self.world, &self.content); - true - } + let world_output = self.world.step(StepResources { + player: self.player, + player_controls: ShipControls { + left: self.input.key_left, + right: self.input.key_right, + thrust: self.input.key_thrust, + guns: self.input.key_guns, + }, + ct: &self.content, + dt: &mut self.gamedata, + particles: &mut self.new_particles, + t, }); - self.world.step(t, &self.content, &mut self.new_particles); - if self.input.v_scroll != 0.0 { self.camera.zoom = (self.camera.zoom + self.input.v_scroll) .clamp(galactica_constants::ZOOM_MIN, galactica_constants::ZOOM_MAX); self.input.v_scroll = 0.0; } - let r = self - .world - .get_ship_mut(&self.player) - .unwrap() - .physics_handle; - let r = self.world.get_rigid_body(r.0).unwrap(); // TODO: r.0 shouldn't be public - let ship_pos = util::rigidbody_position(r); - self.camera.pos = ship_pos; + self.camera.pos = world_output.player_position; self.last_update = Instant::now(); } @@ -176,7 +159,8 @@ impl Game { content: &self.content, world: &self.world, particles: &mut self.new_particles, - player: &self.player, + player_data: self.player, + data: &self.gamedata, } } } diff --git a/crates/world/src/objects/mod.rs b/crates/world/src/objects/mod.rs index 105c6c8..6a1522f 100644 --- a/crates/world/src/objects/mod.rs +++ b/crates/world/src/objects/mod.rs @@ -3,4 +3,4 @@ mod projectile; mod ship; pub use projectile::ProjectileWorldObject; -pub use ship::ShipWorldObject; +pub use ship::{ShipControls, ShipWorldObject}; diff --git a/crates/world/src/objects/projectile.rs b/crates/world/src/objects/projectile.rs index e25f64e..5efdd1e 100644 --- a/crates/world/src/objects/projectile.rs +++ b/crates/world/src/objects/projectile.rs @@ -1,13 +1,19 @@ use rand::Rng; use rapier2d::{dynamics::RigidBodyHandle, geometry::ColliderHandle}; -use galactica_gameobject as object; +use galactica_content as content; /// A single projectile in the world #[derive(Debug)] pub struct ProjectileWorldObject { /// This projectile's game data - pub projectile: object::Projectile, + pub content: content::Projectile, + + /// The remaining lifetime of this projectile, in seconds + pub lifetime: f32, + + /// The faction this projectile belongs to + pub faction: content::FactionHandle, /// This projectile's rigidbody pub rigid_body: RigidBodyHandle, @@ -20,19 +26,33 @@ pub struct ProjectileWorldObject { } impl ProjectileWorldObject { - /// Make a new projectile + /// Create a new projectile pub fn new( - projectile: object::Projectile, + content: content::Projectile, // TODO: use a handle rigid_body: RigidBodyHandle, + faction: content::FactionHandle, collider: ColliderHandle, ) -> Self { let mut rng = rand::thread_rng(); - let size_rng = projectile.content.size_rng; + let size_rng = content.size_rng; + let lifetime = content.lifetime; ProjectileWorldObject { rigid_body, collider, - projectile, + content, + lifetime, + faction, size_rng: rng.gen_range(-size_rng..=size_rng), } } + + /// Process this projectile's state after `t` seconds + pub fn tick(&mut self, t: f32) { + self.lifetime -= t; + } + + /// Has this projectile expired? + pub fn is_expired(&self) -> bool { + return self.lifetime < 0.0; + } } diff --git a/crates/world/src/objects/ship.rs b/crates/world/src/objects/ship.rs index 12af50e..27d63c4 100644 --- a/crates/world/src/objects/ship.rs +++ b/crates/world/src/objects/ship.rs @@ -1,17 +1,30 @@ use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Rad, Vector2, Zero}; use nalgebra::{point, vector}; +use object::GameShipHandle; use rand::{rngs::ThreadRng, Rng}; -use rapier2d::{dynamics::RigidBody, geometry::Collider}; +use rapier2d::{ + dynamics::{RigidBody, RigidBodyHandle}, + geometry::{Collider, ColliderHandle}, +}; -use crate::{util, ParticleBuilder, ShipPhysicsHandle}; +use crate::{behavior::ShipBehavior, util, ParticleBuilder, StepResources}; use galactica_content as content; use galactica_gameobject as object; +/// A ship's controls +#[derive(Debug, Clone)] pub struct ShipControls { + /// True if turning left pub left: bool, + + /// True if turning right pub right: bool, + + /// True if foward thrust pub thrust: bool, + + /// True if firing guns pub guns: bool, } @@ -35,22 +48,23 @@ struct ShipCollapseSequence { impl ShipCollapseSequence { fn new(total_length: f32) -> Self { Self { - total_length: total_length, + 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 { - // Pick a random point inside this ship's collider let mut y = 0.0; let mut x = 0.0; let mut a = false; @@ -63,17 +77,16 @@ impl ShipCollapseSequence { Vector2 { x, y } } + /// Step this sequence `t` seconds fn step( &mut self, - ship: &object::Ship, - ct: &content::Content, - particles: &mut Vec, + res: &mut StepResources, + ship: GameShipHandle, rigid_body: &mut RigidBody, collider: &mut Collider, - t: f32, ) { - let h = ship.handle; - let ship_content = ct.get_ship(h); + let h = ship.content_handle(); + let ship_content = res.ct.get_ship(h); 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 }); @@ -85,11 +98,11 @@ impl ShipCollapseSequence { for event in &ship_content.collapse.events { match event { content::CollapseEvent::Effect(event) => { - if (event.time > self.time_elapsed && event.time <= self.time_elapsed + t) + 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 = ct.get_effect(spawner.effect); + let effect = res.ct.get_effect(spawner.effect); for _ in 0..spawner.count as usize { let pos = if let Some(pos) = spawner.pos { @@ -102,7 +115,7 @@ impl ShipCollapseSequence { let velocity = rigid_body.velocity_at_point(&point![pos.x, pos.y]); - particles.push(ParticleBuilder::from_content( + res.particles.push(ParticleBuilder::from_content( effect, pos, Rad::zero(), @@ -121,7 +134,7 @@ impl ShipCollapseSequence { // Create collapse effects for spawner in &ship_content.collapse.effects { - let effect = ct.get_effect(spawner.effect); + 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. @@ -136,7 +149,7 @@ impl ShipCollapseSequence { return y; }; - let p_add = (t / self.total_length) * pdf(frac_done) * spawner.count; + 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 { @@ -149,7 +162,7 @@ impl ShipCollapseSequence { 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]); - particles.push(ParticleBuilder { + res.particles.push(ParticleBuilder { sprite: effect.sprite, pos, velocity: Vector2 { x: vel.x, y: vel.y }, @@ -162,21 +175,28 @@ impl ShipCollapseSequence { } } - self.time_elapsed += t; + self.time_elapsed += res.t; } } /// A ship instance in the physics system pub struct ShipWorldObject { /// This ship's physics handle - pub physics_handle: ShipPhysicsHandle, + pub rigid_body: RigidBodyHandle, + + /// This ship's collider + pub collider: ColliderHandle, /// This ship's game data - pub ship: object::Ship, + pub data_handle: GameShipHandle, /// This ship's controls - pub controls: ShipControls, + pub(crate) controls: ShipControls, + /// This ship's behavior + behavior: Box, + + /// This ship's collapse sequence collapse_sequence: ShipCollapseSequence, } @@ -184,51 +204,45 @@ impl ShipWorldObject { /// Make a new ship pub fn new( ct: &content::Content, - ship: object::Ship, - physics_handle: ShipPhysicsHandle, + data_handle: GameShipHandle, + behavior: Box, + rigid_body: RigidBodyHandle, + collider: ColliderHandle, ) -> Self { - let ship_content = ct.get_ship(ship.handle); + let ship_content = ct.get_ship(data_handle.content_handle()); ShipWorldObject { - physics_handle, - ship, + rigid_body, + collider, + data_handle, + behavior, controls: ShipControls::new(), collapse_sequence: ShipCollapseSequence::new(ship_content.collapse.length), } } - /// Should this ship should be removed from the world? - pub fn remove_from_world(&self) -> bool { - return self.ship.is_dead() && self.collapse_sequence.is_done(); + /// Compute this ship's controls using its behavior + pub fn update_controls(&mut self, res: &StepResources) { + self.controls = self.behavior.update_controls(res); } /// Step this ship's state by t seconds pub fn step( &mut self, - ct: &content::Content, - particles: &mut Vec, + res: &mut StepResources, rigid_body: &mut RigidBody, collider: &mut Collider, - t: f32, ) { - if self.ship.is_dead() { - return self - .collapse_sequence - .step(&self.ship, ct, particles, rigid_body, collider, t); - } - - self.ship.step(t); - - let ship_content = ct.get_ship(self.ship.handle); + let ship = res.dt.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); let ship_ang = ship_rot.angle(Vector2 { x: 1.0, y: 0.0 }); let mut rng = rand::thread_rng(); - if self.ship.hull <= ship_content.damage.hull { + if ship.get_hull() <= ship_content.damage.hull { for e in &ship_content.damage.effects { - if rng.gen_range(0.0..=1.0) <= t / e.frequency { - let effect = ct.get_effect(e.effect); - let ship_content = ct.get_ship(self.ship.handle); + if rng.gen_range(0.0..=1.0) <= res.t / e.frequency { + let effect = res.ct.get_effect(e.effect); let pos = if let Some(pos) = e.pos { pos.to_vec() @@ -252,7 +266,7 @@ impl ShipWorldObject { let velocity = rigid_body.velocity_at_point(&point![pos.x, pos.y]); - particles.push(ParticleBuilder::from_content( + res.particles.push(ParticleBuilder::from_content( effect, pos, Rad::zero(), @@ -266,28 +280,27 @@ impl ShipWorldObject { } } - let engine_force = ship_rot * t; + let engine_force = ship_rot * res.t; if self.controls.thrust { rigid_body.apply_impulse( - vector![engine_force.x, engine_force.y] - * self.ship.outfits.stat_sum().engine_thrust, + vector![engine_force.x, engine_force.y] * ship.get_outfits().get_engine_thrust(), true, ); } if self.controls.right { rigid_body - .apply_torque_impulse(self.ship.outfits.stat_sum().steer_power * -100.0 * t, true); + .apply_torque_impulse(ship.get_outfits().get_steer_power() * -100.0 * res.t, true); } if self.controls.left { rigid_body - .apply_torque_impulse(self.ship.outfits.stat_sum().steer_power * 100.0 * t, true); + .apply_torque_impulse(ship.get_outfits().get_steer_power() * 100.0 * res.t, true); } - for i in self.ship.outfits.iter_guns() { - i.cooldown -= t; - } + //for i in self.ship.outfits.iter_guns() { + // i.cooldown -= t; + //} } } diff --git a/crates/world/src/world.rs b/crates/world/src/world.rs index bd21717..59b7340 100644 --- a/crates/world/src/world.rs +++ b/crates/world/src/world.rs @@ -1,6 +1,7 @@ use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Point2, Rad, Vector2, Zero}; use crossbeam::channel::Receiver; use nalgebra::{point, vector}; +use object::{ship::Ship, GameData, GameShipHandle}; use rand::Rng; use rapier2d::{ dynamics::{RigidBody, RigidBodyBuilder, RigidBodyHandle}, @@ -10,21 +11,24 @@ use rapier2d::{ use std::{collections::HashMap, f32::consts::PI}; use crate::{ - objects, + behavior, objects, objects::{ProjectileWorldObject, ShipWorldObject}, util, wrapper::Wrapper, - ParticleBuilder, ShipPhysicsHandle, + ParticleBuilder, StepOutput, StepResources, }; use galactica_content as content; use galactica_gameobject as object; -/// Keeps track of all objects in the world that we can interact with. -/// Also wraps our physics engine +/// Manages the physics state of one system pub struct World { + /// The system this world is attached to + system: content::SystemHandle, + wrapper: Wrapper, projectiles: HashMap, - ships: HashMap, + ships: HashMap, + collider_ship_table: HashMap, collision_handler: ChannelEventCollector, collision_queue: Receiver, @@ -56,23 +60,25 @@ impl<'a> World { return Some((r, p)); } - fn remove_ship(&mut self, h: ShipPhysicsHandle) { + fn remove_ship(&mut self, s: &ShipWorldObject) { self.wrapper.rigid_body_set.remove( - h.0, + s.rigid_body, &mut self.wrapper.im, &mut self.wrapper.collider_set, &mut self.wrapper.ij, &mut self.wrapper.mj, true, ); - self.ships.remove(&h.1); + let h = self.collider_ship_table.remove(&s.collider).unwrap(); + self.ships.remove(&h); } + /* /// Add a projectile fired from a ship fn add_projectiles( &mut self, s: ShipPhysicsHandle, - p: Vec<(object::Projectile, content::GunPoint)>, + p: Vec<(ProjectileWorldObject, content::GunPoint)>, ) { let mut rng = rand::thread_rng(); for (projectile, point) in p { @@ -126,37 +132,44 @@ impl<'a> World { ); } } + */ fn collide_projectile_ship( &mut self, - ct: &content::Content, - particles: &mut Vec, + res: &mut StepResources, projectile_h: ColliderHandle, ship_h: ColliderHandle, ) { let projectile = self.projectiles.get(&projectile_h); - let ship = self.ships.get_mut(&ship_h); + let ship = self + .ships + .get_mut(self.collider_ship_table.get(&ship_h).unwrap()); if projectile.is_none() || ship.is_none() { return; } let projectile = projectile.unwrap(); let ship = ship.unwrap(); - let hit = ship - .ship - .handle_projectile_collision(ct, &projectile.projectile); - let s = ship.physics_handle; - if hit { + let ship_d = res.dt.get_ship_mut(ship.data_handle).unwrap(); + + // TODO: check faction + ship_d.apply_damage(projectile.content.damage); + + if true { let pr = self .wrapper .rigid_body_set .get(projectile.rigid_body) .unwrap(); - let v = util::rigidbody_velocity(pr).normalize() * projectile.projectile.content.force; + let v = util::rigidbody_velocity(pr).normalize() * projectile.content.force; let pos = util::rigidbody_position(pr); let _ = pr; - let r = self.wrapper.rigid_body_set.get_mut(s.0).unwrap(); + let r = self + .wrapper + .rigid_body_set + .get_mut(ship.rigid_body) + .unwrap(); r.apply_impulse_at_point(vector![v.x, v.y], point![pos.x, pos.y], true); // Borrow again, we can only have one at a time @@ -168,16 +181,17 @@ impl<'a> World { let pos = util::rigidbody_position(pr); let angle = util::rigidbody_rotation(pr).angle(Vector2 { x: 1.0, y: 0.0 }); - match &projectile.projectile.content.impact_effect { + match &projectile.content.impact_effect { None => {} Some(x) => { - let effect = ct.get_effect(*x); - let (_, sr) = self.get_ship_body(s).unwrap(); + let effect = res.ct.get_effect(*x); + let r = ship.rigid_body; + let sr = self.get_rigid_body(r).unwrap(); let parent_velocity = util::rigidbody_velocity(pr); let target_velocity = sr.velocity_at_point(&nalgebra::Point2::new(pos.x, pos.y)); - particles.push(ParticleBuilder::from_content( + res.particles.push(ParticleBuilder::from_content( effect, pos, -angle, @@ -198,27 +212,41 @@ impl<'a> World { // Public methods impl<'a> World { /// Create a new physics system - pub fn new() -> Self { + pub fn new(ct: &content::Content, dt: &GameData, system: content::SystemHandle) -> Self { let (collision_send, collision_queue) = crossbeam::channel::unbounded(); let (contact_force_send, _) = crossbeam::channel::unbounded(); - Self { + let mut w = Self { + system, wrapper: Wrapper::new(), projectiles: HashMap::new(), ships: HashMap::new(), + collider_ship_table: HashMap::new(), collision_handler: ChannelEventCollector::new(collision_send, contact_force_send), collision_queue, + }; + + // TODO: guarantee not touching + // TODO: add, remove ships each tick + // Maybe store position in gamedata? + let mut rng = rand::thread_rng(); + for s in dt.iter_ships() { + w.add_ship( + ct, + s, + Point2 { + x: rng.gen_range(-500.0..=500.0), + y: rng.gen_range(-500.0..=500.0), + }, + ); } + + return w; } /// Add a ship to this physics system - pub fn add_ship( - &mut self, - ct: &content::Content, - ship: object::Ship, - position: Point2, - ) -> ShipPhysicsHandle { - let ship_content = ct.get_ship(ship.handle); + pub fn add_ship(&mut self, ct: &content::Content, ship: &Ship, position: Point2) { + let ship_content = ct.get_ship(ship.get_content()); let cl = ColliderBuilder::convex_decomposition( &ship_content.collision.points[..], &ship_content.collision.indices[..], @@ -242,42 +270,60 @@ impl<'a> World { &mut self.wrapper.rigid_body_set, ); - let h = ShipPhysicsHandle(r, c); - self.ships - .insert(c, objects::ShipWorldObject::new(ct, ship, h)); - return h; + self.collider_ship_table.insert(c, ship.get_handle()); + self.ships.insert( + ship.get_handle(), + objects::ShipWorldObject::new( + ct, + ship.get_handle(), + Box::new(behavior::Null::new()), + r, + c, + ), + ); } /// Step this physics system by `t` seconds - pub fn step(&mut self, t: f32, ct: &content::Content, particles: &mut Vec) { + pub fn step(&mut self, mut res: StepResources) -> StepOutput { + let mut output = StepOutput { + player_position: Point2 { x: 0.0, y: 0.0 }, + }; + // Run ship updates // TODO: maybe reorganize projectile creation? - let mut projectiles = Vec::new(); + //let mut projectiles = Vec::new(); let mut to_remove = Vec::new(); for (_, s) in &mut self.ships { - let r = &mut self.wrapper.rigid_body_set[s.physics_handle.0]; - let c = &mut self.wrapper.collider_set[s.physics_handle.1]; + let r = &mut self.wrapper.rigid_body_set[s.rigid_body]; + let c = &mut self.wrapper.collider_set[s.collider]; + + if s.data_handle == res.player { + s.controls = res.player_controls.clone(); + output.player_position = util::rigidbody_position(r); + } else { + s.update_controls(&res); + } // TODO: unified step info struct - s.step(ct, particles, r, c, t); - if s.controls.guns { - projectiles.push((s.physics_handle, s.ship.fire_guns())); - } + s.step(&mut res, r, c); + //if s.controls.guns { + // projectiles.push((s.physics_handle, s.ship.fire_guns())); + //} - if s.remove_from_world() { - to_remove.push(s.physics_handle); - continue; - } - } - for (s, p) in projectiles { - self.add_projectiles(s, p); + //if s.remove_from_world() { + // to_remove.push(s.physics_handle); + // continue; + //} } + //for (s, p) in projectiles { + // self.add_projectiles(s, p); + //} for s in to_remove { self.remove_ship(s); } // Update physics - self.wrapper.step(t, &self.collision_handler); + self.wrapper.step(res.t, &self.collision_handler); // Handle collision events while let Ok(event) = &self.collision_queue.try_recv() { @@ -294,19 +340,21 @@ impl<'a> World { }; let p = self.projectiles.get(&a); - let s = self.ships.get_mut(&b); + let s = self + .ships + .get_mut(self.collider_ship_table.get(&b).unwrap()); if p.is_none() || s.is_none() { continue; } - self.collide_projectile_ship(ct, particles, a, b); + self.collide_projectile_ship(&mut res, a, b); } } // Delete projectiles let mut to_remove = Vec::new(); for (c, p) in &mut self.projectiles { - p.projectile.tick(t); - if p.projectile.is_expired() { + p.tick(res.t); + if p.is_expired() { to_remove.push(*c); } } @@ -315,10 +363,10 @@ impl<'a> World { for c in to_remove { let (pr, p) = self.remove_projectile(c).unwrap(); - match &p.projectile.content.expire_effect { + match &p.content.expire_effect { None => {} Some(x) => { - let x = ct.get_effect(*x); + let x = res.ct.get_effect(*x); let pos = util::rigidbody_position(&pr); let vel = util::rigidbody_velocity(&pr); let angle = util::rigidbody_rotation(&pr).angle(Vector2 { x: 1.0, y: 0.0 }); @@ -332,7 +380,7 @@ impl<'a> World { velocity }; - particles.push(ParticleBuilder::from_content( + res.particles.push(ParticleBuilder::from_content( x, pos, -angle, @@ -342,6 +390,12 @@ impl<'a> World { } }; } + + return output; + } + + pub fn get_ship(&self, ship: GameShipHandle) -> Option<&ShipWorldObject> { + self.ships.get(&ship) } /// Get a rigid body from a handle @@ -354,29 +408,13 @@ impl<'a> World { self.wrapper.rigid_body_set.get_mut(r) } - /// Get a ship from a handle - pub fn get_ship_mut(&mut self, s: &ShipPhysicsHandle) -> Option<&mut objects::ShipWorldObject> { - self.ships.get_mut(&s.1) - } - - /// Get a ship and its rigidbody from a handle - pub fn get_ship_body( - &self, - s: ShipPhysicsHandle, - ) -> Option<(&objects::ShipWorldObject, &RigidBody)> { - Some((self.ships.get(&s.1)?, self.wrapper.rigid_body_set.get(s.0)?)) - } - /// Iterate over all ships in this physics system pub fn iter_ship_body( &self, ) -> impl Iterator + '_ { - self.ships.values().map(|x| { - ( - x, - self.wrapper.rigid_body_set.get(x.physics_handle.0).unwrap(), - ) - }) + self.ships + .values() + .map(|x| (x, self.wrapper.rigid_body_set.get(x.rigid_body).unwrap())) } /// Iterate over all ships in this physics system