@@ -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!(), | |||
}, | |||
}; | |||
@@ -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); | |||
@@ -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::<f32>(); | |||
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); | |||
} | |||
} |
@@ -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; |
@@ -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<ComponentEvent<FleetOwned>>, | |||
} | |||
#[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::<FleetOwned>::setup(world); | |||
let mut fleet_owned = world.system_data::<WriteStorage<FleetOwned>>(); | |||
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::<f32>(); | |||
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); | |||
} | |||
} | |||
} |