Makes mobs visually float when weightless (#13391)
This commit is contained in:
61
Content.Client/Gravity/FloatingVisualizerSystem.cs
Normal file
61
Content.Client/Gravity/FloatingVisualizerSystem.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using Content.Shared.Gravity;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Shared.Animations;
|
||||
|
||||
namespace Content.Client.Gravity;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed class FloatingVisualizerSystem : SharedFloatingVisualizerSystem
|
||||
{
|
||||
[Dependency] private readonly AnimationPlayerSystem AnimationSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<FloatingVisualsComponent, AnimationCompletedEvent>(OnAnimationCompleted);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void FloatAnimation(EntityUid uid, Vector2 offset, string animationKey, float animationTime, bool stop = false)
|
||||
{
|
||||
if (stop)
|
||||
{
|
||||
AnimationSystem.Stop(uid, animationKey);
|
||||
return;
|
||||
}
|
||||
|
||||
var animation = new Animation
|
||||
{
|
||||
// We multiply by the number of extra keyframes to make time for them
|
||||
Length = TimeSpan.FromSeconds(animationTime*2),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackComponentProperty
|
||||
{
|
||||
ComponentType = typeof(SpriteComponent),
|
||||
Property = nameof(SpriteComponent.Offset),
|
||||
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f),
|
||||
new AnimationTrackProperty.KeyFrame(offset, animationTime),
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Zero, animationTime),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!AnimationSystem.HasRunningAnimation(uid, animationKey))
|
||||
AnimationSystem.Play(uid, animation, animationKey);
|
||||
}
|
||||
|
||||
private void OnAnimationCompleted(EntityUid uid, FloatingVisualsComponent component, AnimationCompletedEvent args)
|
||||
{
|
||||
if (args.Key != component.AnimationKey)
|
||||
return;
|
||||
|
||||
FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime, !component.CanFloat);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,22 @@
|
||||
using Content.Shared.Pointing.Components;
|
||||
|
||||
namespace Content.Client.Pointing.Components
|
||||
{
|
||||
namespace Content.Client.Pointing.Components;
|
||||
[RegisterComponent]
|
||||
public sealed class PointingArrowComponent : SharedPointingArrowComponent {}
|
||||
public sealed class PointingArrowComponent : SharedPointingArrowComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// How long it takes to go from the bottom of the animation to the top.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("animationTime")]
|
||||
public readonly float AnimationTime = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// How far it goes in any direction.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("offset")]
|
||||
public readonly Vector2 Offset = (0, 0.25f);
|
||||
|
||||
public readonly string AnimationKey = "pointingarrow";
|
||||
}
|
||||
|
||||
@@ -1,53 +1,17 @@
|
||||
using Content.Client.Pointing.Components;
|
||||
using Content.Client.Gravity;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Pointing;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Animations;
|
||||
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
||||
|
||||
namespace Content.Client.Pointing;
|
||||
|
||||
public sealed class PointingSystem : SharedPointingSystem
|
||||
{
|
||||
[Dependency] private readonly AnimationPlayerSystem _player = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
|
||||
private const string AnimationKey = "pointingarrow";
|
||||
|
||||
/// <summary>
|
||||
/// How far it goes in any direction.
|
||||
/// </summary>
|
||||
private const float Offset = 0.25f;
|
||||
|
||||
/// <summary>
|
||||
/// How long it takes to go from the bottom of the animation to the top.
|
||||
/// </summary>
|
||||
private const float UpTime = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Starts at the bottom then goes up and comes back down. Seems to look nicer than starting in the middle.
|
||||
/// </summary>
|
||||
private static readonly Animation PointingAnimation = new Animation()
|
||||
{
|
||||
Length = TimeSpan.FromSeconds(2 * UpTime),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackComponentProperty()
|
||||
{
|
||||
ComponentType = typeof(SpriteComponent),
|
||||
Property = nameof(SpriteComponent.Offset),
|
||||
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f),
|
||||
new AnimationTrackProperty.KeyFrame(new Vector2(0f, Offset), UpTime),
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Zero, UpTime),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
[Dependency] private readonly FloatingVisualizerSystem _floatingSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -61,7 +25,7 @@ public sealed class PointingSystem : SharedPointingSystem
|
||||
|
||||
private void OnArrowAnimation(EntityUid uid, PointingArrowComponent component, AnimationCompletedEvent args)
|
||||
{
|
||||
_player.Play(uid, PointingAnimation, AnimationKey);
|
||||
_floatingSystem.FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime);
|
||||
}
|
||||
|
||||
private void AddPointingVerb(GetVerbsEvent<Verb> args)
|
||||
@@ -98,19 +62,19 @@ public sealed class PointingSystem : SharedPointingSystem
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
private void OnArrowStartup(EntityUid uid, PointingArrowComponent arrow, ComponentStartup args)
|
||||
private void OnArrowStartup(EntityUid uid, PointingArrowComponent component, ComponentStartup args)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(uid, out SpriteComponent? sprite))
|
||||
if (TryComp<SpriteComponent>(uid, out var sprite))
|
||||
{
|
||||
sprite.DrawDepth = (int) DrawDepth.Overlays;
|
||||
}
|
||||
|
||||
_player.Play(uid, PointingAnimation, AnimationKey);
|
||||
_floatingSystem.FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime);
|
||||
}
|
||||
|
||||
private void OnRogueArrowStartup(EntityUid uid, RoguePointingArrowComponent arrow, ComponentStartup args)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(uid, out SpriteComponent? sprite))
|
||||
if (TryComp<SpriteComponent>(uid, out var sprite))
|
||||
{
|
||||
sprite.DrawDepth = (int) DrawDepth.Overlays;
|
||||
sprite.NoRotation = false;
|
||||
|
||||
7
Content.Server/Gravity/FloatingVisualizerSystem.cs
Normal file
7
Content.Server/Gravity/FloatingVisualizerSystem.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using Content.Shared.Gravity;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Server.Gravity;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed class FloatingVisualizerSystem : SharedFloatingVisualizerSystem { }
|
||||
43
Content.Shared/Gravity/FloatingVisualsComponent.cs
Normal file
43
Content.Shared/Gravity/FloatingVisualsComponent.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Gravity;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[Access(typeof(SharedFloatingVisualizerSystem))]
|
||||
public sealed class FloatingVisualsComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// How long it takes to go from the bottom of the animation to the top.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("animationTime")]
|
||||
public float AnimationTime = 2f;
|
||||
|
||||
/// <summary>
|
||||
/// How far it goes in any direction.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("offset")]
|
||||
public Vector2 Offset = new(0, 0.2f);
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool CanFloat = false;
|
||||
public readonly string AnimationKey = "gravity";
|
||||
}
|
||||
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SharedFloatingVisualsComponentState : ComponentState
|
||||
{
|
||||
public float AnimationTime;
|
||||
public Vector2 Offset;
|
||||
public bool HasGravity;
|
||||
|
||||
public SharedFloatingVisualsComponentState(float animationTime, Vector2 offset, bool hasGravity)
|
||||
{
|
||||
AnimationTime = animationTime;
|
||||
Offset = offset;
|
||||
HasGravity = hasGravity;
|
||||
}
|
||||
}
|
||||
78
Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs
Normal file
78
Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Gravity;
|
||||
|
||||
/// <summary>
|
||||
/// Handles offsetting a sprite when there is no gravity
|
||||
/// </summary>
|
||||
public abstract class SharedFloatingVisualizerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedGravitySystem GravitySystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<FloatingVisualsComponent, ComponentStartup>(OnComponentStartup);
|
||||
SubscribeLocalEvent<GravityChangedEvent>(OnGravityChanged);
|
||||
SubscribeLocalEvent<FloatingVisualsComponent, EntParentChangedMessage>(OnEntParentChanged);
|
||||
SubscribeLocalEvent<FloatingVisualsComponent, ComponentGetState>(OnComponentGetState);
|
||||
SubscribeLocalEvent<FloatingVisualsComponent, ComponentHandleState>(OnComponentHandleState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets a sprite with a linear interpolation animation
|
||||
/// </summary>
|
||||
public virtual void FloatAnimation(EntityUid uid, Vector2 offset, string animationKey, float animationTime, bool stop = false) { }
|
||||
|
||||
protected bool CanFloat(EntityUid uid, FloatingVisualsComponent component, TransformComponent? transform = null)
|
||||
{
|
||||
component.CanFloat = GravitySystem.IsWeightless(uid, xform: transform);
|
||||
Dirty(component);
|
||||
return component.CanFloat;
|
||||
}
|
||||
|
||||
private void OnComponentStartup(EntityUid uid, FloatingVisualsComponent component, ComponentStartup args)
|
||||
{
|
||||
if (CanFloat(uid, component))
|
||||
FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime);
|
||||
}
|
||||
|
||||
private void OnGravityChanged(ref GravityChangedEvent args)
|
||||
{
|
||||
foreach (var (floating, transform) in EntityQuery<FloatingVisualsComponent, TransformComponent>(true))
|
||||
{
|
||||
if (transform.GridUid != args.ChangedGridIndex)
|
||||
continue;
|
||||
|
||||
floating.CanFloat = !args.HasGravity;
|
||||
Dirty(floating);
|
||||
|
||||
var uid = floating.Owner;
|
||||
if (!args.HasGravity)
|
||||
FloatAnimation(uid, floating.Offset, floating.AnimationKey, floating.AnimationTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEntParentChanged(EntityUid uid, FloatingVisualsComponent component, ref EntParentChangedMessage args)
|
||||
{
|
||||
var transform = args.Transform;
|
||||
if (CanFloat(uid, component, transform))
|
||||
FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime);
|
||||
}
|
||||
|
||||
private void OnComponentGetState(EntityUid uid, FloatingVisualsComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new SharedFloatingVisualsComponentState(component.AnimationTime, component.Offset, component.CanFloat);
|
||||
}
|
||||
|
||||
private void OnComponentHandleState(EntityUid uid, FloatingVisualsComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not SharedFloatingVisualsComponentState state)
|
||||
return;
|
||||
|
||||
component.AnimationTime = state.AnimationTime;
|
||||
component.Offset = state.Offset;
|
||||
component.CanFloat = state.HasGravity;
|
||||
}
|
||||
}
|
||||
@@ -222,4 +222,6 @@
|
||||
bloodMaxVolume: 150
|
||||
- type: MobPrice
|
||||
price: 150
|
||||
- type: Appearance
|
||||
- type: FloatingVisuals
|
||||
|
||||
|
||||
@@ -229,6 +229,7 @@
|
||||
- type: CreamPiedVisualizer
|
||||
state: creampie_human
|
||||
- type: RotationVisuals
|
||||
- type: FloatingVisuals
|
||||
- type: FireVisuals
|
||||
sprite: Mobs/Effects/onfire.rsi
|
||||
normalState: Generic_mob_burning
|
||||
|
||||
Reference in New Issue
Block a user