2025-10-10 14:08:23 +08:00
|
|
|
|
using System;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
using Managers;
|
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
|
using UnityEngine;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
using Object = UnityEngine.Object;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
|
|
|
|
|
namespace EventWorkClass
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 音频播放事件的配置类。
|
|
|
|
|
|
/// 通过JSON字符串进行初始化。
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class AudioEventConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
[Tooltip("如果存在发起者,是否将音频播放到发起者(initiator)的 AudioSource 上。")]
|
|
|
|
|
|
public bool attachToInitiator = true;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
|
|
|
|
|
[Tooltip("要播放的音频定义名,通过 AudioManager 获取 AudioClip。")]
|
|
|
|
|
|
public string audioClipName;
|
|
|
|
|
|
|
|
|
|
|
|
[Tooltip("播放前的延迟秒数。")] public float delay = 0.0f;
|
|
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
[Tooltip("如果是非循环播放且是临时创建的 AudioSource,是否在播放结束后自动销毁。")]
|
|
|
|
|
|
public bool destroyAfterPlay = true;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
|
|
|
|
|
[Tooltip("是否循环播放。")] public bool loop = false;
|
|
|
|
|
|
|
|
|
|
|
|
[Tooltip("空间混合。0.0 为完全2D,1.0 为完全3D。")] [Range(0f, 1f)]
|
|
|
|
|
|
public float spatialBlend = 0.0f; // 默认为2D音效
|
|
|
|
|
|
|
|
|
|
|
|
[Tooltip("播放音量。0.0 到 1.0。")] [Range(0f, 1f)]
|
|
|
|
|
|
public float volume = 1.0f;
|
|
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 验证配置是否有效。
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool IsValid()
|
|
|
|
|
|
{
|
|
|
|
|
|
return !string.IsNullOrEmpty(audioClipName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 实现一个音频播放事件。
|
|
|
|
|
|
/// 配置通过JSON字符串传入,可指定音频名、音量、循环、空间混合、是否依附于发起者等。
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class Event_PlayAudio : EventWorkClassBase
|
|
|
|
|
|
{
|
|
|
|
|
|
private AudioEventConfig _config;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
private bool _isInitialized;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 初始化音频播放事件,解析JSON配置。
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value">包含音频配置的JSON字符串。</param>
|
|
|
|
|
|
public override void Init(string value)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
_isInitialized = false;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(value))
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("EventPlayAudio 初始化错误:配置 JSON 值为 null 或空。跳过初始化。");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 使用 Newtonsoft.Json 进行反序列化
|
|
|
|
|
|
_config = JsonConvert.DeserializeObject<AudioEventConfig>(value);
|
|
|
|
|
|
if (_config == null || !_config.IsValid())
|
|
|
|
|
|
Debug.LogError("EventPlayAudio 初始化错误:反序列化的配置无效或为空。音频剪辑名称可能缺失。跳过初始化。");
|
|
|
|
|
|
else
|
|
|
|
|
|
_isInitialized = true;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
catch (Exception ex) // 可以更具体地捕获 Newtonsoft.Json.JsonException
|
2025-09-28 15:02:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"EventPlayAudio 初始化错误:使用 Newtonsoft.Json 解析 JSON 配置失败:{ex.Message}\nJSON: {value}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 运行音频播放事件。
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="dimensionID">维度ID(此事件中暂未使用,保留扩展性)。</param>
|
|
|
|
|
|
/// <param name="initiator">事件发起者实体,可能包含一个AudioSource。</param>
|
|
|
|
|
|
public override void Run(string dimensionID, Entity.Entity initiator = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_isInitialized)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("EventPlayAudio 运行错误:事件未初始化或配置无效。跳过音频播放。");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 获取音频片段
|
|
|
|
|
|
var audioClip = AudioManager.Instance.GetAudioClip(_config.audioClipName);
|
|
|
|
|
|
if (!audioClip)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"EventPlayAudio 运行错误:AudioManager 中未找到音频剪辑 '{_config.audioClipName}'。跳过播放。");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AudioSource audioSourceToUse = null;
|
|
|
|
|
|
var isTemporaryAudioSource = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试使用发起者的AudioSource
|
|
|
|
|
|
if (_config.attachToInitiator && initiator != null && initiator.Audio != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
audioSourceToUse = initiator.Audio;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果没有发起者AudioSource或不依附于发起者,则创建临时的GameObject和AudioSource
|
|
|
|
|
|
var tempAudioGO = new GameObject($"TempAudio__{_config.audioClipName}");
|
|
|
|
|
|
audioSourceToUse = tempAudioGO.AddComponent<AudioSource>();
|
|
|
|
|
|
isTemporaryAudioSource = true;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
|
|
|
|
|
if (_config.spatialBlend > 0f)
|
2025-09-28 15:02:57 +08:00
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (initiator != null)
|
2025-09-28 15:02:57 +08:00
|
|
|
|
tempAudioGO.transform.position = initiator.transform.position;
|
|
|
|
|
|
else
|
|
|
|
|
|
tempAudioGO.transform.position = Vector3.zero; // 默认位置
|
|
|
|
|
|
}
|
|
|
|
|
|
// 如果 spatialBlend 为 0,则无需设置位置,它将保持默认的 Vector3.zero。
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 配置AudioSource参数
|
|
|
|
|
|
audioSourceToUse.clip = audioClip;
|
|
|
|
|
|
audioSourceToUse.volume = _config.volume;
|
|
|
|
|
|
audioSourceToUse.loop = _config.loop;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
audioSourceToUse.spatialBlend = _config.spatialBlend;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
audioSourceToUse.playOnAwake = false; // 由Run方法显式控制播放
|
|
|
|
|
|
|
|
|
|
|
|
// 播放音频
|
|
|
|
|
|
if (_config.delay > 0)
|
|
|
|
|
|
audioSourceToUse.PlayDelayed(_config.delay);
|
|
|
|
|
|
else
|
|
|
|
|
|
audioSourceToUse.Play();
|
|
|
|
|
|
|
|
|
|
|
|
// 如果是临时AudioSource且不循环播放,且配置为播放后销毁,则在播放结束后自动销毁
|
|
|
|
|
|
if (isTemporaryAudioSource && !_config.loop && _config.destroyAfterPlay)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 计算销毁时间:延迟 + 音频长度
|
|
|
|
|
|
var destroyTime = _config.delay + audioClip.length;
|
|
|
|
|
|
Object.Destroy(audioSourceToUse.gameObject, destroyTime);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 如果是循环播放的临时AudioSource,不自动销毁,需要外部机制停止/销毁
|
|
|
|
|
|
else if (isTemporaryAudioSource && _config.loop)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
Debug.LogWarning(
|
|
|
|
|
|
$"EventPlayAudio:为 '{_config.audioClipName}' 创建了循环临时 AudioSource。它将不会被自动销毁。需要外部管理来停止和销毁它。");
|
2025-09-28 15:02:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
}
|