Files
aibis-dream/Assets/Scripts/SceneManagement/ActorKit/FrameAnimationActor.cs
T

188 lines
6.1 KiB
C#
Raw 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.Collections;
using System.Linq;
using AibisDream.FrameAnimation;
using AibisDream.Framework;
using AibisDream.SaveSystem;
using AibisDream.Utility;
using UnityEngine;
using UnityEngine.ResourceManagement.AsyncOperations;
namespace AibisDream
{
/// <summary>
/// 由 FrameAnimationGraph 驱动的 ActorManager 角色实现。
/// Graph 使用 FrameAnimation/{ActorName} 的场景级 Addressable key。
/// </summary>
public sealed class FrameAnimationActor : AbsActor
{
private FrameAnimationPlayer _player;
private string _currentStateName = string.Empty;
private bool _isReady;
public override bool IsReady => _isReady;
protected override void InitInternal()
{
_player = GetComponent<FrameAnimationPlayer>();
base.InitInternal();
_actorType = ActorType.FrameAnimation;
_isReady = false;
}
public override IEnumerator InitializeAsync()
{
if (_player == null)
{
Debug.LogError(
$"[FrameAnimationActor] 角色 '{ActorName}' 缺少 FrameAnimationPlayer。",
this);
yield break;
}
var graphKey = ConstRef.FrameAnimationGraphPrefix + ActorName;
var handle = ResourceSystem.LoadSceneAsync<FrameAnimationGraph>(graphKey);
if (!handle.IsValid())
{
Debug.LogError(
$"[FrameAnimationActor] 角色 '{ActorName}' 无法开始加载 Graphkey='{graphKey}'。",
this);
yield break;
}
yield return handle;
if (handle.Status != AsyncOperationStatus.Succeeded || handle.Result == null)
{
Debug.LogError(
$"[FrameAnimationActor] 角色 '{ActorName}' 的 Graph 加载失败,key='{graphKey}'。",
this);
yield break;
}
var validation = FrameAnimationGraphValidator.Validate(handle.Result);
if (validation.HasErrors)
{
var errors = string.Join(
" | ",
validation.Issues
.Where(issue => issue.Severity == FrameAnimationValidationSeverity.Error)
.Select(issue => $"{issue.Code}: {issue.Message}"));
Debug.LogError(
$"[FrameAnimationActor] 角色 '{ActorName}' 的 Graph 校验失败,key='{graphKey}'{errors}",
this);
yield break;
}
if (!_player.TryBindGraph(handle.Result, out var bindError))
{
Debug.LogError(
$"[FrameAnimationActor] 角色 '{ActorName}' 绑定 Graph 失败,key='{graphKey}', error={bindError}",
this);
yield break;
}
_isReady = true;
}
public override void ChangeState(string stateName)
{
if (!TryPlay(stateName, false, out var handle))
{
return;
}
handle.RegisterCompleted(result => LogFailedResult(stateName, result));
}
public override IEnumerator ChangeStateAsync(string stateName)
{
if (!TryPlay(stateName, false, out var handle))
{
yield break;
}
yield return handle;
LogFailedResult(stateName, handle.Result);
}
public override ActorEntrySnapshotDto CaptureEntry()
{
var entry = new ActorEntrySnapshotDto();
FillBaseEntry(entry);
entry.stateName = _currentStateName;
return entry;
}
public override IEnumerator ApplyEntryAsync(ActorEntrySnapshotDto entry)
{
ApplyAlphaFromEntry(entry);
if (string.IsNullOrWhiteSpace(entry.stateName))
{
yield break;
}
if (!TryPlay(entry.stateName, true, out var handle))
{
yield break;
}
// 非循环终态会同步完成;Loop 会继续播放,读档 Barrier 不等待它。
if (handle.IsCompleted)
{
LogFailedResult(entry.stateName, handle.Result);
}
}
private bool TryPlay(
string stateName,
bool restoreTerminalState,
out FrameAnimationPlaybackHandle handle)
{
handle = null;
if (!_isReady || _player == null)
{
Debug.LogError(
$"[FrameAnimationActor] 角色 '{ActorName}' 尚未完成初始化,playable='{stateName}'。",
this);
return false;
}
if (string.IsNullOrWhiteSpace(stateName))
{
Debug.LogWarning(
$"[FrameAnimationActor] 角色 '{ActorName}' 收到空 playable id。",
this);
return false;
}
handle = restoreTerminalState
? _player.RestoreTerminalState(stateName)
: _player.Play(stateName);
if (handle.IsCompleted &&
handle.Result.Reason == FrameAnimationCompletionReason.Failed)
{
LogFailedResult(stateName, handle.Result);
return false;
}
_currentStateName = stateName;
return true;
}
private void LogFailedResult(
string stateName,
FrameAnimationPlaybackResult result)
{
if (result.Reason != FrameAnimationCompletionReason.Failed)
{
return;
}
var graphKey = ConstRef.FrameAnimationGraphPrefix + ActorName;
Debug.LogError(
$"[FrameAnimationActor] 角色 '{ActorName}' 播放失败,Graph='{graphKey}', " +
$"playable='{stateName}', error={result.Error}",
this);
}
}
}