815 lines
32 KiB
C#
815 lines
32 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.SceneManagement;
|
|
using System.Collections;
|
|
|
|
public class selected_songInfo : MonoBehaviour
|
|
{
|
|
public Image t_songCoverImage;
|
|
public Image btm_songCoverImage;
|
|
[Header("极简信息")]
|
|
public Text songNameText;
|
|
public Text currentDifficulty;
|
|
public Text sumScore_thisDifficulty;
|
|
public Text total_gameTime;
|
|
private int maxDifficulty = 22;
|
|
|
|
public Image c_DifficultyImage;
|
|
public Image c_imageMask;
|
|
[Header("分级颜色")]
|
|
public Color _0to5d5;
|
|
public Color _5d5to11;
|
|
public Color _11to16d5;
|
|
public Color _16d5to22;
|
|
public Color _equal22;
|
|
|
|
[Header("对应的难度按钮")]
|
|
public List<Button> difficultyButtons = new List<Button>();
|
|
[Header("对应的难度文本")]
|
|
public List<Text> difficultyTexts = new List<Text>();
|
|
[Header("enter detail page")]
|
|
public Button enterDetailPageButton;
|
|
[Header("quick enter game play")]
|
|
public Button quickEnter_gamePlay;
|
|
[Header("指定image背景色")]
|
|
public Sprite buttons_bgImage;
|
|
[Header("black mask")]
|
|
public Image blackMaskImage;
|
|
|
|
// store the original sprites so we don't overwrite the designer's setup
|
|
private List<Sprite> originalButtonSprites = new List<Sprite>();
|
|
|
|
void Awake()
|
|
{
|
|
Debug.LogWarning("selected_songInfo.Awake called");
|
|
}
|
|
|
|
void OnEnable()
|
|
{
|
|
Debug.LogWarning("selected_songInfo.OnEnable called");
|
|
// register listeners here to ensure binding even if Start wasn't called yet
|
|
if (enterDetailPageButton != null)
|
|
{
|
|
enterDetailPageButton.onClick.RemoveListener(OnEnterDetailPageClicked);
|
|
enterDetailPageButton.onClick.AddListener(OnEnterDetailPageClicked);
|
|
Debug.LogWarning("enterDetailPageButton listener added");
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("enterDetailPageButton is null in OnEnable");
|
|
}
|
|
|
|
if (quickEnter_gamePlay != null)
|
|
{
|
|
quickEnter_gamePlay.onClick.RemoveListener(OnQuickEnterClicked);
|
|
quickEnter_gamePlay.onClick.AddListener(OnQuickEnterClicked);
|
|
Debug.LogWarning("quickEnter_gamePlay listener added");
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("quickEnter_gamePlay is null in OnEnable");
|
|
}
|
|
}
|
|
|
|
void OnDisable()
|
|
{
|
|
Debug.LogWarning("selected_songInfo.OnDisable called");
|
|
if (enterDetailPageButton != null)
|
|
{
|
|
enterDetailPageButton.onClick.RemoveListener(OnEnterDetailPageClicked);
|
|
}
|
|
if (quickEnter_gamePlay != null)
|
|
{
|
|
quickEnter_gamePlay.onClick.RemoveListener(OnQuickEnterClicked);
|
|
}
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
Debug.LogWarning("selected_songInfo.OnDestroy called");
|
|
// ensure we remove sceneLoaded subscription if still present
|
|
SceneManager.sceneLoaded -= OnSceneLoadedAfterQuickEnter;
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
Debug.LogWarning("selected_songInfo.Start called");
|
|
|
|
// ensure black mask is transparent and inactive at start
|
|
if (blackMaskImage != null)
|
|
{
|
|
var c = blackMaskImage.color;
|
|
c.a = 0f;
|
|
blackMaskImage.color = c;
|
|
blackMaskImage.gameObject.SetActive(false);
|
|
}
|
|
|
|
// capture original sprites for difficulty buttons before we make any changes
|
|
originalButtonSprites.Clear();
|
|
if (difficultyButtons != null)
|
|
{
|
|
foreach (var btn in difficultyButtons)
|
|
{
|
|
if (btn == null)
|
|
{
|
|
originalButtonSprites.Add(null);
|
|
continue;
|
|
}
|
|
var img = btn.GetComponent<Image>();
|
|
originalButtonSprites.Add(img != null ? img.sprite : null);
|
|
}
|
|
}
|
|
|
|
// attach click listeners to difficulty buttons (map list index 0..n-1 -> difficulty 0..n-1)
|
|
if (difficultyButtons != null)
|
|
{
|
|
for (int i = 0; i < difficultyButtons.Count; i++)
|
|
{
|
|
var btn = difficultyButtons[i];
|
|
if (btn == null) continue;
|
|
int idx = i; // capture
|
|
btn.onClick.RemoveAllListeners();
|
|
btn.onClick.AddListener(() => OnDifficultyButtonClicked(idx));
|
|
}
|
|
}
|
|
|
|
UpdateSelectedSongDisplay();
|
|
|
|
// Diagnostic: confirm Start ran and key refs
|
|
Debug.LogWarning($"selected_songInfo.Start: quickEnter_gamePlay is {(quickEnter_gamePlay == null ? "NULL" : "ASSIGNED")}, enterDetail assigned={(enterDetailPageButton == null ? "NULL" : "ASSIGNED")}, blackMask assigned={(blackMaskImage == null ? "NULL" : "ASSIGNED")}");
|
|
Debug.LogWarning($"selected_songInfo.Start: SongDataHolder.SelectedSongData is {(SongDataHolder.SelectedSongData == null ? "NULL" : SongDataHolder.SelectedSongData.songName)}");
|
|
}
|
|
|
|
public void UpdateSelectedSongDisplay()
|
|
{
|
|
if (SongDataHolder.SelectedSongData != null)
|
|
{
|
|
var song = SongDataHolder.SelectedSongData;
|
|
if (t_songCoverImage != null && song.right_pic_top_image != null)
|
|
{
|
|
t_songCoverImage.sprite = song.right_pic_top_image;
|
|
t_songCoverImage.enabled = true;
|
|
}
|
|
else
|
|
{
|
|
t_songCoverImage.enabled = false;
|
|
}
|
|
if (btm_songCoverImage != null && song.right_pic_bottom_image != null)
|
|
{
|
|
btm_songCoverImage.sprite = song.right_pic_bottom_image;
|
|
btm_songCoverImage.enabled = true;
|
|
}
|
|
else
|
|
{
|
|
btm_songCoverImage.enabled = false;
|
|
}
|
|
if (songNameText != null)
|
|
{
|
|
songNameText.text = song.songName;
|
|
}
|
|
|
|
// set difficulty button backgrounds according to currently selected difficulty in the song SO
|
|
SetDifficultyButtonBackground(song.thisLevel_selectedDifficultyID);
|
|
|
|
// Update currentDifficulty text and colored difficulty bar
|
|
float difficultyLevel = GetDifficultyLevel(song, song.thisLevel_selectedDifficultyID);
|
|
if (currentDifficulty != null)
|
|
{
|
|
currentDifficulty.text = difficultyLevel.ToString("0.0");
|
|
}
|
|
|
|
if (c_DifficultyImage != null)
|
|
{
|
|
// fill amount is ratio of difficultyLevel / maxDifficulty
|
|
float fill = Mathf.Clamp01(difficultyLevel / (float)maxDifficulty);
|
|
c_DifficultyImage.fillAmount = fill;
|
|
|
|
// choose color by ranges: left-closed, right-open, intervals of 5.5
|
|
// [0,5.5), [5.5,11), [11,16.5), [16.5,22), exactly 22 -> equal color
|
|
Color chosen = _0to5d5;
|
|
if (Mathf.Approximately(difficultyLevel, maxDifficulty))
|
|
{
|
|
chosen = _equal22;
|
|
}
|
|
else if (difficultyLevel >= 16.5f)
|
|
{
|
|
chosen = _16d5to22;
|
|
}
|
|
else if (difficultyLevel >= 11f)
|
|
{
|
|
chosen = _11to16d5;
|
|
}
|
|
else if (difficultyLevel >= 5.5f)
|
|
{
|
|
chosen = _5d5to11;
|
|
}
|
|
else if (difficultyLevel >= 0)
|
|
{
|
|
chosen = _0to5d5;
|
|
}
|
|
else
|
|
{
|
|
chosen = Color.white;
|
|
}
|
|
|
|
// ensure color is opaque
|
|
chosen.a = 1f;
|
|
|
|
// apply color to the mask image if available, otherwise fall back to the difficulty image
|
|
if (c_imageMask != null)
|
|
{
|
|
c_imageMask.color = chosen;
|
|
}
|
|
else
|
|
{
|
|
c_DifficultyImage.color = chosen;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Clear display if no song selected
|
|
if (t_songCoverImage != null)
|
|
{
|
|
t_songCoverImage.sprite = null;
|
|
t_songCoverImage.enabled = false;
|
|
}
|
|
if (btm_songCoverImage != null)
|
|
{
|
|
btm_songCoverImage.sprite = null;
|
|
btm_songCoverImage.enabled = false;
|
|
}
|
|
if (songNameText != null)
|
|
{
|
|
songNameText.text = "未选择歌曲";
|
|
}
|
|
|
|
// restore original difficulty button backgrounds and text colors
|
|
SetDifficultyButtonBackground(-1);
|
|
}
|
|
}
|
|
|
|
private void EnsureOriginalSpritesCount()
|
|
{
|
|
if (difficultyButtons == null) return;
|
|
while (originalButtonSprites.Count < difficultyButtons.Count)
|
|
{
|
|
var btn = difficultyButtons[originalButtonSprites.Count];
|
|
if (btn == null) originalButtonSprites.Add(null);
|
|
else
|
|
{
|
|
var img = btn.GetComponent<Image>();
|
|
originalButtonSprites.Add(img != null ? img.sprite : null);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SetDifficultyButtonBackground(int selectedDifficulty)
|
|
{
|
|
if (difficultyButtons == null || difficultyButtons.Count == 0) return;
|
|
|
|
EnsureOriginalSpritesCount();
|
|
|
|
for (int i = 0; i < difficultyButtons.Count; i++)
|
|
{
|
|
var btn = difficultyButtons[i];
|
|
if (btn == null) continue;
|
|
var img = btn.GetComponent<Image>();
|
|
if (img == null) continue;
|
|
|
|
if (i == selectedDifficulty)
|
|
{
|
|
// apply highlight sprite to selected button
|
|
if (buttons_bgImage != null)
|
|
{
|
|
img.sprite = buttons_bgImage;
|
|
img.color = Color.white;
|
|
}
|
|
// set corresponding text (if exists) to white
|
|
if (difficultyTexts != null && i < difficultyTexts.Count && difficultyTexts[i] != null)
|
|
{
|
|
difficultyTexts[i].color = Color.white;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// restore original sprite if we recorded one; otherwise leave as-is
|
|
if (i < originalButtonSprites.Count)
|
|
{
|
|
img.sprite = originalButtonSprites[i];
|
|
}
|
|
// set corresponding text (if exists) to black
|
|
if (difficultyTexts != null && i < difficultyTexts.Count && difficultyTexts[i] != null)
|
|
{
|
|
difficultyTexts[i].color = Color.black;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnDifficultyButtonClicked(int index)
|
|
{
|
|
// map button index 0..3 to song SO difficulty 0..3
|
|
if (SongDataHolder.SelectedSongData != null)
|
|
{
|
|
SongDataHolder.SelectedSongData.thisLevel_selectedDifficultyID = Mathf.Clamp(index, 0, 3);
|
|
// immediately update UI to reflect new selection
|
|
SetDifficultyButtonBackground(SongDataHolder.SelectedSongData.thisLevel_selectedDifficultyID);
|
|
|
|
// refresh displayed song info so currentDifficulty / difficulty bar update to new difficulty
|
|
UpdateSelectedSongDisplay();
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("No song selected - difficulty button click ignored.");
|
|
}
|
|
}
|
|
|
|
private void OnEnterDetailPageClicked()
|
|
{
|
|
if (SongDataHolder.SelectedSongData != null)
|
|
{
|
|
SceneManager.LoadScene("Songs_Select");
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("No song selected, cannot enter detail page.");
|
|
}
|
|
}
|
|
|
|
private void OnQuickEnterClicked()
|
|
{
|
|
// use SongData from holder or SongButton; ensure selection exists
|
|
SongData sd = FindSongDataFromSelectedButton();
|
|
if (sd == null) sd = SongDataHolder.SelectedSongData;
|
|
if (sd == null)
|
|
{
|
|
Debug.LogWarning("No song selected - cannot quick enter gameplay.");
|
|
return;
|
|
}
|
|
|
|
// Validate that the selected difficulty has a chart file before proceeding
|
|
var chart = sd.GetChartFile(sd.thisLevel_selectedDifficultyID);
|
|
if (chart == null)
|
|
{
|
|
Debug.LogError($"QuickEnter aborted: Song '{sd.songName}' has no chart file for difficulty {sd.thisLevel_selectedDifficultyID}.");
|
|
return;
|
|
}
|
|
|
|
Debug.LogWarning($"QuickEnter clicked, selected song: {sd.songName} id={sd.songID} difficulty={sd.thisLevel_selectedDifficultyID}");
|
|
|
|
// pass selection to BeatmapManager pending fields so newly loaded scene picks it up
|
|
BeatmapManager.SetPendingSong(sd, sd.thisLevel_selectedDifficultyID);
|
|
|
|
// keep selected in holder to make it accessible in new scene
|
|
SongDataHolder.SelectedSongData = sd;
|
|
|
|
// mark this object to persist across scene load so callbacks/coroutines are valid
|
|
DontDestroyOnLoad(this.gameObject);
|
|
// start fade and load sequence
|
|
StartCoroutine(QuickEnterSequence());
|
|
}
|
|
|
|
private IEnumerator QuickEnterSequence()
|
|
{
|
|
Debug.LogWarning("QuickEnterSequence started: beginning fade");
|
|
// Fade black mask in over 0.25 seconds
|
|
float duration = 0.25f;
|
|
if (blackMaskImage != null)
|
|
{
|
|
// if mask is inactive, ensure its alpha is zero before activating
|
|
if (!blackMaskImage.gameObject.activeSelf)
|
|
{
|
|
Color cc = blackMaskImage.color;
|
|
cc.a = 0f;
|
|
blackMaskImage.color = cc;
|
|
blackMaskImage.gameObject.SetActive(true);
|
|
}
|
|
else
|
|
{
|
|
// active: explicitly set alpha to 0 to start fade from transparent
|
|
Color cc = blackMaskImage.color;
|
|
cc.a = 0f;
|
|
blackMaskImage.color = cc;
|
|
}
|
|
|
|
float t = 0f;
|
|
Color c = blackMaskImage.color;
|
|
while (t < duration)
|
|
{
|
|
t += Time.deltaTime;
|
|
float alpha = Mathf.Clamp01(t / duration);
|
|
c.a = alpha;
|
|
blackMaskImage.color = c;
|
|
yield return null;
|
|
}
|
|
c.a = 1f;
|
|
blackMaskImage.color = c;
|
|
}
|
|
|
|
Debug.LogWarning("Fade complete, loading gameplay scene...");
|
|
// after black screen, load gameplay scene asynchronously and wait for completion
|
|
SceneManager.sceneLoaded += OnSceneLoadedAfterQuickEnter;
|
|
var asyncOp = SceneManager.LoadSceneAsync("gamePlay_gamePlay");
|
|
if (asyncOp != null)
|
|
{
|
|
// wait until load completes
|
|
while (!asyncOp.isDone)
|
|
{
|
|
yield return null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// fallback to synchronous load
|
|
SceneManager.LoadScene("gamePlay_gamePlay");
|
|
}
|
|
|
|
yield break;
|
|
}
|
|
|
|
private SongData FindSongDataFromSelectedButton()
|
|
{
|
|
var allButtons = FindObjectsOfType<SongButton>();
|
|
Debug.LogWarning($"FindSongDataFromSelectedButton: found {allButtons.Length} SongButton instances");
|
|
foreach (var sb in allButtons)
|
|
{
|
|
if (sb == null) continue;
|
|
try
|
|
{
|
|
// log selection marker info for each button to help debugging
|
|
var field = sb.GetType().GetField("selected_boarder", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
|
|
Image img = null;
|
|
if (field != null) img = field.GetValue(sb) as Image;
|
|
float alpha = img != null ? img.color.a : -1f;
|
|
Debug.LogWarning($"SongButton id field value for '{sb.name}': selected_boarder alpha={alpha}");
|
|
|
|
if (img != null && img.color.a > 0.5f)
|
|
{
|
|
// prefer thisSong_so if present
|
|
var soField = sb.GetType().GetField("thisSong_so", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
|
|
if (soField != null)
|
|
{
|
|
var soObj = soField.GetValue(sb);
|
|
if (soObj != null && soObj is SongData)
|
|
{
|
|
Debug.LogWarning($"Selected SongButton has thisSong_so assigned: {((SongData)soObj).songName}");
|
|
return soObj as SongData;
|
|
}
|
|
}
|
|
|
|
// fallback: use song id on SongButton
|
|
var idField = sb.GetType().GetField("song_songSerialID", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
|
|
if (idField != null)
|
|
{
|
|
int id = (int)idField.GetValue(sb);
|
|
Debug.LogWarning($"Selected SongButton id = {id}");
|
|
var sd = SongDataLibrary.Instance != null ? SongDataLibrary.Instance.GetSongDataByID(id) : null;
|
|
if (sd != null)
|
|
{
|
|
Debug.LogWarning($"Found SongData by id: {sd.songName}");
|
|
return sd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Debug.LogWarning("Exception while inspecting SongButton: " + ex.Message);
|
|
}
|
|
}
|
|
Debug.LogWarning("FindSongDataFromSelectedButton: no selected SongButton found");
|
|
return null;
|
|
}
|
|
|
|
private void OnSceneLoadedAfterQuickEnter(Scene scene, LoadSceneMode mode)
|
|
{
|
|
// If this object has been destroyed, unsubscribe and bail out safely
|
|
if (!this)
|
|
{
|
|
SceneManager.sceneLoaded -= OnSceneLoadedAfterQuickEnter;
|
|
return;
|
|
}
|
|
|
|
// only handle target gameplay scene
|
|
if (scene.name != "gamePlay_gamePlay")
|
|
{
|
|
// unsubscribe anyway
|
|
SceneManager.sceneLoaded -= OnSceneLoadedAfterQuickEnter;
|
|
return;
|
|
}
|
|
|
|
// If the black mask reference exists but the GameObject is disabled, ensure its alpha is 0
|
|
if (blackMaskImage != null && !blackMaskImage.gameObject.activeSelf)
|
|
{
|
|
var cc = blackMaskImage.color;
|
|
cc.a = 0f;
|
|
blackMaskImage.color = cc;
|
|
}
|
|
|
|
// perform setup: load chart JSON from selected SongData's selected difficulty and set audio
|
|
SongData selected = null;
|
|
|
|
// Prefer SongButton's assigned SO if available
|
|
selected = FindSongDataFromSelectedButton();
|
|
|
|
// Fallback to SongDataHolder
|
|
if (selected == null) selected = SongDataHolder.SelectedSongData;
|
|
|
|
if (selected == null)
|
|
{
|
|
Debug.LogWarning("OnSceneLoadedAfterQuickEnter: SelectedSongData is null");
|
|
SceneManager.sceneLoaded -= OnSceneLoadedAfterQuickEnter;
|
|
// allow this object to be destroyed now
|
|
Destroy(this.gameObject);
|
|
return;
|
|
}
|
|
|
|
// find managers in the new scene
|
|
var beatmapManager = FindObjectOfType<BeatmapManager>();
|
|
var gameManager = FindObjectOfType<GameManager>();
|
|
|
|
Debug.LogWarning($"selected song: {selected.songName} (id {selected.songID}), difficulty {selected.thisLevel_selectedDifficultyID}");
|
|
|
|
// get chart TextAsset from SongData for current selected difficulty
|
|
TextAsset chartAsset = selected.GetChartFile(selected.thisLevel_selectedDifficultyID);
|
|
if (chartAsset == null)
|
|
{
|
|
Debug.LogWarning($"Chart file for difficulty {selected.thisLevel_selectedDifficultyID} not found on SongData {selected.songName}");
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"Chart asset found, size={chartAsset.text?.Length ?? 0} chars");
|
|
}
|
|
|
|
// parse beatmap only and assign music, but DO NOT start spawning until player starts
|
|
if (beatmapManager != null && chartAsset != null)
|
|
{
|
|
Debug.LogWarning("Parsing chart JSON via BeatmapManager.ParseJsonOnly");
|
|
bool parsed = false;
|
|
try
|
|
{
|
|
parsed = beatmapManager.ParseJsonOnly(chartAsset.text);
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Debug.LogWarning("Exception during ParseJsonOnly: " + ex.Message + "\n" + ex.StackTrace);
|
|
}
|
|
Debug.LogWarning($"ParseJsonOnly returned {parsed}");
|
|
if (!parsed)
|
|
{
|
|
Debug.LogWarning("Failed to parse chart JSON from SongData chart file.");
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"Beatmap parsed: beatmap is {(beatmapManager.beatmap != null ? "NOT null" : "null")}, parsedMusicFile={beatmapManager.parsedMusicFile}, globalDelaySeconds={beatmapManager.globalDelaySeconds}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (beatmapManager == null) Debug.LogWarning("BeatmapManager not found in gameplay scene");
|
|
}
|
|
|
|
// assign audio clip to GameManager.musicSource if available
|
|
if (gameManager != null)
|
|
{
|
|
if (selected.audioFile != null && gameManager.musicSource != null)
|
|
{
|
|
gameManager.musicSource.clip = selected.audioFile;
|
|
gameManager.musicSource.loop = false;
|
|
// make sure AudioSource won't auto-play due to inspector settings
|
|
gameManager.musicSource.playOnAwake = false;
|
|
// warm up audio by playing muted so decoding happens before unpause
|
|
try
|
|
{
|
|
gameManager.musicSource.mute = true;
|
|
gameManager.musicSource.Play();
|
|
Debug.LogWarning("Warmed audio playback (muted) after assigning SongData.audioFile");
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Debug.LogWarning("Failed to Play() for warmup: " + ex.Message);
|
|
}
|
|
|
|
Debug.LogWarning("Assigned SongData.audioFile to GameManager.musicSource.clip (playOnAwake disabled)");
|
|
|
|
// Request PauseManager-driven pause (centralized)
|
|
RequestPauseManagerPause();
|
|
}
|
|
else
|
|
{
|
|
// try to load by parsedMusicFile similar to pressStart normal mode
|
|
if (gameManager.musicSource != null && beatmapManager != null && !string.IsNullOrEmpty(beatmapManager.parsedMusicFile))
|
|
{
|
|
Debug.LogWarning($"Attempting Resources.Load for audio: {beatmapManager.parsedMusicFile}");
|
|
var ac = Resources.Load<AudioClip>(beatmapManager.parsedMusicFile);
|
|
if (ac != null)
|
|
{
|
|
gameManager.musicSource.clip = ac;
|
|
gameManager.musicSource.playOnAwake = false;
|
|
// warm up audio by playing muted
|
|
try
|
|
{
|
|
gameManager.musicSource.mute = true;
|
|
gameManager.musicSource.Play();
|
|
Debug.LogWarning("Warmed audio playback (muted) after Resources.Load");
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Debug.LogWarning("Failed to Play() for warmup after Resources.Load: " + ex.Message);
|
|
}
|
|
|
|
Debug.LogWarning("Loaded audio via Resources.Load(parsedMusicFile) and disabled playOnAwake");
|
|
|
|
RequestPauseManagerPause();
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"Resources.Load failed for '{beatmapManager.parsedMusicFile}'");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("No audio assigned: selected.audioFile null and parsedMusicFile empty or musicSource missing");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ensure PauseManager pause is requested; the RequestPauseManagerPause call above will have already
|
|
// attempted to pause the game if audio was set. If not yet requested, call it now to reuse PauseManager.
|
|
RequestPauseManagerPause();
|
|
|
|
// Start coroutine to wait for player input (Space) to begin playback and spawning
|
|
// Use a safe host for coroutine in case this MonoBehaviour is destroyed unexpectedly
|
|
var pauseMgr = PauseManager.Instance ?? FindObjectOfType<PauseManager>();
|
|
MonoBehaviour coroutineHost = (pauseMgr as MonoBehaviour) ?? (gameManager as MonoBehaviour) ?? (beatmapManager as MonoBehaviour) ?? this;
|
|
if (coroutineHost != null)
|
|
{
|
|
Debug.LogWarning("Starting WaitForPlayerStartAndBegin coroutine on host: " + coroutineHost.name);
|
|
coroutineHost.StartCoroutine(WaitForPlayerStartAndBegin(beatmapManager, gameManager));
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("No valid coroutine host found to start WaitForPlayerStartAndBegin.");
|
|
}
|
|
|
|
// unsubscribe from sceneLoaded
|
|
SceneManager.sceneLoaded -= OnSceneLoadedAfterQuickEnter;
|
|
}
|
|
|
|
private IEnumerator WaitForPlayerStartAndBegin(BeatmapManager beatmapManager, GameManager gameManager)
|
|
{
|
|
Debug.LogWarning("Waiting for player to press Space to start playback...");
|
|
// Wait until player presses Space
|
|
while (!Input.GetKeyDown(KeyCode.Space))
|
|
{
|
|
yield return null;
|
|
}
|
|
|
|
Debug.LogWarning("Player pressed Space. Preparing to start playback.");
|
|
|
|
// wait for NotePool prewarm to complete (block until finished to avoid hitch)
|
|
if (NotePool.Instance != null)
|
|
{
|
|
Debug.LogWarning("Waiting for NotePool prewarm to finish (blocking)...");
|
|
while (!NotePool.Instance.IsPrewarmed)
|
|
{
|
|
yield return null;
|
|
}
|
|
Debug.LogWarning("NotePool prewarm completed.");
|
|
}
|
|
|
|
// ensure audio has been warmed (attempt play muted if not already playing)
|
|
if (gameManager != null && gameManager.musicSource != null && gameManager.musicSource.clip != null && !gameManager.musicSource.isPlaying)
|
|
{
|
|
try
|
|
{
|
|
gameManager.musicSource.mute = true;
|
|
gameManager.musicSource.Play();
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
// Prewarm particle systems via AnimationController to avoid first-play hitch
|
|
var anim = AnimationController.Global ?? FindObjectOfType<AnimationController>();
|
|
if (anim != null)
|
|
{
|
|
Debug.LogWarning("Starting AnimationController particle prewarm (will wait until complete)...");
|
|
// yield until the prewarm completes
|
|
yield return StartCoroutine(anim.PrewarmParticlesRoutine(2));
|
|
Debug.LogWarning("AnimationController particle prewarm complete.");
|
|
}
|
|
|
|
// Unpause via PauseManager
|
|
var pauseMgr = PauseManager.Instance ?? FindObjectOfType<PauseManager>();
|
|
pauseMgr?.Pause(false);
|
|
|
|
// small buffer to avoid hitching immediately after unpause: wait configured realtime delay from GameManager
|
|
float unpauseBuffer = 3f;
|
|
if (gameManager != null) unpauseBuffer = Mathf.Max(0f, gameManager.playbackStartDelay);
|
|
yield return new WaitForSecondsRealtime(unpauseBuffer);
|
|
|
|
// Start spawning notes
|
|
if (beatmapManager != null && beatmapManager.beatmap != null)
|
|
{
|
|
Debug.LogWarning("Calling beatmapManager.LoadBeatmap");
|
|
beatmapManager.LoadBeatmap(beatmapManager.beatmap);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("Cannot start beatmap: beatmapManager or beatmap is null.");
|
|
}
|
|
|
|
// fade out black mask in gameManager if available
|
|
if (gameManager != null)
|
|
{
|
|
gameManager.StartCoroutine(gameManager.FadeOutBlackMask(0.25f));
|
|
}
|
|
|
|
// Play audio using GameManager.musicSource with delay
|
|
if (gameManager != null && gameManager.musicSource != null)
|
|
{
|
|
float delay = beatmapManager != null ? beatmapManager.globalDelaySeconds : 0f;
|
|
if (gameManager.musicSource.clip != null)
|
|
{
|
|
Debug.LogWarning($"Starting audio playback with delay {delay}");
|
|
// Use GameManager helper to ensure unmute and start playback reliably
|
|
try { gameManager.PlayMusicWithDelay(delay); }
|
|
catch (System.Exception ex) { Debug.LogWarning("Failed to start music via GameManager.PlayMusicWithDelay: " + ex); }
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("GameManager.musicSource.clip is null; skipping audio playback.");
|
|
}
|
|
}
|
|
|
|
// done with this helper object - allow it to be destroyed
|
|
Destroy(this.gameObject);
|
|
|
|
yield break;
|
|
}
|
|
|
|
// Debug helper: press F1 at runtime to print diagnostic state to Console (warnings)
|
|
void Update()
|
|
{
|
|
if (Input.GetKeyDown(KeyCode.F1))
|
|
{
|
|
Debug.LogWarning("selected_songInfo.DebugTrigger: F1 pressed - dumping diagnostic info");
|
|
Debug.LogWarning($"GameObject activeInHierarchy={gameObject.activeInHierarchy}, enabled={enabled}");
|
|
Debug.LogWarning($"quickEnter_gamePlay assigned={(quickEnter_gamePlay==null?"NULL":"ASSIGNED")}");
|
|
Debug.LogWarning($"enterDetailPageButton assigned={(enterDetailPageButton==null?"NULL":"ASSIGNED")}");
|
|
Debug.LogWarning($"blackMaskImage assigned={(blackMaskImage==null?"NULL":"ASSIGNED")}");
|
|
Debug.LogWarning($"SongDataHolder.SelectedSongData={(SongDataHolder.SelectedSongData==null?"NULL":SongDataHolder.SelectedSongData.songName)}");
|
|
var allButtons = FindObjectsOfType<SongButton>();
|
|
Debug.LogWarning($"Found {allButtons.Length} SongButton instances in scene");
|
|
for (int i = 0; i < allButtons.Length; i++)
|
|
{
|
|
var sb = allButtons[i];
|
|
if (sb == null) continue;
|
|
Debug.LogWarning($" [{i}] name={sb.name} active={sb.gameObject.activeInHierarchy}");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper to centralize PauseManager pause request so selected_songInfo reuses PauseManager implementation
|
|
private bool pauseRequested = false;
|
|
private void RequestPauseManagerPause()
|
|
{
|
|
if (pauseRequested) return;
|
|
var pm = PauseManager.Instance ?? FindObjectOfType<PauseManager>();
|
|
if (pm != null)
|
|
{
|
|
pm.Pause(true);
|
|
Debug.LogWarning("selected_songInfo: PauseManager.Pause(true) requested (centralized)");
|
|
pauseRequested = true;
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("selected_songInfo: PauseManager not found when requesting pause");
|
|
}
|
|
}
|
|
|
|
// Helper to get difficulty level (float) from SongData for a given difficulty id
|
|
private float GetDifficultyLevel(SongData song, int difficultyId)
|
|
{
|
|
if (song == null) return 0f;
|
|
if (song.chartFiles != null)
|
|
{
|
|
foreach (var entry in song.chartFiles)
|
|
{
|
|
if (entry != null && entry.difficulty == difficultyId)
|
|
{
|
|
return entry.difficultyLEVEL;
|
|
}
|
|
}
|
|
}
|
|
// fallback: try dictionary if available
|
|
if (song.difficultyNumberMap != null && song.difficultyNumberMap.ContainsKey(difficultyId))
|
|
{
|
|
return (float)song.difficultyNumberMap[difficultyId];
|
|
}
|
|
return 0f;
|
|
}
|
|
}
|