using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
using UnityEngine;
namespace Stary.Evo.StoryEditor
{
///
/// 剧本播放器
///
public static class ScriptPlayer
{
///
/// 资源加载工具
///
private static IResource _loader;
///
/// 动画单次时长
///
private const float AnimationTime = 0.2f;
///
/// 刷新帧率
///
private const float UpdateInterval = 0.02f;
///
/// 字幕组件
///
private static SpriteRenderer _caption;
///
/// 音频组件
///
private static AudioSource _audio;
///
/// 当前执行的剧本
///
private static GraphPlayer _graph;
///
/// 初始化剧本播放器
///
/// 资源加载工具
/// 音频组件
/// 字幕组件
public static void Init(IResource loader, AudioSource audio = null, SpriteRenderer caption = null)
{
_loader = loader;
_caption = caption;
_audio = audio;
}
///
/// 释放资源
///
public static void Release()
{
_loader = null;
_caption = null;
_audio = null;
Resources.UnloadUnusedAssets();
}
///
/// 播放剧本
///
/// 包体ID
/// 剧本名称(不用加_txt后缀)
public static async UniTask Play(string packageID, string scriptName)
{
// 资源加载工具排空
if (_loader == null)
{
Debug.LogError("资源加载工具未准备好");
return;
}
// 加载剧本
ResourcePathData path = new(packageID,scriptName);
var json = await _loader.Load(path);
var scriptData = JsonConvert.DeserializeObject(json.text, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });
if (scriptData == null)
{
Debug.LogError($"剧本加载失败:[{path.packageID}]{path.path}");
return;
}
// 解析并执行剧本
_graph = new(scriptData, _loader);
await _graph.Execute();
}
///
/// 播放剧本段落
///
/// 段落数据
/// CT
public static async UniTask PlayScriptPara(ScriptParagraphNodePlayer para, CancellationToken ct)
{
// 设置变量
if (_caption)
_caption.sprite = await _loader.Load(para.CaptionPath);
if (_audio)
_audio.clip = await _loader.Load(para.AudioPath);
// 淡入
await SetCaptionColor(1,ct);
// 等音频播放完
if (_audio)
{
_audio.Play();
await UniTask.Delay(TimeSpan.FromSeconds(_audio.clip.length), cancellationToken:ct);
}
// 淡出
await SetCaptionColor(0, ct);
await UniTask.Delay(TimeSpan.FromSeconds(AnimationTime), cancellationToken:ct);
}
///
/// 停止剧本
///
public static async UniTask Stop()
{
_graph.Stop();
await SetCaptionColor(0, CancellationToken.None);
ReleaseGraph();
}
public static void ReleaseGraph() => _graph = null;
private static async UniTask DoAnim(Action animAction, CancellationToken ct)
{
float time = 0;
while (time < AnimationTime)
{
animAction?.Invoke();
await UniTask.Delay(TimeSpan.FromSeconds(UpdateInterval), cancellationToken: ct);
time+=UpdateInterval;
}
}
private static async UniTask SetCaptionColor(int alpha, CancellationToken ct)
{
var isAdd = alpha > _caption.color.a;
var speed = Mathf.Abs(_caption.color.a - alpha) / AnimationTime * UpdateInterval;
if (speed == 0)
return;
await DoAnim(() =>
{
_caption.color = new(1, 1, 1, _caption.color.a + (isAdd ? speed : -speed));
}, ct);
}
}
}