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.

139 rivejä
4.6 KiB

  1. use glc::{
  2. math::linear_step,
  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::{FleetOrbiting, FleetOwned, MeetingPoint, Position, Ship, ShipOrbiting},
  10. constants::{SHIP_DATA_IN_ORBIT, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND},
  11. misc::StorageHelperMut,
  12. resources::Global,
  13. };
  14. #[derive(Default)]
  15. pub struct ShipsOrbiting;
  16. #[derive(SystemData)]
  17. pub struct ShipsData<'a> {
  18. global: Read<'a, Global>,
  19. positions: ReadStorage<'a, Position>,
  20. fleet_owned: ReadStorage<'a, FleetOwned>,
  21. ships: WriteStorage<'a, Ship>,
  22. ships_orbiting: WriteStorage<'a, ShipOrbiting>,
  23. fleets_orbiting: ReadStorage<'a, FleetOrbiting>,
  24. meeting_points: ReadStorage<'a, MeetingPoint>,
  25. }
  26. struct Processor<'a> {
  27. delta: f32,
  28. positions: &'a ReadStorage<'a, Position>,
  29. meeting_points: &'a ReadStorage<'a, MeetingPoint>,
  30. fleets_orbiting: &'a ReadStorage<'a, FleetOrbiting>,
  31. }
  32. impl<'a> System<'a> for ShipsOrbiting {
  33. type SystemData = ShipsData<'a>;
  34. fn run(&mut self, data: Self::SystemData) {
  35. let ShipsData {
  36. global,
  37. positions,
  38. fleet_owned,
  39. mut ships,
  40. mut ships_orbiting,
  41. fleets_orbiting,
  42. meeting_points,
  43. } = data;
  44. /* update ships */
  45. let processor = Processor {
  46. delta: global.delta * global.world_speed,
  47. positions: &positions,
  48. fleets_orbiting: &fleets_orbiting,
  49. meeting_points: &meeting_points,
  50. };
  51. ships.set_event_emission(false);
  52. let data = (&positions, &fleet_owned, &mut ships, &mut ships_orbiting);
  53. data.par_join()
  54. .for_each(|(position, fleet_owned, ship, ship_orbiting)| {
  55. processor.progress_ship(position, fleet_owned, ship, ship_orbiting);
  56. });
  57. ships.set_event_emission(true);
  58. }
  59. }
  60. impl Processor<'_> {
  61. fn progress_ship(
  62. &self,
  63. position: &Position,
  64. fleet_owned: &FleetOwned,
  65. ship: &mut Ship,
  66. ship_orbiting: &mut ShipOrbiting,
  67. ) {
  68. let fleet_id = fleet_owned.owner();
  69. let fleet_orbiting = self.fleets_orbiting.get(fleet_id).unwrap();
  70. let meeting_point_id = fleet_orbiting.meeting_point();
  71. let meeting_point = self.meeting_points.get(meeting_point_id).unwrap();
  72. let meeting_point_pos = self.positions.get(meeting_point_id).unwrap().get();
  73. let ship_pos = position.get();
  74. let target_pos = *ship_orbiting.target_pos();
  75. let target_dir = ship_orbiting.target_dir();
  76. let meeting_point_to_ship = ship_pos - meeting_point_pos;
  77. let mut ship_to_target = target_pos - ship_pos;
  78. let has_target = target_dir.length_sqr() != 0.0;
  79. let passed_target = target_dir * ship_to_target <= 0.0;
  80. /* check and update target posistion */
  81. if !has_target || passed_target {
  82. let meeting_point_to_ship_vec3 =
  83. Vector3f::new(meeting_point_to_ship.x, meeting_point_to_ship.y, 0.0);
  84. let ship_dir_vec3 = ship.dir().into_vec3();
  85. let dir = if meeting_point_to_ship_vec3.cross(&ship_dir_vec3).z > 0.0 {
  86. 1.0
  87. } else {
  88. -1.0
  89. };
  90. let meeting_point_min = meeting_point.min();
  91. let meeting_point_max = meeting_point.max();
  92. const VECTOR2F_POS_X: Vector2f = Vector2f::new(1.0, 0.0);
  93. let add = SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random::<f32>();
  94. let angle =
  95. meeting_point_to_ship.angle2(&VECTOR2F_POS_X) + (add * dir / meeting_point_max);
  96. let radius =
  97. meeting_point_min + (meeting_point_max - meeting_point_min) * random::<f32>();
  98. let target_pos = Vector2f::new(
  99. meeting_point_pos.x + radius * angle.cos(),
  100. meeting_point_pos.y + radius * angle.sin(),
  101. );
  102. ship_to_target = target_pos - ship_pos;
  103. let target_dir = ship_to_target.normalize();
  104. ship_orbiting.set_target(target_pos, target_dir);
  105. }
  106. /* update ship direction */
  107. let angle = ship_to_target.angle2(ship.dir());
  108. if angle.into_inner().abs() > 0.0001 {
  109. let dir = angle.into_inner() / angle.abs().into_inner();
  110. let agility = SHIP_DATA_IN_ORBIT.agility;
  111. let rot_speed = agility * linear_step(0.0, 45.0, angle.abs().into_deg().into_inner());
  112. *ship.dir_mut() *= Matrix3f::rotate(rot_speed * -dir * self.delta);
  113. }
  114. }
  115. }