JitteringSystem.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. using System.Numerics;
  2. using Content.Shared.Jittering;
  3. using Robust.Client.Animations;
  4. using Robust.Client.GameObjects;
  5. using Robust.Shared.Random;
  6. namespace Content.Client.Jittering
  7. {
  8. public sealed class JitteringSystem : SharedJitteringSystem
  9. {
  10. [Dependency] private readonly IRobustRandom _random = default!;
  11. [Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!;
  12. private readonly float[] _sign = { -1, 1 };
  13. private readonly string _jitterAnimationKey = "jittering";
  14. public override void Initialize()
  15. {
  16. base.Initialize();
  17. SubscribeLocalEvent<JitteringComponent, ComponentStartup>(OnStartup);
  18. SubscribeLocalEvent<JitteringComponent, ComponentShutdown>(OnShutdown);
  19. SubscribeLocalEvent<JitteringComponent, AnimationCompletedEvent>(OnAnimationCompleted);
  20. }
  21. private void OnStartup(EntityUid uid, JitteringComponent jittering, ComponentStartup args)
  22. {
  23. if (!TryComp(uid, out SpriteComponent? sprite))
  24. return;
  25. var animationPlayer = EnsureComp<AnimationPlayerComponent>(uid);
  26. jittering.StartOffset = sprite.Offset;
  27. _animationPlayer.Play(uid, animationPlayer, GetAnimation(jittering, sprite), _jitterAnimationKey);
  28. }
  29. private void OnShutdown(EntityUid uid, JitteringComponent jittering, ComponentShutdown args)
  30. {
  31. if (TryComp(uid, out AnimationPlayerComponent? animationPlayer))
  32. _animationPlayer.Stop(uid, animationPlayer, _jitterAnimationKey);
  33. if (TryComp(uid, out SpriteComponent? sprite))
  34. sprite.Offset = jittering.StartOffset;
  35. }
  36. private void OnAnimationCompleted(EntityUid uid, JitteringComponent jittering, AnimationCompletedEvent args)
  37. {
  38. if(args.Key != _jitterAnimationKey)
  39. return;
  40. if (!args.Finished)
  41. return;
  42. if (TryComp(uid, out AnimationPlayerComponent? animationPlayer)
  43. && TryComp(uid, out SpriteComponent? sprite))
  44. _animationPlayer.Play(uid, animationPlayer, GetAnimation(jittering, sprite), _jitterAnimationKey);
  45. }
  46. private Animation GetAnimation(JitteringComponent jittering, SpriteComponent sprite)
  47. {
  48. var amplitude = MathF.Min(4f, jittering.Amplitude / 100f + 1f) / 10f;
  49. var offset = new Vector2(_random.NextFloat(amplitude/4f, amplitude),
  50. _random.NextFloat(amplitude / 4f, amplitude / 3f));
  51. offset.X *= _random.Pick(_sign);
  52. offset.Y *= _random.Pick(_sign);
  53. if (Math.Sign(offset.X) == Math.Sign(jittering.LastJitter.X)
  54. || Math.Sign(offset.Y) == Math.Sign(jittering.LastJitter.Y))
  55. {
  56. // If the sign is the same as last time on both axis we flip one randomly
  57. // to avoid jitter staying in one quadrant too much.
  58. if (_random.Prob(0.5f))
  59. offset.X *= -1;
  60. else
  61. offset.Y *= -1;
  62. }
  63. var length = 0f;
  64. // avoid dividing by 0 so animations don't try to be infinitely long
  65. if (jittering.Frequency > 0)
  66. length = 1f / jittering.Frequency;
  67. jittering.LastJitter = offset;
  68. return new Animation()
  69. {
  70. Length = TimeSpan.FromSeconds(length),
  71. AnimationTracks =
  72. {
  73. new AnimationTrackComponentProperty()
  74. {
  75. ComponentType = typeof(SpriteComponent),
  76. Property = nameof(SpriteComponent.Offset),
  77. KeyFrames =
  78. {
  79. new AnimationTrackProperty.KeyFrame(sprite.Offset, 0f),
  80. new AnimationTrackProperty.KeyFrame(jittering.StartOffset + offset, length),
  81. }
  82. }
  83. }
  84. };
  85. }
  86. }
  87. }