From 0119fdaf0bf458faf6483634fd5be3d2603f7d0c Mon Sep 17 00:00:00 2001 From: Bergmann89 Date: Thu, 17 Dec 2020 02:29:47 +0100 Subject: [PATCH] Refactored ship system and fixed small bug in fleet info calculation --- .../src/systems/fleet_info_update.rs | 8 +- space-crush-common/src/dispatcher.rs | 4 +- space-crush-common/src/systems/fleets.rs | 134 ------------ space-crush-common/src/systems/mod.rs | 4 +- space-crush-common/src/systems/ships.rs | 205 ++++++++++++++++++ 5 files changed, 213 insertions(+), 142 deletions(-) delete mode 100644 space-crush-common/src/systems/fleets.rs create mode 100644 space-crush-common/src/systems/ships.rs diff --git a/space-crush-app/src/systems/fleet_info_update.rs b/space-crush-app/src/systems/fleet_info_update.rs index 6ca7cbd..83dc594 100644 --- a/space-crush-app/src/systems/fleet_info_update.rs +++ b/space-crush-app/src/systems/fleet_info_update.rs @@ -142,15 +142,15 @@ impl<'a> System<'a> for FleetInfoUpdate { None => false, Some(modified) => match (modified.old_fleet_id, modified.old_player_id) { (Some(old_fleet_id), Some(old_player_id)) => { - old_fleet_id != fleet_id && old_player_id == player_id + old_fleet_id == fleet_id && old_player_id == player_id } (Some(old_fleet_id), None) => { - old_fleet_id != fleet_id && player_owned.owner == player_id + old_fleet_id == fleet_id && player_owned.owner == player_id } (None, Some(old_player_id)) => { - fleet_owned.owner != fleet_id && old_player_id == player_id + fleet_owned.owner == fleet_id && old_player_id == player_id } - (None, None) => false, + (None, None) => unreachable!(), }, }; diff --git a/space-crush-common/src/dispatcher.rs b/space-crush-common/src/dispatcher.rs index 77b9600..d504d04 100644 --- a/space-crush-common/src/dispatcher.rs +++ b/space-crush-common/src/dispatcher.rs @@ -3,7 +3,7 @@ use specs::{Dispatcher as Inner, DispatcherBuilder, World, WorldExt}; use crate::{ components::Player, resources::Global, - systems::{Fleets, Movement, Process}, + systems::{Movement, Process, Ships}, }; pub struct Dispatcher<'a, 'b> { @@ -19,7 +19,7 @@ impl<'a, 'b> Dispatcher<'a, 'b> { let mut dispatcher = DispatcherBuilder::new() .with(Process::default(), "process", &[]) .with(Movement::default(), "movement", &[]) - .with(Fleets::default(), "fleets", &[]) + .with(Ships::new(world), "ships", &[]) .build(); dispatcher.setup(world); diff --git a/space-crush-common/src/systems/fleets.rs b/space-crush-common/src/systems/fleets.rs deleted file mode 100644 index 404f642..0000000 --- a/space-crush-common/src/systems/fleets.rs +++ /dev/null @@ -1,134 +0,0 @@ -use glc::{ - math::{linear_step, sqr}, - matrix::Matrix3f, - vector::{Vector2f, Vector3f}, -}; -use rand::random; -use specs::{prelude::*, ParJoin, Read, ReadStorage, System, WriteStorage}; - -use crate::{ - components::{Fleet, FleetOwned, Position, Ship, Velocity}, - constants::{ - SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND, - SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X, - }, - resources::Global, -}; - -#[derive(Default)] -pub struct Fleets; - -#[derive(SystemData)] -pub struct FleetsData<'a> { - ship: WriteStorage<'a, Ship>, - velocity: WriteStorage<'a, Velocity>, - fleet_owned: ReadStorage<'a, FleetOwned>, - position: ReadStorage<'a, Position>, - fleet: ReadStorage<'a, Fleet>, - global: Read<'a, Global>, -} - -impl<'a> System<'a> for Fleets { - type SystemData = FleetsData<'a>; - - fn run(&mut self, data: Self::SystemData) { - let FleetsData { - mut ship, - mut velocity, - fleet_owned, - position, - fleet, - global, - } = data; - - (&mut ship, &mut velocity, &fleet_owned, &position) - .par_join() - .for_each(|(ship, vel, fleet_owned, pos)| { - progress_ship( - &position, - &fleet, - ship, - vel, - fleet_owned.owner, - pos, - global.delta, - ) - }); - } -} - -fn progress_ship<'a>( - positions: &ReadStorage<'a, Position>, - fleets: &ReadStorage<'a, Fleet>, - ship: &mut Ship, - velocity: &mut Velocity, - fleet_id: Entity, - position: &Position, - delta: f32, -) { - let (orbit_pos, orbit_min, orbit_max): (Vector2f, f32, f32) = - match (positions.get(fleet_id), fleets.get(fleet_id)) { - (Some(position), Some(fleet)) => (position.pos, fleet.orbit_min, fleet.orbit_max), - (_, _) => return, - }; - - let orbit_to_target = ship.target_pos - orbit_pos; - let orbit_to_ship = position.pos - orbit_pos; - let ship_to_target = ship.target_pos - position.pos; - - let target_radius = orbit_to_target.length_sqr(); - let ship_radius = orbit_to_ship.length_sqr(); - - let target_in_orbit = (target_radius <= sqr(orbit_max)) && (target_radius >= sqr(orbit_min)); - let ship_in_orbit = ship_radius < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit_max); - - /* check and update target posistion */ - if ship.target_dir.length_sqr() == 0.0 - || ship_in_orbit != target_in_orbit - || ship.target_dir * ship_to_target <= 0.0 - { - if ship_in_orbit && orbit_max > 0.0 { - let orbit_to_ship_vec3 = Vector3f::new(orbit_to_ship.x, orbit_to_ship.y, 0.0); - let ship_dir_vec3 = Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0); - - let dir = if orbit_to_ship_vec3.cross(&ship_dir_vec3).z > 0.0 { - 1.0 - } else { - -1.0 - }; - - let angle = orbit_to_ship.angle2(&VECTOR_2F_POS_X); - let angle = angle - + (SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random()) * dir - / orbit_max; - let radius = orbit_min + (orbit_max - orbit_min) * random::(); - - ship.target_pos.x = orbit_pos.x + radius * angle.cos(); - ship.target_pos.y = orbit_pos.y + radius * angle.sin(); - } else { - ship.target_pos = orbit_pos; - } - ship.target_dir = (ship.target_pos - position.pos).normalize(); - } - - /* update ship direction */ - let angle = ship_to_target.angle2(&velocity.dir); - if angle.into_inner().abs() > 0.0001 { - let dir = angle.into_inner() / angle.abs().into_inner(); - let agility = if ship_in_orbit { - SHIP_ORBIT_AGILITY - } else { - ship.agility - }; - let rot_speed = agility * linear_step(0.0, 45.0, angle.abs().into_deg().into_inner()); - - let m = Matrix3f::new( - Vector3f::new(velocity.dir.y, -velocity.dir.x, 0.0), - Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0), - Vector3f::new(0.0, 0.0, 1.0), - ); - let m = m * Matrix3f::rotate(rot_speed * -dir * delta); - - velocity.dir = Vector2f::new(m.axis_y.x, m.axis_y.y); - } -} diff --git a/space-crush-common/src/systems/mod.rs b/space-crush-common/src/systems/mod.rs index dc3c6de..b17a21a 100644 --- a/space-crush-common/src/systems/mod.rs +++ b/space-crush-common/src/systems/mod.rs @@ -1,7 +1,7 @@ -mod fleets; mod movement; mod process; +mod ships; -pub use fleets::Fleets; pub use movement::Movement; pub use process::Process; +pub use ships::Ships; diff --git a/space-crush-common/src/systems/ships.rs b/space-crush-common/src/systems/ships.rs new file mode 100644 index 0000000..a010ea1 --- /dev/null +++ b/space-crush-common/src/systems/ships.rs @@ -0,0 +1,205 @@ +use glc::{ + math::{linear_step, sqr}, + matrix::Matrix3f, + vector::{Vector2f, Vector3f}, +}; +use rand::random; +use shrev::ReaderId; +use specs::{ + hibitset::BitSet, prelude::*, Entities, ParJoin, Read, ReadStorage, System, WriteStorage, +}; + +use crate::{ + components::{Fleet, FleetOwned, Position, Ship, Velocity}, + constants::{ + SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND, + SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X, + }, + misc::ComponentEvent, + resources::Global, + return_if_none, +}; + +pub struct Ships { + need_update: BitSet, + fleet_owned_id: ReaderId>, +} + +#[derive(SystemData)] +pub struct ShipsData<'a> { + global: Read<'a, Global>, + entities: Entities<'a>, + ships: WriteStorage<'a, Ship>, + velocities: WriteStorage<'a, Velocity>, + fleet_owned: ReadStorage<'a, FleetOwned>, + positions: ReadStorage<'a, Position>, + fleets: ReadStorage<'a, Fleet>, +} + +struct Processor<'a> { + need_update: &'a BitSet, + positions: &'a ReadStorage<'a, Position>, + fleets: &'a ReadStorage<'a, Fleet>, + delta: f32, +} + +impl Ships { + pub fn new(world: &mut World) -> Self { + let need_update = BitSet::new(); + let fleet_owned_id = unsafe { + WriteStorage::::setup(world); + + let mut fleet_owned = world.system_data::>(); + fleet_owned + .unprotected_storage_mut() + .channel_mut() + .register_reader() + }; + + Self { + need_update, + fleet_owned_id, + } + } + + fn progress_events(&mut self, fleet_owned: &ReadStorage<'_, FleetOwned>) { + self.need_update.clear(); + let events = fleet_owned + .unprotected_storage() + .channel() + .read(&mut self.fleet_owned_id); + for event in events { + let id = match event { + ComponentEvent::Inserted(id) => id, + ComponentEvent::Modified(id, _) => id, + ComponentEvent::Removed(id, _) => id, + }; + + self.need_update.add(*id); + } + } +} + +impl<'a> System<'a> for Ships { + type SystemData = ShipsData<'a>; + + fn run(&mut self, data: Self::SystemData) { + let ShipsData { + global, + entities, + mut ships, + mut velocities, + fleet_owned, + positions, + fleets, + } = data; + + self.progress_events(&fleet_owned); + + /* update ships */ + let processor = Processor { + need_update: &self.need_update, + positions: &positions, + fleets: &fleets, + delta: global.delta, + }; + ( + &entities, + &mut ships, + &mut velocities, + &positions, + &fleet_owned, + ) + .par_join() + .for_each(|(entity, ship, velocity, position, fleet_owned)| { + processor.progress_ship(entity, ship, velocity, position, fleet_owned); + }); + } +} + +impl Processor<'_> { + fn progress_ship( + &self, + entity: Entity, + ship: &mut Ship, + velocity: &mut Velocity, + position: &Position, + fleet_owned: &FleetOwned, + ) { + let fleet_id = fleet_owned.owner; + let fleet = return_if_none!(self.fleets.get(fleet_id)); + let orbit_pos = return_if_none!(self.positions.get(fleet_id)).pos; + let ship_pos = position.pos; + let target_pos = ship.target_pos; + let target_dir = ship.target_dir; + + let orbit_to_target = target_pos - orbit_pos; + let orbit_to_ship = position.pos - orbit_pos; + let ship_to_target = target_pos - position.pos; + + let r_ship = orbit_to_ship.length_sqr(); + let r_target = orbit_to_target.length_sqr(); + + let orbit_min = fleet.orbit_min; + let orbit_max = fleet.orbit_max; + + let target_in_orbit = (r_target <= sqr(fleet.orbit_max)) && (r_target >= sqr(orbit_min)); + let ship_in_orbit = r_ship < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit_max); + + let need_update = self.need_update.contains(entity.id()); + let has_target = target_dir.length_sqr() != 0.0; + let passed_target = target_dir * ship_to_target <= 0.0; + + /* check and update target posistion */ + if need_update || !has_target || passed_target || ship_in_orbit != target_in_orbit { + let target_pos = if ship_in_orbit && fleet.orbit_max > 0.0 { + let orbit_to_ship_vec3 = Vector3f::new(orbit_to_ship.x, orbit_to_ship.y, 0.0); + let ship_dir_vec3 = Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0); + + let dir = if orbit_to_ship_vec3.cross(&ship_dir_vec3).z > 0.0 { + 1.0 + } else { + -1.0 + }; + + let angle = orbit_to_ship.angle2(&VECTOR_2F_POS_X); + let angle = angle + + (SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random()) * dir + / fleet.orbit_max; + let radius = + fleet.orbit_min + (fleet.orbit_max - fleet.orbit_min) * random::(); + + Vector2f::new( + orbit_pos.x + radius * angle.cos(), + orbit_pos.y + radius * angle.sin(), + ) + } else { + orbit_pos + }; + + ship.target_pos = target_pos; + ship.target_dir = (target_pos - ship_pos).normalize(); + } + + /* update ship direction */ + let angle = ship_to_target.angle2(&velocity.dir); + if angle.into_inner().abs() > 0.0001 { + let dir = angle.into_inner() / angle.abs().into_inner(); + let agility = if ship_in_orbit { + SHIP_ORBIT_AGILITY + } else { + ship.agility + }; + let rot_speed = agility * linear_step(0.0, 45.0, angle.abs().into_deg().into_inner()); + + let m = Matrix3f::new( + Vector3f::new(velocity.dir.y, -velocity.dir.x, 0.0), + Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0), + Vector3f::new(0.0, 0.0, 1.0), + ); + let m = m * Matrix3f::rotate(rot_speed * -dir * self.delta); + + velocity.dir = Vector2f::new(m.axis_y.x, m.axis_y.y); + } + } +}