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.

204 lines
6.3 KiB

  1. use glc::{
  2. math::{linear_step, sqr},
  3. matrix::Matrix3f,
  4. vector::{Vector2f, Vector3f},
  5. };
  6. use rand::random;
  7. use shrev::ReaderId;
  8. use specs::{
  9. hibitset::BitSet, prelude::*, world::Index, ParJoin, Read, ReadStorage, System, WriteStorage,
  10. };
  11. use crate::{
  12. components::{Fleet, FleetOwned, Position, Ship, Velocity},
  13. constants::{
  14. SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND,
  15. SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X,
  16. },
  17. misc::ComponentEvent,
  18. resources::Global,
  19. return_if_none,
  20. };
  21. pub struct Ships {
  22. need_update: BitSet,
  23. fleet_owned_id: ReaderId<ComponentEvent<FleetOwned>>,
  24. }
  25. #[derive(SystemData)]
  26. pub struct ShipsData<'a> {
  27. global: Read<'a, Global>,
  28. ships: WriteStorage<'a, Ship>,
  29. velocities: WriteStorage<'a, Velocity>,
  30. fleet_owned: ReadStorage<'a, FleetOwned>,
  31. positions: ReadStorage<'a, Position>,
  32. fleets: ReadStorage<'a, Fleet>,
  33. }
  34. struct Processor<'a> {
  35. need_update: &'a BitSet,
  36. positions: &'a ReadStorage<'a, Position>,
  37. fleets: &'a ReadStorage<'a, Fleet>,
  38. delta: f32,
  39. }
  40. impl Ships {
  41. pub fn new(world: &mut World) -> Self {
  42. let need_update = BitSet::new();
  43. let fleet_owned_id = unsafe {
  44. WriteStorage::<FleetOwned>::setup(world);
  45. let mut fleet_owned = world.system_data::<WriteStorage<FleetOwned>>();
  46. fleet_owned
  47. .unprotected_storage_mut()
  48. .channel_mut()
  49. .register_reader()
  50. };
  51. Self {
  52. need_update,
  53. fleet_owned_id,
  54. }
  55. }
  56. fn progress_events(&mut self, fleet_owned: &ReadStorage<'_, FleetOwned>) {
  57. self.need_update.clear();
  58. let events = fleet_owned
  59. .unprotected_storage()
  60. .channel()
  61. .read(&mut self.fleet_owned_id);
  62. for event in events {
  63. let id = match event {
  64. ComponentEvent::Inserted(id) => id,
  65. ComponentEvent::Modified(id, _) => id,
  66. ComponentEvent::Removed(id, _) => id,
  67. };
  68. self.need_update.add(*id);
  69. }
  70. }
  71. }
  72. impl<'a> System<'a> for Ships {
  73. type SystemData = ShipsData<'a>;
  74. fn run(&mut self, data: Self::SystemData) {
  75. let ShipsData {
  76. global,
  77. mut ships,
  78. mut velocities,
  79. fleet_owned,
  80. positions,
  81. fleets,
  82. } = data;
  83. self.progress_events(&fleet_owned);
  84. /* update ships */
  85. let processor = Processor {
  86. need_update: &self.need_update,
  87. positions: &positions,
  88. fleets: &fleets,
  89. delta: global.delta,
  90. };
  91. (
  92. positions.mask(),
  93. &mut ships,
  94. &mut velocities,
  95. &positions,
  96. &fleet_owned,
  97. )
  98. .par_join()
  99. .for_each(|(id, ship, velocity, position, fleet_owned)| {
  100. processor.progress_ship(id, ship, velocity, position, fleet_owned);
  101. });
  102. }
  103. }
  104. impl Processor<'_> {
  105. fn progress_ship(
  106. &self,
  107. id: Index,
  108. ship: &mut Ship,
  109. velocity: &mut Velocity,
  110. position: &Position,
  111. fleet_owned: &FleetOwned,
  112. ) {
  113. let fleet_id = fleet_owned.owner;
  114. let fleet = return_if_none!(self.fleets.get(fleet_id));
  115. let orbit_pos = return_if_none!(self.positions.get(fleet_id)).pos;
  116. let ship_pos = position.pos;
  117. let target_pos = ship.target_pos;
  118. let target_dir = ship.target_dir;
  119. let orbit_to_target = target_pos - orbit_pos;
  120. let orbit_to_ship = position.pos - orbit_pos;
  121. let ship_to_target = target_pos - position.pos;
  122. let r_ship = orbit_to_ship.length_sqr();
  123. let r_target = orbit_to_target.length_sqr();
  124. let orbit_min = fleet.orbit_min;
  125. let orbit_max = fleet.orbit_max;
  126. let target_in_orbit = (r_target <= sqr(fleet.orbit_max)) && (r_target >= sqr(orbit_min));
  127. let ship_in_orbit = r_ship < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit_max);
  128. let need_update = self.need_update.contains(id);
  129. let has_target = target_dir.length_sqr() != 0.0;
  130. let passed_target = target_dir * ship_to_target <= 0.0;
  131. /* check and update target posistion */
  132. if need_update || !has_target || passed_target || ship_in_orbit != target_in_orbit {
  133. let target_pos = if ship_in_orbit && fleet.orbit_max > 0.0 {
  134. let orbit_to_ship_vec3 = Vector3f::new(orbit_to_ship.x, orbit_to_ship.y, 0.0);
  135. let ship_dir_vec3 = Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0);
  136. let dir = if orbit_to_ship_vec3.cross(&ship_dir_vec3).z > 0.0 {
  137. 1.0
  138. } else {
  139. -1.0
  140. };
  141. let angle = orbit_to_ship.angle2(&VECTOR_2F_POS_X);
  142. let angle = angle
  143. + (SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random()) * dir
  144. / fleet.orbit_max;
  145. let radius =
  146. fleet.orbit_min + (fleet.orbit_max - fleet.orbit_min) * random::<f32>();
  147. Vector2f::new(
  148. orbit_pos.x + radius * angle.cos(),
  149. orbit_pos.y + radius * angle.sin(),
  150. )
  151. } else {
  152. orbit_pos
  153. };
  154. ship.target_pos = target_pos;
  155. ship.target_dir = (target_pos - ship_pos).normalize();
  156. }
  157. /* update ship direction */
  158. let angle = ship_to_target.angle2(&velocity.dir);
  159. if angle.into_inner().abs() > 0.0001 {
  160. let dir = angle.into_inner() / angle.abs().into_inner();
  161. let agility = if ship_in_orbit {
  162. SHIP_ORBIT_AGILITY
  163. } else {
  164. ship.agility
  165. };
  166. let rot_speed = agility * linear_step(0.0, 45.0, angle.abs().into_deg().into_inner());
  167. let m = Matrix3f::new(
  168. Vector3f::new(velocity.dir.y, -velocity.dir.x, 0.0),
  169. Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0),
  170. Vector3f::new(0.0, 0.0, 1.0),
  171. );
  172. let m = m * Matrix3f::rotate(rot_speed * -dir * self.delta);
  173. velocity.dir = Vector2f::new(m.axis_y.x, m.axis_y.y);
  174. }
  175. }
  176. }