MeleeWeaponSystem.Effects.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. using System.Numerics;
  2. using Content.Client.Animations;
  3. using Content.Client.Weapons.Melee.Components;
  4. using Content.Shared.Weapons.Melee;
  5. using Robust.Client.Animations;
  6. using Robust.Client.GameObjects;
  7. using Robust.Shared.Animations;
  8. using Robust.Shared.Map;
  9. namespace Content.Client.Weapons.Melee;
  10. public sealed partial class MeleeWeaponSystem
  11. {
  12. private const string FadeAnimationKey = "melee-fade";
  13. private const string SlashAnimationKey = "melee-slash";
  14. private const string ThrustAnimationKey = "melee-thrust";
  15. /// <summary>
  16. /// Does all of the melee effects for a player that are predicted, i.e. character lunge and weapon animation.
  17. /// </summary>
  18. public override void DoLunge(EntityUid user, EntityUid weapon, Angle angle, Vector2 localPos, string? animation, bool predicted = true)
  19. {
  20. if (!Timing.IsFirstTimePredicted)
  21. return;
  22. var lunge = GetLungeAnimation(localPos);
  23. // Stop any existing lunges on the user.
  24. _animation.Stop(user, MeleeLungeKey);
  25. _animation.Play(user, lunge, MeleeLungeKey);
  26. if (localPos == Vector2.Zero || animation == null)
  27. return;
  28. if (!_xformQuery.TryGetComponent(user, out var userXform) || userXform.MapID == MapId.Nullspace)
  29. return;
  30. var animationUid = Spawn(animation, userXform.Coordinates);
  31. if (!TryComp<SpriteComponent>(animationUid, out var sprite)
  32. || !TryComp<WeaponArcVisualsComponent>(animationUid, out var arcComponent))
  33. {
  34. return;
  35. }
  36. var spriteRotation = Angle.Zero;
  37. if (arcComponent.Animation != WeaponArcAnimation.None
  38. && TryComp(weapon, out MeleeWeaponComponent? meleeWeaponComponent))
  39. {
  40. if (user != weapon
  41. && TryComp(weapon, out SpriteComponent? weaponSpriteComponent))
  42. sprite.CopyFrom(weaponSpriteComponent);
  43. spriteRotation = meleeWeaponComponent.WideAnimationRotation;
  44. if (meleeWeaponComponent.SwingLeft)
  45. angle *= -1;
  46. }
  47. sprite.Rotation = localPos.ToWorldAngle();
  48. var distance = Math.Clamp(localPos.Length() / 2f, 0.2f, 1f);
  49. var xform = _xformQuery.GetComponent(animationUid);
  50. TrackUserComponent track;
  51. switch (arcComponent.Animation)
  52. {
  53. case WeaponArcAnimation.Slash:
  54. track = EnsureComp<TrackUserComponent>(animationUid);
  55. track.User = user;
  56. _animation.Play(animationUid, GetSlashAnimation(sprite, angle, spriteRotation), SlashAnimationKey);
  57. if (arcComponent.Fadeout)
  58. _animation.Play(animationUid, GetFadeAnimation(sprite, 0.065f, 0.065f + 0.05f), FadeAnimationKey);
  59. break;
  60. case WeaponArcAnimation.Thrust:
  61. track = EnsureComp<TrackUserComponent>(animationUid);
  62. track.User = user;
  63. _animation.Play(animationUid, GetThrustAnimation(sprite, distance, spriteRotation), ThrustAnimationKey);
  64. if (arcComponent.Fadeout)
  65. _animation.Play(animationUid, GetFadeAnimation(sprite, 0.05f, 0.15f), FadeAnimationKey);
  66. break;
  67. case WeaponArcAnimation.None:
  68. var (mapPos, mapRot) = TransformSystem.GetWorldPositionRotation(userXform);
  69. var worldPos = mapPos + (mapRot - userXform.LocalRotation).RotateVec(localPos);
  70. var newLocalPos = Vector2.Transform(worldPos, TransformSystem.GetInvWorldMatrix(xform.ParentUid));
  71. TransformSystem.SetLocalPositionNoLerp(animationUid, newLocalPos, xform);
  72. if (arcComponent.Fadeout)
  73. _animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
  74. break;
  75. }
  76. }
  77. private Animation GetSlashAnimation(SpriteComponent sprite, Angle arc, Angle spriteRotation)
  78. {
  79. const float slashStart = 0.03f;
  80. const float slashEnd = 0.065f;
  81. const float length = slashEnd + 0.05f;
  82. var startRotation = sprite.Rotation + arc / 2;
  83. var endRotation = sprite.Rotation - arc / 2;
  84. var startRotationOffset = startRotation.RotateVec(new Vector2(0f, -1f));
  85. var endRotationOffset = endRotation.RotateVec(new Vector2(0f, -1f));
  86. startRotation += spriteRotation;
  87. endRotation += spriteRotation;
  88. return new Animation()
  89. {
  90. Length = TimeSpan.FromSeconds(length),
  91. AnimationTracks =
  92. {
  93. new AnimationTrackComponentProperty()
  94. {
  95. ComponentType = typeof(SpriteComponent),
  96. Property = nameof(SpriteComponent.Rotation),
  97. KeyFrames =
  98. {
  99. new AnimationTrackProperty.KeyFrame(startRotation, 0f),
  100. new AnimationTrackProperty.KeyFrame(startRotation, slashStart),
  101. new AnimationTrackProperty.KeyFrame(endRotation, slashEnd)
  102. }
  103. },
  104. new AnimationTrackComponentProperty()
  105. {
  106. ComponentType = typeof(SpriteComponent),
  107. Property = nameof(SpriteComponent.Offset),
  108. KeyFrames =
  109. {
  110. new AnimationTrackProperty.KeyFrame(startRotationOffset, 0f),
  111. new AnimationTrackProperty.KeyFrame(startRotationOffset, slashStart),
  112. new AnimationTrackProperty.KeyFrame(endRotationOffset, slashEnd)
  113. }
  114. },
  115. }
  116. };
  117. }
  118. private Animation GetThrustAnimation(SpriteComponent sprite, float distance, Angle spriteRotation)
  119. {
  120. const float thrustEnd = 0.05f;
  121. const float length = 0.15f;
  122. var startOffset = sprite.Rotation.RotateVec(new Vector2(0f, -distance / 5f));
  123. var endOffset = sprite.Rotation.RotateVec(new Vector2(0f, -distance));
  124. sprite.Rotation += spriteRotation;
  125. return new Animation()
  126. {
  127. Length = TimeSpan.FromSeconds(length),
  128. AnimationTracks =
  129. {
  130. new AnimationTrackComponentProperty()
  131. {
  132. ComponentType = typeof(SpriteComponent),
  133. Property = nameof(SpriteComponent.Offset),
  134. KeyFrames =
  135. {
  136. new AnimationTrackProperty.KeyFrame(startOffset, 0f),
  137. new AnimationTrackProperty.KeyFrame(endOffset, thrustEnd),
  138. new AnimationTrackProperty.KeyFrame(endOffset, length),
  139. }
  140. },
  141. }
  142. };
  143. }
  144. private Animation GetFadeAnimation(SpriteComponent sprite, float start, float end)
  145. {
  146. return new Animation
  147. {
  148. Length = TimeSpan.FromSeconds(end),
  149. AnimationTracks =
  150. {
  151. new AnimationTrackComponentProperty()
  152. {
  153. ComponentType = typeof(SpriteComponent),
  154. Property = nameof(SpriteComponent.Color),
  155. KeyFrames =
  156. {
  157. new AnimationTrackProperty.KeyFrame(sprite.Color, start),
  158. new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(0f), end)
  159. }
  160. }
  161. }
  162. };
  163. }
  164. /// <summary>
  165. /// Get the sprite offset animation to use for mob lunges.
  166. /// </summary>
  167. private Animation GetLungeAnimation(Vector2 direction)
  168. {
  169. const float length = 0.1f;
  170. return new Animation
  171. {
  172. Length = TimeSpan.FromSeconds(length),
  173. AnimationTracks =
  174. {
  175. new AnimationTrackComponentProperty()
  176. {
  177. ComponentType = typeof(SpriteComponent),
  178. Property = nameof(SpriteComponent.Offset),
  179. InterpolationMode = AnimationInterpolationMode.Linear,
  180. KeyFrames =
  181. {
  182. new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, 0f),
  183. new AnimationTrackProperty.KeyFrame(Vector2.Zero, length)
  184. }
  185. }
  186. }
  187. };
  188. }
  189. /// <summary>
  190. /// Updates the effect positions to follow the user
  191. /// </summary>
  192. private void UpdateEffects()
  193. {
  194. var query = EntityQueryEnumerator<TrackUserComponent, TransformComponent>();
  195. while (query.MoveNext(out var uid, out var arcComponent, out var xform))
  196. {
  197. if (arcComponent.User == null)
  198. continue;
  199. Vector2 targetPos = TransformSystem.GetWorldPosition(arcComponent.User.Value);
  200. if (arcComponent.Offset != Vector2.Zero)
  201. {
  202. var entRotation = TransformSystem.GetWorldRotation(xform);
  203. targetPos += entRotation.RotateVec(arcComponent.Offset);
  204. }
  205. TransformSystem.SetWorldPosition(uid, targetPos);
  206. }
  207. }
  208. }