fish-station/Content.Client/_Sunrise/Animations/ContainerInteraction/ContainerInteractionAnimationVisualsSystem.cs
ThereDrD dd9543db36
Улучшение визуала контейнеров (#3599)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-05 00:28:44 +03:00

87 lines
3.4 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Numerics;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Shared.Animations;
using Robust.Shared.Containers;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Client._Sunrise.Animations.ContainerInteraction;
public sealed class ContainerInteractionAnimationVisualsSystem : EntitySystem
{
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private EntityQuery<SpriteComponent> _spriteQuery;
/// <summary>
/// Минимальный скейл, который будет у спрайта при анимации.
/// Используется как нижняя граница допустимого скейла, чтобы проиграть хоть сколько-то видимую анимацию.
/// </summary>
private const float MinimumScale = 1.1f;
private const string InsertTrack = "insert-animation";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ContainerInteractionAnimationVisualsComponent, EntInsertedIntoContainerMessage>(HandleEvent);
SubscribeLocalEvent<ContainerInteractionAnimationVisualsComponent, EntRemovedFromContainerMessage>(HandleEvent);
_spriteQuery = GetEntityQuery<SpriteComponent>();
}
private void HandleEvent<T>(Entity<ContainerInteractionAnimationVisualsComponent> ent, ref T args)
{
TryDoAnimation(ent);
}
private bool TryDoAnimation(Entity<ContainerInteractionAnimationVisualsComponent> ent)
{
if (!_timing.IsFirstTimePredicted || IsClientSide(ent))
return false;
if (!_spriteQuery.TryComp(ent, out var sprite))
return false;
if (_animation.HasRunningAnimation(ent, InsertTrack))
return false;
DoAnimation(ent, sprite);
return true;
}
private void DoAnimation(Entity<ContainerInteractionAnimationVisualsComponent> ent, SpriteComponent sprite)
{
var targetScaleX = ent.Comp.Scale + _random.NextFloat(-ent.Comp.ScaleVariation, ent.Comp.ScaleVariation);
var targetScaleY = ent.Comp.Scale + _random.NextFloat(-ent.Comp.ScaleVariation, ent.Comp.ScaleVariation);
// Чтобы была хоть какая-то видимая анимация, если после рандома значение получилось слишком маленьким.
targetScaleX = MathF.Max(targetScaleX, MinimumScale);
targetScaleY = MathF.Max(targetScaleY, MinimumScale);
var animation = new Animation
{
Length = TimeSpan.FromSeconds(ent.Comp.Duration),
AnimationTracks =
{
new AnimationTrackComponentProperty
{
Property = nameof(SpriteComponent.Scale),
ComponentType = typeof(SpriteComponent),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(new Vector2(targetScaleX, targetScaleY), 0f),
new AnimationTrackProperty.KeyFrame(sprite.Scale, ent.Comp.Duration),
},
},
},
};
_animation.Play(ent, animation, InsertTrack);
}
}