You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

135 lines
4.2 KiB

  1. use glc::{
  2. math::{linear_step, sqr},
  3. matrix::Matrix3f,
  4. vector::{Vector2f, Vector3f},
  5. };
  6. use rand::random;
  7. use specs::{prelude::*, ParJoin, Read, ReadStorage, System, WriteStorage};
  8. use crate::{
  9. components::{Fleet, FleetOwned, Position, Ship, Velocity},
  10. constants::{
  11. SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND,
  12. SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X,
  13. },
  14. resources::Global,
  15. };
  16. #[derive(Default)]
  17. pub struct Fleets;
  18. #[derive(SystemData)]
  19. pub struct FleetsData<'a> {
  20. ship: WriteStorage<'a, Ship>,
  21. velocity: WriteStorage<'a, Velocity>,
  22. fleet_owned: ReadStorage<'a, FleetOwned>,
  23. position: ReadStorage<'a, Position>,
  24. fleet: ReadStorage<'a, Fleet>,
  25. global: Read<'a, Global>,
  26. }
  27. impl<'a> System<'a> for Fleets {
  28. type SystemData = FleetsData<'a>;
  29. fn run(&mut self, data: Self::SystemData) {
  30. let FleetsData {
  31. mut ship,
  32. mut velocity,
  33. fleet_owned,
  34. position,
  35. fleet,
  36. global,
  37. } = data;
  38. (&mut ship, &mut velocity, &fleet_owned, &position)
  39. .par_join()
  40. .for_each(|(ship, vel, fleet_owned, pos)| {
  41. progress_ship(
  42. &position,
  43. &fleet,
  44. ship,
  45. vel,
  46. fleet_owned.owner,
  47. pos,
  48. global.delta,
  49. )
  50. });
  51. }
  52. }
  53. fn progress_ship<'a>(
  54. positions: &ReadStorage<'a, Position>,
  55. fleets: &ReadStorage<'a, Fleet>,
  56. ship: &mut Ship,
  57. velocity: &mut Velocity,
  58. fleet_id: Entity,
  59. position: &Position,
  60. delta: f32,
  61. ) {
  62. let (orbit_pos, orbit_min, orbit_max): (Vector2f, f32, f32) =
  63. match (positions.get(fleet_id), fleets.get(fleet_id)) {
  64. (Some(position), Some(fleet)) => (position.pos, fleet.orbit_min, fleet.orbit_max),
  65. (_, _) => return,
  66. };
  67. let orbit_to_target = ship.target_pos - orbit_pos;
  68. let orbit_to_ship = position.pos - orbit_pos;
  69. let ship_to_target = ship.target_pos - position.pos;
  70. let target_radius = orbit_to_target.length_sqr();
  71. let ship_radius = orbit_to_ship.length_sqr();
  72. let target_in_orbit = (target_radius <= sqr(orbit_max)) && (target_radius >= sqr(orbit_min));
  73. let ship_in_orbit = ship_radius < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit_max);
  74. /* check and update target posistion */
  75. if ship.target_dir.length_sqr() == 0.0
  76. || ship_in_orbit != target_in_orbit
  77. || ship.target_dir * ship_to_target <= 0.0
  78. {
  79. if ship_in_orbit && orbit_max > 0.0 {
  80. let orbit_to_ship_vec3 = Vector3f::new(orbit_to_ship.x, orbit_to_ship.y, 0.0);
  81. let ship_dir_vec3 = Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0);
  82. let dir = if orbit_to_ship_vec3.cross(&ship_dir_vec3).z > 0.0 {
  83. 1.0
  84. } else {
  85. -1.0
  86. };
  87. let angle = orbit_to_ship.angle2(&VECTOR_2F_POS_X);
  88. let angle = angle
  89. + (SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random()) * dir
  90. / orbit_max;
  91. let radius = orbit_min + (orbit_max - orbit_min) * random::<f32>();
  92. ship.target_pos.x = orbit_pos.x + radius * angle.cos();
  93. ship.target_pos.y = orbit_pos.y + radius * angle.sin();
  94. } else {
  95. ship.target_pos = orbit_pos;
  96. }
  97. ship.target_dir = (ship.target_pos - position.pos).normalize();
  98. }
  99. /* update ship direction */
  100. let angle = ship_to_target.angle2(&velocity.dir);
  101. if angle.into_inner().abs() > 0.0001 {
  102. let dir = angle.into_inner() / angle.abs().into_inner();
  103. let agility = if ship_in_orbit {
  104. SHIP_ORBIT_AGILITY
  105. } else {
  106. ship.agility
  107. };
  108. let rot_speed = agility * linear_step(0.0, 45.0, angle.abs().into_deg().into_inner());
  109. let m = Matrix3f::new(
  110. Vector3f::new(velocity.dir.y, -velocity.dir.x, 0.0),
  111. Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0),
  112. Vector3f::new(0.0, 0.0, 1.0),
  113. );
  114. let m = m * Matrix3f::rotate(rot_speed * -dir * delta);
  115. velocity.dir = Vector2f::new(m.axis_y.x, m.axis_y.y);
  116. }
  117. }