2025-11-13 19:08:07 +08:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
/// 音频空间控制器(精简版)
|
|
|
|
|
|
/// 职责:管理 3D 空间音效和位置跟随
|
|
|
|
|
|
/// 设计:最小化字段,直接操作 AudioSource
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class AudioSpatialController
|
|
|
|
|
|
{
|
2025-11-13 19:58:51 +08:00
|
|
|
|
#region Constants
|
|
|
|
|
|
|
|
|
|
|
|
private const float DEFAULT_MAX_DISTANCE = 150f;
|
|
|
|
|
|
private const float DEFAULT_MIN_DISTANCE = 1f;
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-11-13 19:08:07 +08:00
|
|
|
|
#region Fields
|
|
|
|
|
|
|
2025-11-13 19:58:51 +08:00
|
|
|
|
private readonly Transform _audioTransform;
|
|
|
|
|
|
private readonly AudioSource _audioSource;
|
|
|
|
|
|
private GameObject _followTarget;
|
2025-11-13 19:08:07 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
/// 是否启用 3D 音效(从 AudioSource 读取)
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// </summary>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
public bool Is3DEnabled => _audioSource != null && _audioSource.spatialBlend > 0f;
|
2025-11-13 19:08:07 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 当前跟随的目标
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public GameObject FollowTarget => _followTarget;
|
|
|
|
|
|
|
2025-11-13 19:58:51 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 是否正在跟随对象
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool IsFollowing => _followTarget != null;
|
|
|
|
|
|
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 当前位置
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Vector3 Position
|
|
|
|
|
|
{
|
2025-11-13 19:58:51 +08:00
|
|
|
|
get => _audioTransform?.position ?? Vector3.zero;
|
2025-11-13 19:08:07 +08:00
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_audioTransform != null)
|
|
|
|
|
|
_audioTransform.position = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Constructor
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建空间音频控制器
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public AudioSpatialController(Transform audioTransform, AudioSource audioSource)
|
|
|
|
|
|
{
|
|
|
|
|
|
_audioTransform = audioTransform;
|
|
|
|
|
|
_audioSource = audioSource;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-11-13 19:58:51 +08:00
|
|
|
|
#region Public Methods - 3D Control
|
2025-11-13 19:08:07 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
/// 设置 3D 模式(统一接口)
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// </summary>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
/// <param name="enable">是否启用 3D</param>
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// <param name="maxDistance">最大听音距离</param>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
public void Set3D(bool enable, float maxDistance = DEFAULT_MAX_DISTANCE)
|
2025-11-13 19:08:07 +08:00
|
|
|
|
{
|
2025-11-13 19:58:51 +08:00
|
|
|
|
if (_audioSource == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (enable)
|
|
|
|
|
|
{
|
|
|
|
|
|
_audioSource.spatialBlend = 1f;
|
|
|
|
|
|
_audioSource.dopplerLevel = 0f;
|
|
|
|
|
|
_audioSource.rolloffMode = AudioRolloffMode.Linear;
|
|
|
|
|
|
_audioSource.minDistance = DEFAULT_MIN_DISTANCE;
|
|
|
|
|
|
_audioSource.maxDistance = maxDistance;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_audioSource.spatialBlend = 0f;
|
|
|
|
|
|
}
|
2025-11-13 19:08:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 19:58:51 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 启用 3D 空间音效
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Enable3D(float maxDistance = DEFAULT_MAX_DISTANCE)
|
|
|
|
|
|
=> Set3D(true, maxDistance);
|
|
|
|
|
|
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 禁用 3D 空间音效(改为 2D)
|
|
|
|
|
|
/// </summary>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
public void Disable3D()
|
|
|
|
|
|
=> Set3D(false);
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Public Methods - Position Control
|
2025-11-13 19:08:07 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
/// 设置跟随目标(自动启用/禁用 3D)
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// </summary>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
/// <param name="target">跟随目标,null 则停止跟随并禁用 3D</param>
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// <param name="maxDistance">最大听音距离</param>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
public void SetFollowTarget(GameObject target, float maxDistance = DEFAULT_MAX_DISTANCE)
|
2025-11-13 19:08:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
_followTarget = target;
|
|
|
|
|
|
|
|
|
|
|
|
if (target != null)
|
|
|
|
|
|
{
|
2025-11-13 19:58:51 +08:00
|
|
|
|
// 立即同步位置并启用 3D
|
|
|
|
|
|
Position = target.transform.position;
|
2025-11-13 19:08:07 +08:00
|
|
|
|
Enable3D(maxDistance);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-11-13 19:58:51 +08:00
|
|
|
|
// 停止跟随并禁用 3D
|
2025-11-13 19:08:07 +08:00
|
|
|
|
Disable3D();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
/// 设置静态位置(不跟随,可选择是否 3D)
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="position">世界坐标位置</param>
|
|
|
|
|
|
/// <param name="enable3D">是否启用 3D 音效</param>
|
|
|
|
|
|
/// <param name="maxDistance">最大听音距离</param>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
public void SetStaticPosition(Vector3 position, bool enable3D = true, float maxDistance = DEFAULT_MAX_DISTANCE)
|
2025-11-13 19:08:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
_followTarget = null;
|
2025-11-13 19:58:51 +08:00
|
|
|
|
Position = position;
|
|
|
|
|
|
Set3D(enable3D, maxDistance);
|
2025-11-13 19:08:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新位置跟随(在 Update 循环中调用)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Update()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_followTarget != null && _audioTransform != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_audioTransform.position = _followTarget.transform.position;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 19:58:51 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Public Methods - Advanced
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 高级配置:自定义所有 3D 参数
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="spatialBlend">空间混合度 (0=2D, 1=3D)</param>
|
|
|
|
|
|
/// <param name="minDistance">最小距离(全音量范围)</param>
|
|
|
|
|
|
/// <param name="maxDistance">最大距离(衰减到 0)</param>
|
|
|
|
|
|
/// <param name="rolloffMode">衰减模式</param>
|
|
|
|
|
|
/// <param name="dopplerLevel">多普勒效应强度</param>
|
|
|
|
|
|
public void ConfigureAdvanced(
|
|
|
|
|
|
float spatialBlend,
|
|
|
|
|
|
float minDistance = DEFAULT_MIN_DISTANCE,
|
|
|
|
|
|
float maxDistance = DEFAULT_MAX_DISTANCE,
|
|
|
|
|
|
AudioRolloffMode rolloffMode = AudioRolloffMode.Linear,
|
|
|
|
|
|
float dopplerLevel = 0f)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_audioSource == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
_audioSource.spatialBlend = Mathf.Clamp01(spatialBlend);
|
|
|
|
|
|
_audioSource.minDistance = Mathf.Max(0.01f, minDistance);
|
|
|
|
|
|
_audioSource.maxDistance = Mathf.Max(minDistance, maxDistance);
|
|
|
|
|
|
_audioSource.rolloffMode = rolloffMode;
|
|
|
|
|
|
_audioSource.dopplerLevel = Mathf.Max(0f, dopplerLevel);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// <summary>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
/// 重置到初始状态(2D、不跟随、位置归零)
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Reset()
|
|
|
|
|
|
{
|
|
|
|
|
|
_followTarget = null;
|
|
|
|
|
|
Disable3D();
|
|
|
|
|
|
|
|
|
|
|
|
if (_audioTransform != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_audioTransform.localPosition = Vector3.zero;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Debug
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取调试信息
|
|
|
|
|
|
/// </summary>
|
2025-11-13 19:58:51 +08:00
|
|
|
|
public override string ToString()
|
2025-11-13 19:08:07 +08:00
|
|
|
|
{
|
2025-11-13 19:58:51 +08:00
|
|
|
|
if (_audioSource == null)
|
|
|
|
|
|
return "SpatialController: [Invalid]";
|
2025-11-13 19:08:07 +08:00
|
|
|
|
|
2025-11-13 19:58:51 +08:00
|
|
|
|
return $"SpatialController: " +
|
|
|
|
|
|
$"Mode={(Is3DEnabled ? "3D" : "2D")}, " +
|
|
|
|
|
|
$"Following={(_followTarget?.name ?? "None")}, " +
|
|
|
|
|
|
$"Position={Position:F1}, " +
|
|
|
|
|
|
$"SpatialBlend={_audioSource.spatialBlend:F2}, " +
|
|
|
|
|
|
$"MaxDist={_audioSource.maxDistance:F0}";
|
2025-11-13 19:08:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|