Files
2026-01-06 15:59:37 +08:00

162 lines
4.9 KiB
C#
Raw Permalink 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;
using System.Threading;
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
using UnityEngine;
namespace Stary.Evo.StoryEditor
{
/// <summary>
/// 剧本播放器
/// </summary>
public static class ScriptPlayer
{
/// <summary>
/// 资源加载工具
/// </summary>
private static IResource _loader;
/// <summary>
/// 动画单次时长
/// </summary>
private const float AnimationTime = 0.2f;
/// <summary>
/// 刷新帧率
/// </summary>
private const float UpdateInterval = 0.02f;
/// <summary>
/// 字幕组件
/// </summary>
private static SpriteRenderer _caption;
/// <summary>
/// 音频组件
/// </summary>
private static AudioSource _audio;
/// <summary>
/// 当前执行的剧本
/// </summary>
private static GraphPlayer _graph;
/// <summary>
/// 初始化剧本播放器
/// </summary>
/// <param name="loader">资源加载工具</param>
/// <param name="audio">音频组件</param>
/// <param name="caption">字幕组件</param>
public static void Init(IResource loader, AudioSource audio = null, SpriteRenderer caption = null)
{
_loader = loader;
_caption = caption;
_audio = audio;
}
/// <summary>
/// 释放资源
/// </summary>
public static void Release()
{
_loader = null;
_caption = null;
_audio = null;
Resources.UnloadUnusedAssets();
}
/// <summary>
/// 播放剧本
/// </summary>
/// <param name="packageID">包体ID</param>
/// <param name="scriptName">剧本名称不用加_txt后缀</param>
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<TextAsset>(path);
var scriptData = JsonConvert.DeserializeObject<GraphData>(json.text, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });
if (scriptData == null)
{
Debug.LogError($"剧本加载失败:[{path.packageID}]{path.path}");
return;
}
// 解析并执行剧本
_graph = new(scriptData, _loader);
await _graph.Execute();
}
/// <summary>
/// 播放剧本段落
/// </summary>
/// <param name="para">段落数据</param>
/// <param name="ct">CT</param>
public static async UniTask PlayScriptPara(ScriptParagraphNodePlayer para, CancellationToken ct)
{
// 设置变量
if (_caption)
_caption.sprite = await _loader.Load<Sprite>(para.CaptionPath);
if (_audio)
_audio.clip = await _loader.Load<AudioClip>(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);
}
/// <summary>
/// 停止剧本
/// </summary>
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);
}
}
}