fix: 火山表情修复

This commit is contained in:
2026-07-19 23:43:53 +08:00
parent a6d541383b
commit f444978717
8 changed files with 275 additions and 9 deletions
@@ -88,12 +88,14 @@ namespace AibisDream.FrameAnimation
private double frameElapsedSeconds;
private bool hasStarted;
private bool hasCompleted;
private bool hasCompletedFirstTerminalLoopCycle;
public string PlayableId => plan.PlayableId;
public string CurrentClipId => CurrentStep?.Clip != null ? CurrentStep.Clip.Id : string.Empty;
public string CurrentNodeId => CurrentStep?.NodeId ?? string.Empty;
public int CurrentFrameIndex => hasStarted && !hasCompleted ? frameIndex : -1;
public FrameClip CurrentClip => CurrentStep?.Clip;
internal bool HasCompletedFirstTerminalLoopCycle => hasCompletedFirstTerminalLoopCycle;
internal FrameAnimationPlaybackSnapshot Snapshot =>
new FrameAnimationPlaybackSnapshot(
hasStarted,
@@ -129,6 +131,7 @@ namespace AibisDream.FrameAnimation
{
hasStarted = true;
hasCompleted = false;
hasCompletedFirstTerminalLoopCycle = false;
stepIndex = 0;
frameIndex = 0;
frameElapsedSeconds = 0d;
@@ -186,6 +189,7 @@ namespace AibisDream.FrameAnimation
var cycleRealDuration = GetClipDurationSeconds(step.Clip) / effectiveSpeed;
if (cycleRealDuration > Epsilon && remainingRealSeconds >= cycleRealDuration)
{
hasCompletedFirstTerminalLoopCycle = true;
remainingRealSeconds %= cycleRealDuration;
if (remainingRealSeconds <= Epsilon)
{
@@ -247,6 +251,7 @@ namespace AibisDream.FrameAnimation
if (step.TerminalEndBehavior == FrameClipEndBehavior.Loop)
{
hasCompletedFirstTerminalLoopCycle = true;
frameIndex = 0;
ApplyCurrentFrame(applySprite);
return FrameAnimationSessionEvaluation.Running;
@@ -1,3 +1,4 @@
using System;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
@@ -136,6 +137,20 @@ namespace AibisDream.FrameAnimation
return PlayInternal(playableId, options);
}
/// <summary>
/// 等待当前播放请求完成首轮。非循环请求等待自然结束;终点为 Loop 的请求在
/// 第一次回绕后结束等待,但播放请求本身保持活动并继续循环。
/// </summary>
public CustomYieldInstruction WaitForFirstPass(FrameAnimationPlaybackHandle playbackHandle)
{
if (playbackHandle == null)
{
throw new ArgumentNullException(nameof(playbackHandle));
}
return new FirstPassYieldInstruction(this, playbackHandle);
}
public bool TryBindGraph(
FrameAnimationGraph value,
out FrameAnimationPlaybackError error)
@@ -499,6 +514,33 @@ namespace AibisDream.FrameAnimation
}
}
private bool ShouldWaitForFirstPass(FrameAnimationPlaybackHandle playbackHandle)
{
if (playbackHandle.IsCompleted || activeHandle != playbackHandle || session == null)
{
return false;
}
return !session.HasCompletedFirstTerminalLoopCycle;
}
private sealed class FirstPassYieldInstruction : CustomYieldInstruction
{
private readonly FrameAnimationPlayer player;
private readonly FrameAnimationPlaybackHandle playbackHandle;
public FirstPassYieldInstruction(
FrameAnimationPlayer player,
FrameAnimationPlaybackHandle playbackHandle)
{
this.player = player;
this.playbackHandle = playbackHandle;
}
public override bool keepWaiting =>
player != null && player.ShouldWaitForFirstPass(playbackHandle);
}
private void ApplyEndBehavior(FrameClipEndBehavior endBehavior)
{
switch (endBehavior)