Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix loop behaviour in animate() #1801

Merged
merged 14 commits into from
Sep 3, 2024
57 changes: 42 additions & 15 deletions OpenDreamClient/Rendering/DreamIcon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
private int _animationFrame;
private TimeSpan _animationFrameTime = gameTiming.CurTime;
private List<AppearanceAnimation>? _appearanceAnimations;
private int _appearanceAnimationsLoops;
private Box2? _cachedAABB;
private IRenderTexture? _ping, _pong;
private bool _textureDirty = true;
Expand Down Expand Up @@ -133,7 +134,18 @@
start = _appearanceAnimations[^1].Start + _appearanceAnimations[^1].Duration; //if it's not parallel, it's chained

_appearanceAnimations ??= new List<AppearanceAnimation>();
_appearanceAnimations.Add(new AppearanceAnimation(start, duration, endingAppearance, easing, loops, flags, delay));
if(_appearanceAnimations.Count == 0) {//only valid on the first animation
_appearanceAnimationsLoops = loops;
}

for(int i=_appearanceAnimations.Count-1; i>=0; i--) //there can be only one last-in-sequence, and it might not be the last element of the list because it could be added to mid-loop
if(_appearanceAnimations[i].LastInSequence) {
var lastAnim = _appearanceAnimations[i];
lastAnim.LastInSequence = false;
_appearanceAnimations[i] = lastAnim;
break;
}
amylizzle marked this conversation as resolved.
Show resolved Hide resolved
_appearanceAnimations.Add(new AppearanceAnimation(start, duration, endingAppearance, easing, flags, delay, true));
Fixed Show fixed Hide fixed
}

/// <summary>
Expand Down Expand Up @@ -177,6 +189,7 @@
private void UpdateAnimation() {
if(DMI == null || Appearance == null)
return;

DMIParser.ParsedDMIState? dmiState = DMI.Description.GetStateOrDefault(Appearance.IconState);
if(dmiState == null)
return;
Expand All @@ -201,10 +214,11 @@
return _appearance;
IconAppearance appearance = new IconAppearance(_appearance);
List<AppearanceAnimation>? toRemove = null;
List<AppearanceAnimation>? toReAdd = null;
for(int i = 0; i < _appearanceAnimations.Count; i++) {
AppearanceAnimation animation = _appearanceAnimations[i];
//if it's not the first one, and it's not parallel, break
if((animation.flags & AnimationFlags.AnimationParallel) == 0 && i != 0)
if((animation.Flags & AnimationFlags.AnimationParallel) == 0 && i != 0)
break;

float timeFactor = Math.Clamp((float)(DateTime.Now - animation.Start).Ticks / animation.Duration.Ticks, 0.0f, 1.0f);
Expand Down Expand Up @@ -377,21 +391,34 @@
}

if (timeFactor >= 1f) {
if (animation.loops > 0) {
var tempAnimation = _appearanceAnimations[i];
tempAnimation.loops--;
_appearanceAnimations[i] = tempAnimation;
}
if (animation.loops == 0) {
toRemove ??= new();
toRemove.Add(animation);
toRemove ??= new();
toRemove.Add(animation);
if (_appearanceAnimationsLoops != 0) { //add it back to the list with the times updated
if(_appearanceAnimationsLoops != -1 && animation.LastInSequence)
_appearanceAnimationsLoops -= 1;
toReAdd ??= new();
DateTime start;
if((animation.Flags & AnimationFlags.AnimationParallel) != 0)
start = _appearanceAnimations[^1].Start; //either that's also a parallel, or its one that this should be parallel with
else
start = _appearanceAnimations[^1].Start + _appearanceAnimations[^1].Duration; //if it's not parallel, it's chained
AppearanceAnimation repeatAnimation = new AppearanceAnimation(start, animation.Duration, animation.EndAppearance, animation.Easing, animation.Flags, animation.Delay, animation.LastInSequence);
toReAdd.Add(repeatAnimation);
}

}
}

if(toRemove != null)
foreach (AppearanceAnimation animation in toRemove!) {
foreach (AppearanceAnimation animation in toRemove) {
EndAppearanceAnimation(animation);
}

if(toReAdd != null)
Fixed Show fixed Hide fixed
foreach (AppearanceAnimation animation in toReAdd) {
_appearanceAnimations.Add(animation);
}

return appearance;
}

Expand Down Expand Up @@ -497,13 +524,13 @@
CachedTexture = null;
}

private struct AppearanceAnimation(DateTime start, TimeSpan duration, IconAppearance endAppearance, AnimationEasing easing, int loops, AnimationFlags flags, int delay) {
private struct AppearanceAnimation(DateTime start, TimeSpan duration, IconAppearance endAppearance, AnimationEasing easing, AnimationFlags flags, int delay, bool lastInSequence) {

Check warning

Code scanning / InspectCode

Struct with default equality members is used for comparison: Private accessibility Warning

Struct 'AppearanceAnimation' is checked for equality using the inefficient runtime-provided implementation
public readonly DateTime Start = start;
public readonly TimeSpan Duration = duration;
public readonly IconAppearance EndAppearance = endAppearance;
public readonly AnimationEasing Easing = easing;
public int loops = loops;
public readonly AnimationFlags flags = flags;
public int delay = delay;
public readonly AnimationFlags Flags = flags;
public readonly int Delay = delay;
public bool LastInSequence = lastInSequence;
}
}
Loading