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 _spriteQuery; /// /// Минимальный скейл, который будет у спрайта при анимации. /// Используется как нижняя граница допустимого скейла, чтобы проиграть хоть сколько-то видимую анимацию. /// private const float MinimumScale = 1.1f; private const string InsertTrack = "insert-animation"; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(HandleEvent); SubscribeLocalEvent(HandleEvent); _spriteQuery = GetEntityQuery(); } private void HandleEvent(Entity ent, ref T args) { TryDoAnimation(ent); } private bool TryDoAnimation(Entity 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 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); } }