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;
|
using Content.Shared.Pointing.Components;
|
||||||
|
|
||||||
namespace Content.Client.Pointing.Components
|
namespace Content.Client.Pointing.Components;
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class PointingArrowComponent : SharedPointingArrowComponent
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
/// <summary>
|
||||||
public sealed class PointingArrowComponent : SharedPointingArrowComponent {}
|
/// 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.Pointing.Components;
|
||||||
|
using Content.Client.Gravity;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Pointing;
|
using Content.Shared.Pointing;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Client.Animations;
|
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.Animations;
|
|
||||||
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
||||||
|
|
||||||
namespace Content.Client.Pointing;
|
namespace Content.Client.Pointing;
|
||||||
|
|
||||||
public sealed class PointingSystem : SharedPointingSystem
|
public sealed class PointingSystem : SharedPointingSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly AnimationPlayerSystem _player = default!;
|
|
||||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
|
[Dependency] private readonly FloatingVisualizerSystem _floatingSystem = 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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -61,7 +25,7 @@ public sealed class PointingSystem : SharedPointingSystem
|
|||||||
|
|
||||||
private void OnArrowAnimation(EntityUid uid, PointingArrowComponent component, AnimationCompletedEvent args)
|
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)
|
private void AddPointingVerb(GetVerbsEvent<Verb> args)
|
||||||
@@ -98,19 +62,19 @@ public sealed class PointingSystem : SharedPointingSystem
|
|||||||
args.Verbs.Add(verb);
|
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;
|
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)
|
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.DrawDepth = (int) DrawDepth.Overlays;
|
||||||
sprite.NoRotation = false;
|
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
|
bloodMaxVolume: 150
|
||||||
- type: MobPrice
|
- type: MobPrice
|
||||||
price: 150
|
price: 150
|
||||||
|
- type: Appearance
|
||||||
|
- type: FloatingVisuals
|
||||||
|
|
||||||
|
|||||||
@@ -229,6 +229,7 @@
|
|||||||
- type: CreamPiedVisualizer
|
- type: CreamPiedVisualizer
|
||||||
state: creampie_human
|
state: creampie_human
|
||||||
- type: RotationVisuals
|
- type: RotationVisuals
|
||||||
|
- type: FloatingVisuals
|
||||||
- type: FireVisuals
|
- type: FireVisuals
|
||||||
sprite: Mobs/Effects/onfire.rsi
|
sprite: Mobs/Effects/onfire.rsi
|
||||||
normalState: Generic_mob_burning
|
normalState: Generic_mob_burning
|
||||||
|
|||||||
Reference in New Issue
Block a user