Files
ichni_Official/Assets/Scripts/Manager/SongPlayer.cs
SoulliesOfficial 3a63641a2c 谱面改进
2026-04-09 11:03:18 -04:00

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