您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

291 行
9.6 KiB

  1. use glc::{
  2. math::{linear_step, sqr},
  3. matrix::Matrix3f,
  4. vector::{Angle, Vector2f, Vector3f},
  5. };
  6. use rand::random;
  7. use shrev::ReaderId;
  8. use specs::{
  9. hibitset::BitSet, prelude::*, world::Index, Entities, ParJoin, Read, ReadStorage, System,
  10. WriteStorage,
  11. };
  12. use crate::{
  13. components::{Fleet, FleetOwned, Obstacle, Position, Ship, ShipObstacle, Velocity},
  14. constants::{
  15. SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND,
  16. SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X,
  17. },
  18. misc::ComponentEvent,
  19. resources::Global,
  20. return_if_none,
  21. };
  22. pub struct Ships {
  23. need_update: BitSet,
  24. fleet_owned_id: ReaderId<ComponentEvent<FleetOwned>>,
  25. }
  26. #[derive(SystemData)]
  27. pub struct ShipsData<'a> {
  28. global: Read<'a, Global>,
  29. entities: Entities<'a>,
  30. ships: WriteStorage<'a, Ship>,
  31. velocities: WriteStorage<'a, Velocity>,
  32. fleet_owned: ReadStorage<'a, FleetOwned>,
  33. positions: ReadStorage<'a, Position>,
  34. obstacles: ReadStorage<'a, Obstacle>,
  35. fleets: ReadStorage<'a, Fleet>,
  36. }
  37. struct Processor<'a> {
  38. need_update: &'a BitSet,
  39. entities: &'a Entities<'a>,
  40. positions: &'a ReadStorage<'a, Position>,
  41. obstacles: &'a ReadStorage<'a, Obstacle>,
  42. fleets: &'a ReadStorage<'a, Fleet>,
  43. delta: f32,
  44. }
  45. impl Ships {
  46. pub fn new(world: &mut World) -> Self {
  47. let need_update = BitSet::new();
  48. let fleet_owned_id = unsafe {
  49. WriteStorage::<FleetOwned>::setup(world);
  50. let mut fleet_owned = world.system_data::<WriteStorage<FleetOwned>>();
  51. fleet_owned
  52. .unprotected_storage_mut()
  53. .channel_mut()
  54. .register_reader()
  55. };
  56. Self {
  57. need_update,
  58. fleet_owned_id,
  59. }
  60. }
  61. fn progress_events(&mut self, fleet_owned: &ReadStorage<'_, FleetOwned>) {
  62. self.need_update.clear();
  63. let events = fleet_owned
  64. .unprotected_storage()
  65. .channel()
  66. .read(&mut self.fleet_owned_id);
  67. for event in events {
  68. let id = match event {
  69. ComponentEvent::Inserted(id) => id,
  70. ComponentEvent::Modified(id, _) => id,
  71. ComponentEvent::Removed(id, _) => id,
  72. };
  73. self.need_update.add(*id);
  74. }
  75. }
  76. }
  77. impl<'a> System<'a> for Ships {
  78. type SystemData = ShipsData<'a>;
  79. fn run(&mut self, data: Self::SystemData) {
  80. let ShipsData {
  81. global,
  82. entities,
  83. mut ships,
  84. mut velocities,
  85. fleet_owned,
  86. positions,
  87. obstacles,
  88. fleets,
  89. } = data;
  90. self.progress_events(&fleet_owned);
  91. /* update ships */
  92. let processor = Processor {
  93. need_update: &self.need_update,
  94. entities: &entities,
  95. positions: &positions,
  96. obstacles: &obstacles,
  97. fleets: &fleets,
  98. delta: global.delta * global.world_speed,
  99. };
  100. let data = (
  101. positions.mask(),
  102. &mut ships,
  103. &mut velocities,
  104. &positions,
  105. &fleet_owned,
  106. );
  107. data.par_join()
  108. .for_each(|(id, ship, velocity, position, fleet_owned)| {
  109. processor.progress_ship(id, ship, velocity, position, fleet_owned);
  110. });
  111. }
  112. }
  113. impl Processor<'_> {
  114. fn progress_ship(
  115. &self,
  116. id: Index,
  117. ship: &mut Ship,
  118. velocity: &mut Velocity,
  119. position: &Position,
  120. fleet_owned: &FleetOwned,
  121. ) {
  122. let fleet_id = fleet_owned.owner;
  123. let fleet = return_if_none!(self.fleets.get(fleet_id));
  124. let orbit_pos = return_if_none!(self.positions.get(fleet_id)).pos;
  125. let ship_pos = position.pos;
  126. let target_pos = ship.target_pos;
  127. let target_dir = ship.target_dir;
  128. let orbit_to_target = target_pos - orbit_pos;
  129. let orbit_to_ship = ship_pos - orbit_pos;
  130. let mut ship_to_target = target_pos - position.pos;
  131. let r_ship = orbit_to_ship.length_sqr();
  132. let r_target = orbit_to_target.length_sqr();
  133. let orbit_min = fleet.orbit_min;
  134. let orbit_max = fleet.orbit_max;
  135. let target_in_orbit = (r_target <= sqr(fleet.orbit_max)) && (r_target >= sqr(orbit_min));
  136. let ship_in_orbit = r_ship < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit_max);
  137. let need_update = self.need_update.contains(id);
  138. let has_target = target_dir.length_sqr() != 0.0;
  139. let passed_target = target_dir * ship_to_target <= 0.0;
  140. /* check and update target posistion */
  141. if need_update || !has_target || passed_target || ship_in_orbit != target_in_orbit {
  142. let target_pos = if ship_in_orbit && fleet.orbit_max > 0.0 {
  143. let orbit_to_ship_vec3 = Vector3f::new(orbit_to_ship.x, orbit_to_ship.y, 0.0);
  144. let ship_dir_vec3 = Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0);
  145. let dir = if orbit_to_ship_vec3.cross(&ship_dir_vec3).z > 0.0 {
  146. 1.0
  147. } else {
  148. -1.0
  149. };
  150. let add = SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random();
  151. let angle = orbit_to_ship.angle2(&VECTOR_2F_POS_X);
  152. let angle = angle + add * dir / orbit_max;
  153. let radius = orbit_min + (orbit_max - orbit_min) * random::<f32>();
  154. Vector2f::new(
  155. orbit_pos.x + radius * angle.cos(),
  156. orbit_pos.y + radius * angle.sin(),
  157. )
  158. } else {
  159. ship.obstacle = ShipObstacle::Search;
  160. orbit_pos
  161. };
  162. ship.target_pos = target_pos;
  163. ship.target_dir = (target_pos - ship_pos).normalize();
  164. ship_to_target = target_pos - ship_pos;
  165. }
  166. /* check if obstacle is still valid */
  167. if ship_in_orbit {
  168. ship.obstacle = ShipObstacle::Done;
  169. } else if let ShipObstacle::Known(obstacle) = ship.obstacle {
  170. if let Some(position) = self.positions.get(obstacle) {
  171. let obstacle_fleet = self.fleets.get(obstacle).unwrap();
  172. let obstacle_pos = position.pos;
  173. let ship_to_obstacle = obstacle_pos - ship_pos;
  174. let obstacle_angle = ship_to_target
  175. .angle2(&ship_to_obstacle)
  176. .into_deg()
  177. .into_inner()
  178. .abs();
  179. let orbit_sqr = obstacle_fleet.orbit_max * obstacle_fleet.orbit_max;
  180. if (obstacle_angle > 90.0 && ship_to_obstacle.length_sqr() > orbit_sqr)
  181. || obstacle_angle > 170.0
  182. {
  183. ship.obstacle = ShipObstacle::Search;
  184. }
  185. } else {
  186. ship.obstacle = ShipObstacle::Search;
  187. }
  188. }
  189. /* find obstacle */
  190. if !ship_in_orbit && ship.obstacle == ShipObstacle::Search {
  191. let mut dist_sqr = f32::MAX;
  192. for (e, position, _) in (self.entities, self.positions, self.obstacles).join() {
  193. let obstacle_pos = position.pos;
  194. let ship_to_obstacle = obstacle_pos - ship_pos;
  195. if ship_to_target * ship_to_obstacle < 0.0 {
  196. continue; // obstacle is behind the ship
  197. }
  198. let len_sqr = ship_to_obstacle.length_sqr();
  199. if len_sqr < dist_sqr {
  200. dist_sqr = len_sqr;
  201. ship.obstacle = ShipObstacle::Known(e);
  202. }
  203. }
  204. if let ShipObstacle::Known(e) = ship.obstacle {
  205. if e == fleet_owned.owner {
  206. ship.obstacle = ShipObstacle::Done;
  207. }
  208. }
  209. }
  210. /* check the obstacle */
  211. let mut expected_dir = ship_to_target;
  212. if let ShipObstacle::Known(obstacle) = ship.obstacle {
  213. let obstacle_pos = self.positions.get(obstacle).unwrap();
  214. let obstacle_fleet = self.fleets.get(obstacle).unwrap();
  215. let ship_to_obstacle = obstacle_pos.pos - ship_pos;
  216. let orbit = ship_to_obstacle.length();
  217. if orbit < obstacle_fleet.orbit_max {
  218. let orbit_min = obstacle_fleet.orbit_min;
  219. let orbit_max = obstacle_fleet.orbit_max;
  220. let mut tangent = Vector2f::new(-ship_to_obstacle.y, ship_to_obstacle.x);
  221. let radius = obstacle_pos.shape.radius();
  222. let mut adjust_low = linear_step(orbit_min, radius, orbit);
  223. let adjust_high = 1.0 - linear_step(orbit_max, orbit_min, orbit);
  224. if ship_to_target * tangent < 0.0 {
  225. tangent = -tangent;
  226. } else {
  227. adjust_low = -adjust_low;
  228. }
  229. let a_low = Angle::Deg(45.0);
  230. let a_high = tangent.angle2(&ship_to_target);
  231. let mat = Matrix3f::rotate(a_low * adjust_low + a_high * adjust_high);
  232. expected_dir = mat.transform(tangent);
  233. }
  234. }
  235. /* update ship direction */
  236. let angle = expected_dir.angle2(&velocity.dir);
  237. if angle.into_inner().abs() > 0.0001 {
  238. let dir = angle.into_inner() / angle.abs().into_inner();
  239. let agility = if ship_in_orbit {
  240. SHIP_ORBIT_AGILITY
  241. } else {
  242. ship.agility
  243. };
  244. let rot_speed = agility * linear_step(0.0, 45.0, angle.abs().into_deg().into_inner());
  245. velocity.dir = Matrix3f::rotate(rot_speed * -dir * self.delta).transform(velocity.dir);
  246. }
  247. }
  248. }