ChasingWalkSystem.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. using System.Linq;
  2. using System.Numerics;
  3. using Content.Server.Physics.Components;
  4. using Robust.Shared.Random;
  5. using Robust.Shared.Timing;
  6. using Robust.Shared.Physics.Systems;
  7. using Robust.Shared.Physics.Components;
  8. using Robust.Shared.Physics.Controllers;
  9. namespace Content.Server.Physics.Controllers;
  10. /// <summary>
  11. /// A system which makes its entity chasing another entity with selected component.
  12. /// </summary>
  13. public sealed class ChasingWalkSystem : VirtualController
  14. {
  15. [Dependency] private readonly IGameTiming _gameTiming = default!;
  16. [Dependency] private readonly IRobustRandom _random = default!;
  17. [Dependency] private readonly SharedTransformSystem _transform = default!;
  18. [Dependency] private readonly EntityLookupSystem _lookup = default!;
  19. [Dependency] private readonly SharedPhysicsSystem _physics = default!;
  20. private readonly HashSet<Entity<IComponent>> _potentialChaseTargets = new();
  21. public override void Initialize()
  22. {
  23. base.Initialize();
  24. SubscribeLocalEvent<ChasingWalkComponent, MapInitEvent>(OnChasingMapInit);
  25. }
  26. private void OnChasingMapInit(EntityUid uid, ChasingWalkComponent component, MapInitEvent args)
  27. {
  28. component.NextImpulseTime = _gameTiming.CurTime;
  29. component.NextChangeVectorTime = _gameTiming.CurTime;
  30. }
  31. public override void UpdateBeforeSolve(bool prediction, float frameTime)
  32. {
  33. base.UpdateBeforeSolve(prediction, frameTime);
  34. var query = EntityQueryEnumerator<ChasingWalkComponent>();
  35. while (query.MoveNext(out var uid, out var chasing))
  36. {
  37. //Set Velocity to Target
  38. if (chasing.NextImpulseTime <= _gameTiming.CurTime)
  39. {
  40. ForceImpulse(uid, chasing);
  41. chasing.NextImpulseTime += TimeSpan.FromSeconds(chasing.ImpulseInterval);
  42. }
  43. //Change Target
  44. if (chasing.NextChangeVectorTime <= _gameTiming.CurTime)
  45. {
  46. ChangeTarget(uid, chasing);
  47. var delay = TimeSpan.FromSeconds(_random.NextFloat(chasing.ChangeVectorMinInterval, chasing.ChangeVectorMaxInterval));
  48. chasing.NextChangeVectorTime += delay;
  49. }
  50. }
  51. }
  52. private void ChangeTarget(EntityUid uid, ChasingWalkComponent component)
  53. {
  54. if (component.ChasingComponent.Count <= 0)
  55. return;
  56. //We find our coordinates and calculate the radius of the target search.
  57. var xform = Transform(uid);
  58. var range = component.MaxChaseRadius;
  59. var compType = _random.Pick(component.ChasingComponent.Values).Component.GetType();
  60. _potentialChaseTargets.Clear();
  61. _lookup.GetEntitiesInRange(compType, _transform.GetMapCoordinates(xform), range, _potentialChaseTargets, LookupFlags.Uncontained);
  62. //If there are no required components in the radius, don't moving.
  63. if (_potentialChaseTargets.Count <= 0)
  64. return;
  65. //In the case of finding required components, we choose a random one of them and remember its uid.
  66. component.ChasingEntity = _random.Pick(_potentialChaseTargets).Owner;
  67. component.Speed = _random.NextFloat(component.MinSpeed, component.MaxSpeed);
  68. }
  69. //pushing the entity toward its target
  70. private void ForceImpulse(EntityUid uid, ChasingWalkComponent component)
  71. {
  72. if (Deleted(component.ChasingEntity) || component.ChasingEntity == null)
  73. {
  74. ChangeTarget(uid, component);
  75. return;
  76. }
  77. if (!TryComp<PhysicsComponent>(uid, out var physics))
  78. return;
  79. //Calculating direction to the target.
  80. var pos1 = _transform.GetWorldPosition(uid);
  81. var pos2 = _transform.GetWorldPosition(component.ChasingEntity.Value);
  82. var delta = pos2 - pos1;
  83. var speed = delta.Length() > 0 ? delta.Normalized() * component.Speed : Vector2.Zero;
  84. _physics.SetLinearVelocity(uid, speed);
  85. _physics.SetBodyStatus(uid, physics, BodyStatus.InAir); //If this is not done, from the explosion up close, the tesla will "Fall" to the ground, and almost stop moving.
  86. }
  87. }