2025-06-03 02:42:28 -04:00
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
2026-04-09 11:03:18 -04:00
|
|
|
|
using AK.Wwise;
|
2025-06-03 02:42:28 -04:00
|
|
|
|
using Sirenix.OdinInspector;
|
2026-03-14 03:13:10 -04:00
|
|
|
|
using SLSUtilities.WwiseAssistance;
|
2025-06-03 02:42:28 -04:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using Event = AK.Wwise.Event;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Ichni
|
|
|
|
|
|
{
|
2025-06-06 10:14:55 -04:00
|
|
|
|
public class SongPlayer : SerializedMonoBehaviour
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
2026-03-14 03:13:10 -04:00
|
|
|
|
public bool isLoading = true;
|
2026-04-03 10:53:11 -04:00
|
|
|
|
public bool isStarting = false;
|
2026-03-14 03:13:10 -04:00
|
|
|
|
public bool isDelaying = false;
|
|
|
|
|
|
public bool isPlaying = false; // 是否正在播放音乐
|
|
|
|
|
|
public bool isPausing = false; // 是否正在暂停音乐
|
|
|
|
|
|
public bool isFinished = false;
|
2026-04-03 10:53:11 -04:00
|
|
|
|
public bool isUpdating => isStarting || isDelaying || isPlaying;
|
2026-03-14 03:13:10 -04:00
|
|
|
|
|
2025-06-03 02:42:28 -04:00
|
|
|
|
public Event PlayMusicEvent; // 播放背景音乐的事件
|
|
|
|
|
|
public Event ResumeMusicEvent; // 恢复播放背景音乐的事件
|
|
|
|
|
|
public Event PauseMusicEvent; // 暂停播放背景音乐的事件
|
|
|
|
|
|
public Event StopMusicEvent; // 停止播放背景音乐的事件
|
2026-04-09 11:03:18 -04:00
|
|
|
|
|
|
|
|
|
|
public RTPC HighPassFilter;
|
|
|
|
|
|
public RTPC LowPassFilter;
|
2025-06-03 02:42:28 -04:00
|
|
|
|
|
2025-07-08 14:28:40 -04:00
|
|
|
|
private uint _playingId;
|
2025-06-03 02:42:28 -04:00
|
|
|
|
public float songTimeSegment = 0;
|
|
|
|
|
|
public float pauseTimeSegment;
|
|
|
|
|
|
private float duration;
|
|
|
|
|
|
private float recordedSongSeg;
|
|
|
|
|
|
|
|
|
|
|
|
public float judgeOffset = 0;
|
|
|
|
|
|
|
2026-03-14 03:13:10 -04:00
|
|
|
|
private void Start()
|
|
|
|
|
|
{
|
|
|
|
|
|
InformationTransistor.instance.chapterSwitch.SetValue(gameObject);
|
|
|
|
|
|
InformationTransistor.instance.songSwitch.SetValue(gameObject);
|
|
|
|
|
|
isLoading = true;
|
2026-04-03 10:53:11 -04:00
|
|
|
|
isStarting = false;
|
2026-04-09 11:03:18 -04:00
|
|
|
|
|
2026-03-14 03:13:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-03 02:42:28 -04:00
|
|
|
|
private void Update()
|
|
|
|
|
|
{
|
2026-03-14 03:13:10 -04:00
|
|
|
|
if (isLoading)
|
2025-07-08 14:28:40 -04:00
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-14 03:13:10 -04:00
|
|
|
|
if (isDelaying)
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
|
|
|
|
|
songTimeSegment += Time.deltaTime;
|
2025-08-11 14:04:06 -04:00
|
|
|
|
//songTimeSegment = Mathf.Max(songTimeSegment, 0); // 确保时间段不为负数
|
2025-07-08 14:28:40 -04:00
|
|
|
|
|
|
|
|
|
|
if (songTimeSegment >= 0)
|
|
|
|
|
|
{
|
2026-03-14 03:13:10 -04:00
|
|
|
|
isDelaying = false;
|
2025-08-11 14:04:06 -04:00
|
|
|
|
songTimeSegment = 0; // 延迟结束后,时间段归零
|
2026-03-14 03:13:10 -04:00
|
|
|
|
PlaySong();
|
2025-07-08 14:28:40 -04:00
|
|
|
|
}
|
2025-06-03 02:42:28 -04:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2026-03-14 03:13:10 -04:00
|
|
|
|
if (GameManager.Instance.isDebugging)
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-14 03:13:10 -04:00
|
|
|
|
if (isFinished)
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
|
|
|
|
|
songTimeSegment = recordedSongSeg;
|
2025-07-08 14:28:40 -04:00
|
|
|
|
|
2025-06-03 02:42:28 -04:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-14 03:13:10 -04:00
|
|
|
|
if (isPlaying)
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
2026-04-09 11:03:18 -04:00
|
|
|
|
// 获取底层 Wwise 的当前正确时间
|
2025-08-22 14:54:40 -04:00
|
|
|
|
float currentSongSegment = PlaySegment() / 1000f - (judgeOffset / 1000f);
|
|
|
|
|
|
|
2026-04-09 11:03:18 -04:00
|
|
|
|
// 1. 让游戏时间先基于引擎渲染帧线性平滑推进
|
|
|
|
|
|
songTimeSegment += Time.deltaTime * Time.timeScale;
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 计算当前平滑时间与底层实际音频时间的误差
|
|
|
|
|
|
float difference = currentSongSegment - songTimeSegment;
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 时间校准逻辑
|
|
|
|
|
|
// 如果偏差非常大(例如超过 50ms),说明游戏发生过卡顿停顿,强行同步消除误差
|
|
|
|
|
|
if (Mathf.Abs(difference) > 0.05f)
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
2025-08-22 14:54:40 -04:00
|
|
|
|
songTimeSegment = currentSongSegment;
|
2026-04-09 11:03:18 -04:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果在正常范围内,使用微调去柔和追击这个误差,避免肉眼看到跳变(Jitter)
|
|
|
|
|
|
songTimeSegment += difference * 0.1f;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保证时间不要神奇地倒退影响铺面逻辑
|
|
|
|
|
|
if (songTimeSegment > recordedSongSeg)
|
|
|
|
|
|
{
|
|
|
|
|
|
recordedSongSeg = songTimeSegment;
|
2025-06-03 02:42:28 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-14 03:13:10 -04:00
|
|
|
|
else if (isPausing)
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
2025-08-11 14:04:06 -04:00
|
|
|
|
songTimeSegment = pauseTimeSegment;
|
2025-06-03 02:42:28 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[Button]
|
2025-06-06 10:14:55 -04:00
|
|
|
|
public void PlaySong()
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
|
|
|
|
|
_playingId = PlayMusicEvent.Post(gameObject,
|
2025-08-11 14:04:06 -04:00
|
|
|
|
(uint)AkCallbackType.AK_EnableGetMusicPlayPosition |
|
|
|
|
|
|
(uint)AkCallbackType.AK_MusicSyncEntry |
|
|
|
|
|
|
(uint)AkCallbackType.AK_MusicSyncExit,
|
2025-06-03 02:42:28 -04:00
|
|
|
|
OnMusicEvent, null);
|
|
|
|
|
|
|
2026-03-14 03:13:10 -04:00
|
|
|
|
isPlaying = true;
|
|
|
|
|
|
isPausing = false;
|
|
|
|
|
|
isFinished = false;
|
2025-06-03 02:42:28 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Button]
|
2025-06-06 10:14:55 -04:00
|
|
|
|
public void PauseSong()
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
2025-08-22 14:54:40 -04:00
|
|
|
|
pauseTimeSegment = songTimeSegment;
|
2026-03-14 03:13:10 -04:00
|
|
|
|
isPlaying = false;
|
|
|
|
|
|
isPausing = true;
|
2025-06-03 02:42:28 -04:00
|
|
|
|
PauseMusicEvent.Post(gameObject);
|
|
|
|
|
|
Time.timeScale = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Button]
|
2025-06-06 10:14:55 -04:00
|
|
|
|
public void ResumeSong()
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
|
|
|
|
|
Time.timeScale = 1;
|
2026-03-14 03:13:10 -04:00
|
|
|
|
isPlaying = true;
|
|
|
|
|
|
isPausing = false;
|
2025-06-03 02:42:28 -04:00
|
|
|
|
ResumeMusicEvent.Post(gameObject);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Button]
|
2025-06-06 10:14:55 -04:00
|
|
|
|
public void StopSong()
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
2026-03-14 03:13:10 -04:00
|
|
|
|
isPlaying = false;
|
|
|
|
|
|
isPausing = false;
|
2025-06-03 02:42:28 -04:00
|
|
|
|
StopMusicEvent.Post(gameObject);
|
|
|
|
|
|
}
|
2025-08-11 14:04:06 -04:00
|
|
|
|
|
2025-06-03 02:42:28 -04:00
|
|
|
|
private void OnMusicEvent(object in_cookie, AkCallbackType in_type, AkCallbackInfo in_info)
|
|
|
|
|
|
{
|
2025-08-11 14:04:06 -04:00
|
|
|
|
Debug.Log(in_type + " " + in_info);
|
|
|
|
|
|
|
|
|
|
|
|
if (in_type == AkCallbackType.AK_MusicSyncEntry)
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
2025-08-11 14:04:06 -04:00
|
|
|
|
if (in_info is AkMusicSyncCallbackInfo musicInfo)
|
2025-06-03 02:42:28 -04:00
|
|
|
|
{
|
2026-03-14 03:13:10 -04:00
|
|
|
|
GameManager.Instance.songInformation.songLength = musicInfo.segmentInfo_iActiveDuration / 1000f;
|
2025-08-11 14:04:06 -04:00
|
|
|
|
InformationTransistor.instance.songLength = musicInfo.segmentInfo_iActiveDuration / 1000f;
|
2026-03-14 03:13:10 -04:00
|
|
|
|
InformationTransistor.instance.bpm = GameManager.Instance.songInformation.bpm;
|
2025-06-03 02:42:28 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-11 14:04:06 -04:00
|
|
|
|
|
|
|
|
|
|
if (in_type == AkCallbackType.AK_MusicSyncExit)
|
|
|
|
|
|
{
|
2026-03-14 03:13:10 -04:00
|
|
|
|
isFinished = true;
|
|
|
|
|
|
GameManager.Instance.summaryPageCanvas.SetUpSummary();
|
|
|
|
|
|
GameManager.Instance.summaryPageCanvas.FadeIn();
|
2025-08-11 14:04:06 -04:00
|
|
|
|
}
|
2025-06-03 02:42:28 -04:00
|
|
|
|
}
|
2025-08-11 14:04:06 -04:00
|
|
|
|
|
2025-06-03 02:42:28 -04:00
|
|
|
|
int PlaySegment()
|
|
|
|
|
|
{
|
|
|
|
|
|
AkSegmentInfo segmentInfo = new AkSegmentInfo();
|
2026-04-09 11:03:18 -04:00
|
|
|
|
AkUnitySoundEngine.GetPlayingSegmentInfo(_playingId, segmentInfo,true);
|
2025-06-03 02:42:28 -04:00
|
|
|
|
|
|
|
|
|
|
return segmentInfo.iCurrentPosition;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|