@@ -142,15 +142,15 @@ impl<'a> System<'a> for FleetInfoUpdate { | |||||
None => false, | None => false, | ||||
Some(modified) => match (modified.old_fleet_id, modified.old_player_id) { | Some(modified) => match (modified.old_fleet_id, modified.old_player_id) { | ||||
(Some(old_fleet_id), Some(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) => { | (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)) => { | (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::{ | use crate::{ | ||||
components::Player, | components::Player, | ||||
resources::Global, | resources::Global, | ||||
systems::{Fleets, Movement, Process}, | |||||
systems::{Movement, Process, Ships}, | |||||
}; | }; | ||||
pub struct Dispatcher<'a, 'b> { | pub struct Dispatcher<'a, 'b> { | ||||
@@ -19,7 +19,7 @@ impl<'a, 'b> Dispatcher<'a, 'b> { | |||||
let mut dispatcher = DispatcherBuilder::new() | let mut dispatcher = DispatcherBuilder::new() | ||||
.with(Process::default(), "process", &[]) | .with(Process::default(), "process", &[]) | ||||
.with(Movement::default(), "movement", &[]) | .with(Movement::default(), "movement", &[]) | ||||
.with(Fleets::default(), "fleets", &[]) | |||||
.with(Ships::new(world), "ships", &[]) | |||||
.build(); | .build(); | ||||
dispatcher.setup(world); | 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 movement; | ||||
mod process; | mod process; | ||||
mod ships; | |||||
pub use fleets::Fleets; | |||||
pub use movement::Movement; | pub use movement::Movement; | ||||
pub use process::Process; | 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); | |||||
} | |||||
} | |||||
} |