|
- 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);
- }
- }
|