Melee weapons animations upgrade (#41425)

* upgrading

* Update MeleeWeaponSystem.Effects.cs

* Easing
This commit is contained in:
Red 2026-01-04 00:29:48 +03:00 committed by BarryNorfolk
parent 4677401244
commit 6c8f446f12
4 changed files with 66 additions and 40 deletions

View File

@ -43,6 +43,9 @@ public sealed partial class MeleeWeaponSystem
return; return;
} }
var length = 1f;
var offset = 1f;
var spriteRotation = Angle.Zero; var spriteRotation = Angle.Zero;
if (arcComponent.Animation != WeaponArcAnimation.None if (arcComponent.Animation != WeaponArcAnimation.None
&& TryComp(weapon, out MeleeWeaponComponent? meleeWeaponComponent)) && TryComp(weapon, out MeleeWeaponComponent? meleeWeaponComponent))
@ -55,10 +58,11 @@ public sealed partial class MeleeWeaponSystem
if (meleeWeaponComponent.SwingLeft) if (meleeWeaponComponent.SwingLeft)
angle *= -1; angle *= -1;
if (meleeWeaponComponent.ChangeSwingDirection) meleeWeaponComponent.SwingLeft = !meleeWeaponComponent.SwingLeft; // DeltaV - Nice swing animation for desword
length = (1 / meleeWeaponComponent.AttackRate) * 0.6f;
offset = meleeWeaponComponent.AnimationOffset;
} }
_sprite.SetRotation((animationUid, sprite), localPos.ToWorldAngle()); _sprite.SetRotation((animationUid, sprite), localPos.ToWorldAngle());
var distance = Math.Clamp(localPos.Length() / 2f, 0.2f, 1f);
var xform = _xformQuery.GetComponent(animationUid); var xform = _xformQuery.GetComponent(animationUid);
TrackUserComponent track; TrackUserComponent track;
@ -68,16 +72,16 @@ public sealed partial class MeleeWeaponSystem
case WeaponArcAnimation.Slash: case WeaponArcAnimation.Slash:
track = EnsureComp<TrackUserComponent>(animationUid); track = EnsureComp<TrackUserComponent>(animationUid);
track.User = user; track.User = user;
_animation.Play(animationUid, GetSlashAnimation(sprite, angle, spriteRotation), SlashAnimationKey); _animation.Play(animationUid, GetSlashAnimation((animationUid, sprite), angle, spriteRotation, length, offset), SlashAnimationKey);
if (arcComponent.Fadeout) if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0.065f, 0.065f + 0.05f), FadeAnimationKey); _animation.Play(animationUid, GetFadeAnimation(sprite, length * 0.5f, length + 0.15f), FadeAnimationKey);
break; break;
case WeaponArcAnimation.Thrust: case WeaponArcAnimation.Thrust:
track = EnsureComp<TrackUserComponent>(animationUid); track = EnsureComp<TrackUserComponent>(animationUid);
track.User = user; track.User = user;
_animation.Play(animationUid, GetThrustAnimation((animationUid, sprite), distance, spriteRotation), ThrustAnimationKey); _animation.Play(animationUid, GetThrustAnimation((animationUid, sprite), offset, spriteRotation, length), ThrustAnimationKey);
if (arcComponent.Fadeout) if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0.05f, 0.15f), FadeAnimationKey); _animation.Play(animationUid, GetFadeAnimation(sprite, length * 0.5f, length + 0.15f), FadeAnimationKey);
break; break;
case WeaponArcAnimation.None: case WeaponArcAnimation.None:
var (mapPos, mapRot) = TransformSystem.GetWorldPositionRotation(userXform); var (mapPos, mapRot) = TransformSystem.GetWorldPositionRotation(userXform);
@ -90,21 +94,22 @@ public sealed partial class MeleeWeaponSystem
} }
} }
private Animation GetSlashAnimation(SpriteComponent sprite, Angle arc, Angle spriteRotation) private Animation GetSlashAnimation(Entity<SpriteComponent> sprite, Angle arc, Angle spriteRotation, float length, float offset)
{ {
const float slashStart = 0.03f; var startRotation = sprite.Comp.Rotation + (arc * 0.5f);
const float slashEnd = 0.065f; var endRotation = sprite.Comp.Rotation - (arc * 0.5f);
const float length = slashEnd + 0.05f;
var startRotation = sprite.Rotation + arc / 2; var startRotationOffset = startRotation.RotateVec(new Vector2(0f, -offset * 0.9f));
var endRotation = sprite.Rotation - arc / 2; var minRotationOffset = sprite.Comp.Rotation.RotateVec(new Vector2(0f, -offset * 1.1f));
var startRotationOffset = startRotation.RotateVec(new Vector2(0f, -1f)); var endRotationOffset = endRotation.RotateVec(new Vector2(0f, -offset * 0.9f));
var endRotationOffset = endRotation.RotateVec(new Vector2(0f, -1f));
startRotation += spriteRotation; startRotation += spriteRotation;
endRotation += spriteRotation; endRotation += spriteRotation;
sprite.Comp.NoRotation = true;
return new Animation() return new Animation()
{ {
Length = TimeSpan.FromSeconds(length), Length = TimeSpan.FromSeconds(length + 0.05f),
AnimationTracks = AnimationTracks =
{ {
new AnimationTrackComponentProperty() new AnimationTrackComponentProperty()
@ -113,10 +118,12 @@ public sealed partial class MeleeWeaponSystem
Property = nameof(SpriteComponent.Rotation), Property = nameof(SpriteComponent.Rotation),
KeyFrames = KeyFrames =
{ {
new AnimationTrackProperty.KeyFrame(startRotation, 0f), new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,0.0f), length * 0.0f),
new AnimationTrackProperty.KeyFrame(startRotation, slashStart), new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,0.5f), length * 0.10f),
new AnimationTrackProperty.KeyFrame(endRotation, slashEnd) new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,1.0f), length * 0.15f),
} new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,0.9f), length * 0.20f),
new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,0.80f), length * 0.6f, Easings.OutQuart)
},
}, },
new AnimationTrackComponentProperty() new AnimationTrackComponentProperty()
{ {
@ -124,21 +131,21 @@ public sealed partial class MeleeWeaponSystem
Property = nameof(SpriteComponent.Offset), Property = nameof(SpriteComponent.Offset),
KeyFrames = KeyFrames =
{ {
new AnimationTrackProperty.KeyFrame(startRotationOffset, 0f), new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startRotationOffset,endRotationOffset,0.0f), length * 0.0f),
new AnimationTrackProperty.KeyFrame(startRotationOffset, slashStart), new AnimationTrackProperty.KeyFrame(minRotationOffset, length * 0.10f),
new AnimationTrackProperty.KeyFrame(endRotationOffset, slashEnd) new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startRotationOffset,endRotationOffset,1.0f), length * 0.15f),
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startRotationOffset,endRotationOffset,0.80f), length * 0.6f, Easings.OutQuart)
} }
}, },
} }
}; };
} }
private Animation GetThrustAnimation(Entity<SpriteComponent> sprite, float distance, Angle spriteRotation) private Animation GetThrustAnimation(Entity<SpriteComponent> sprite, float offset, Angle spriteRotation, float length)
{ {
const float thrustEnd = 0.05f; var startOffset = sprite.Comp.Rotation.RotateVec(new Vector2(0f, 0f));
const float length = 0.15f; var endOffset = sprite.Comp.Rotation.RotateVec(new Vector2(0f, -offset * 1.2f));
var startOffset = sprite.Comp.Rotation.RotateVec(new Vector2(0f, -distance / 5f));
var endOffset = sprite.Comp.Rotation.RotateVec(new Vector2(0f, -distance));
_sprite.SetRotation(sprite.AsNullable(), sprite.Comp.Rotation + spriteRotation); _sprite.SetRotation(sprite.AsNullable(), sprite.Comp.Rotation + spriteRotation);
return new Animation() return new Animation()
@ -152,9 +159,11 @@ public sealed partial class MeleeWeaponSystem
Property = nameof(SpriteComponent.Offset), Property = nameof(SpriteComponent.Offset),
KeyFrames = KeyFrames =
{ {
new AnimationTrackProperty.KeyFrame(startOffset, 0f), new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startOffset, endOffset, 0f), length * 0f),
new AnimationTrackProperty.KeyFrame(endOffset, thrustEnd), new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startOffset, endOffset, 0.65f), length * 0.10f),
new AnimationTrackProperty.KeyFrame(endOffset, length), new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startOffset, endOffset, 1f), length * 0.20f),
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startOffset, endOffset, 0.9f), length * 0.30f),
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startOffset, endOffset, 0.7f), length * 0.60f, Easings.OutQuart)
} }
}, },
} }
@ -201,11 +210,12 @@ public sealed partial class MeleeWeaponSystem
InterpolationMode = AnimationInterpolationMode.Linear, InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames = KeyFrames =
{ {
new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, 0f), new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f),
new AnimationTrackProperty.KeyFrame(Vector2.Zero, length) new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, length*0.4f),
} new AnimationTrackProperty.KeyFrame(Vector2.Zero, length*0.6f),
} },
} },
},
}; };
} }

View File

@ -100,7 +100,7 @@ public sealed partial class MeleeWeaponComponent : Component
public Angle Angle = Angle.FromDegrees(60); public Angle Angle = Angle.FromDegrees(60);
[DataField, AutoNetworkedField] [DataField, AutoNetworkedField]
public EntProtoId Animation = "WeaponArcPunch"; public EntProtoId Animation = "WeaponArcThrust";
[DataField, AutoNetworkedField] [DataField, AutoNetworkedField]
public EntProtoId WideAnimation = "WeaponArcSlash"; public EntProtoId WideAnimation = "WeaponArcSlash";
@ -112,15 +112,26 @@ public sealed partial class MeleeWeaponComponent : Component
[DataField, AutoNetworkedField] [DataField, AutoNetworkedField]
public Angle WideAnimationRotation = Angle.Zero; public Angle WideAnimationRotation = Angle.Zero;
/// <summary>
/// Attack animation direction.
/// </summary>
[DataField, AutoNetworkedField] [DataField, AutoNetworkedField]
public bool SwingLeft; public bool SwingLeft;
/// <summary> /// <summary>
/// DeltaV: if true, weapon will swing in different direction each strike. Purely cosmetic. /// Change <see cref="SwingLeft"/> after every attack. Allows each attack to take turns being either left or right.
/// Thats looks cool visually
/// </summary>
[DataField, AutoNetworkedField]
public bool SwingBeverage = true;
/// <summary>
/// How far away from the player the animation should be played.
/// We don't connect it with attack range, because different weapons have different sprites,
/// and this value should be adjusted manually for every weapon ideally
/// </summary> /// </summary>
[DataField] [DataField]
public bool ChangeSwingDirection; public float AnimationOffset = 1f;
// Sounds // Sounds

View File

@ -439,6 +439,12 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
var ev = new AttemptMeleeEvent(); var ev = new AttemptMeleeEvent();
RaiseLocalEvent(weaponUid, ref ev); RaiseLocalEvent(weaponUid, ref ev);
if (weapon.SwingBeverage)
{
weapon.SwingLeft = !weapon.SwingLeft;
DirtyField(weaponUid, weapon, nameof(MeleeWeaponComponent.SwingLeft));
}
if (ev.Cancelled) if (ev.Cancelled)
{ {
if (ev.Message != null) if (ev.Message != null)

View File

@ -344,7 +344,6 @@
- type: MeleeWeapon - type: MeleeWeapon
wideAnimationRotation: -135 wideAnimationRotation: -135
attackRate: 2.0 # DeltaV - was 1.5 attackRate: 2.0 # DeltaV - was 1.5
changeSwingDirection: true # DeltaV
angle: 100 angle: 100
damage: damage:
types: types: