Files
bansonic_beta_main/Assets/scripts/gamePlay_gameplay/GameManager.cs
T

627 lines
24 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.IO;
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.Networking;
public class GameManager : MonoBehaviour
{
public BeatmapManager beatmapManager; // غ͹
public NoteSpawner noteSpawner; //
public AudioSource musicSource; // ֲ
[Header("paths")]
// ٴӾ̬жȡ
public string JSONPath;
public string audioPath;
public string bgPicPath;
// Optional: sprite renderer to show background image
public SpriteRenderer backgroundRenderer;
// NEW: UI Text to display banflag content from pressStart
[Header("Debug / Test")]
public Text banflagTextUI;
[Header("UI Overlays")]
public UnityEngine.UI.Image blackMaskImage; // assign in inspector: full-screen black overlay
[Header("Playback")]
[Tooltip("Delay in seconds after unpausing (press Space) before starting audio and spawning. Configure in inspector.")]
public float playbackStartDelay = 3f;
private bool pauseSubscribed = false;
private bool musicWasPlayingBeforePause = false;
private void SubscribeToPauseManager()
{
if (pauseSubscribed) return;
// prefer the singleton, but try to find in scene if null
var pm = PauseManager.Instance ?? FindObjectOfType<PauseManager>();
if (pm != null)
{
pm.OnPauseStateChanged += HandlePauseStateChanged;
pauseSubscribed = true;
}
}
private void UnsubscribeFromPauseManager()
{
if (!pauseSubscribed) return;
var pm = PauseManager.Instance ?? FindObjectOfType<PauseManager>();
if (pm != null)
{
pm.OnPauseStateChanged -= HandlePauseStateChanged;
}
pauseSubscribed = false;
}
private void OnEnable()
{
SubscribeToPauseManager();
}
private void OnDisable()
{
UnsubscribeFromPauseManager();
}
private void HandlePauseStateChanged(bool isPaused)
{
if (musicSource != null)
{
try
{
if (isPaused)
{
// remember whether music was playing and pause it to stop timeline advancing
musicWasPlayingBeforePause = musicSource.isPlaying;
if (musicWasPlayingBeforePause)
{
musicSource.Pause();
}
}
else
{
// Do not change mute state here. External startup flow will unmute when appropriate.
// resume if it was playing before pause
if (musicWasPlayingBeforePause)
{
try { musicSource.UnPause(); } catch { }
}
// reset flag
musicWasPlayingBeforePause = false;
}
}
catch { }
}
}
/// <summary>
/// Fade out the black mask image over duration seconds (unscaled), then disable its raycast target so UI passes through.
/// </summary>
public IEnumerator FadeOutBlackMask(float duration)
{
if (blackMaskImage == null) yield break;
// ensure image active
if (!blackMaskImage.gameObject.activeSelf) blackMaskImage.gameObject.SetActive(true);
float t = 0f;
Color c = blackMaskImage.color;
float startA = c.a;
while (t < duration)
{
t += Time.unscaledDeltaTime;
float frac = Mathf.Clamp01(t / Mathf.Max(0.0001f, duration));
c.a = Mathf.Lerp(startA, 0f, frac);
blackMaskImage.color = c;
yield return null;
}
// ensure fully transparent
c.a = 0f;
blackMaskImage.color = c;
// disable raycast so underlying UI can receive input
try { blackMaskImage.raycastTarget = false; } catch { }
// optionally deactivate the overlay to save draw calls
blackMaskImage.gameObject.SetActive(false);
}
// Public helper to reliably unmute and start music playback, respecting delay.
public void PlayMusicWithDelay(float delaySeconds)
{
if (musicSource == null) return;
try
{
// Ensure unmuted
musicSource.mute = false;
}
catch { }
try
{
// If a delay is specified, stop current and schedule playback
if (delaySeconds > 0f)
{
// Stop any currently playing to avoid overlapping schedules
try { musicSource.Stop(); } catch { }
musicSource.PlayDelayed(delaySeconds);
Debug.Log($"GameManager.PlayMusicWithDelay: PlayDelayed({delaySeconds}) called");
}
else
{
// If already playing but paused, try UnPause; otherwise Play
if (musicSource.isPlaying)
{
// already playing - nothing to do
Debug.Log("GameManager.PlayMusicWithDelay: musicSource already playing");
}
else
{
// Try UnPause first (in case it was paused), otherwise Play
try { musicSource.UnPause(); Debug.Log("GameManager.PlayMusicWithDelay: UnPause called"); }
catch { musicSource.Play(); Debug.Log("GameManager.PlayMusicWithDelay: Play called"); }
}
}
}
catch (System.Exception ex)
{
Debug.LogWarning($"PlayMusicWithDelay failed: {ex}");
try { musicSource.Play(); } catch { }
}
}
void Start()
{
Debug.Log("GameManager Start() ");
// ؼǷΪ
if (beatmapManager == null) Debug.LogError("beatmapManager δֵ");
if (noteSpawner == null) Debug.LogError("noteSpawner δֵ");
if (musicSource == null) Debug.LogError("musicSource δֵ");
// preload audio fully and start muted playback to warm up audio decoding
if (musicSource != null && musicSource.clip != null)
{
musicSource.mute = true;
musicSource.loop = false;
musicSource.playOnAwake = false;
try
{
musicSource.Play();
Debug.Log("GameManager: warmed up audio playback (muted)");
}
catch (System.Exception ex)
{
Debug.LogWarning("GameManager: failed to warm up audio: " + ex.Message);
}
}
// pressStart Ѿȡ banflag ݣʾ UIˣ
if (banflagTextUI != null && !string.IsNullOrEmpty(pressStart.banflagContent))
{
banflagTextUI.text = pressStart.banflagContent;
Debug.Log("Displayed banflag content from pressStart into banflagTextUI.");
}
// test mode ʹⲿ·ԤԴͣϵͳȴո
if (GameConfig.testMode)
{
// ӳٸֵ Start() лȡ̬·ʱ pressStart.cs Ѿв
JSONPath = pressStart.testmode_beatmapJSON_path;
audioPath = pressStart.testmode_audioFile_path;
bgPicPath = pressStart.testmode_bgPicFile_path;
Debug.Log("Test mode active: using external paths to preload assets");
// also update banflag UI if content exists
if (banflagTextUI != null && !string.IsNullOrEmpty(pressStart.banflagContent))
{
banflagTextUI.text = pressStart.banflagContent;
}
StartCoroutine(HandleTestModeStartup());
return;
}
else
{
StartCoroutine(HandleNormalModeStartup());
}
// Ensure black mask blocks input and is fully opaque at scene start (will fade out after loading).
if (blackMaskImage != null)
{
try
{
Color cc = blackMaskImage.color;
cc.a = 1f;
blackMaskImage.color = cc;
blackMaskImage.gameObject.SetActive(true);
blackMaskImage.raycastTarget = true;
// start automatic fade from alpha=1 to 0 over 1 second after Start
StartCoroutine(FadeOutBlackMask(1f));
}
catch { }
}
}
private IEnumerator HandleTestModeStartup()
{
// Preload audio from audioPath (absolute)
if (!string.IsNullOrEmpty(audioPath))
{
if (!File.Exists(audioPath))
{
Debug.LogError($"TestMode audio file not found: {audioPath}");
}
else
{
// Use UnityWebRequestMultimedia instead of WWW which is deprecated and can be unreliable for file:// audio
string url = "file://" + audioPath;
// determine audio type from extension for best compatibility
AudioType audioType = AudioType.UNKNOWN;
string ext = Path.GetExtension(audioPath)?.ToLowerInvariant();
if (!string.IsNullOrEmpty(ext))
{
switch (ext)
{
case ".wav": audioType = AudioType.WAV; break;
case ".ogg": audioType = AudioType.OGGVORBIS; break;
case ".mp3": audioType = AudioType.MPEG; break;
case ".aif":
case ".aiff": audioType = AudioType.AIFF; break;
default: audioType = AudioType.UNKNOWN; break;
}
}
using (var uwr = UnityWebRequestMultimedia.GetAudioClip(url, audioType))
{
yield return uwr.SendWebRequest();
#if UNITY_2020_1_OR_NEWER
if (uwr.result == UnityWebRequest.Result.ConnectionError || uwr.result == UnityWebRequest.Result.ProtocolError)
#else
if (uwr.isNetworkError || uwr.isHttpError)
#endif
{
Debug.LogError($"TestMode audio load failed: {uwr.error}");
}
else
{
AudioClip clip = DownloadHandlerAudioClip.GetContent(uwr);
if (clip == null)
{
Debug.LogError("Failed to obtain AudioClip from downloaded data");
}
else
{
// wait for audio data to be loaded if necessary
float waitStart = Time.realtimeSinceStartup;
while (clip.loadState == AudioDataLoadState.Loading && Time.realtimeSinceStartup - waitStart < 5f)
{
yield return null;
}
if (clip.loadState != AudioDataLoadState.Loaded)
{
Debug.LogWarning($"AudioClip loadState is {clip.loadState}. It may still stream or be incomplete.");
}
if (musicSource == null)
{
Debug.LogError("musicSource is null - cannot assign TestMode audio");
}
else
{
clip.name = Path.GetFileName(audioPath);
musicSource.clip = clip;
musicSource.loop = false;
musicSource.playOnAwake = false;
// Warm up decoding by playing briefly muted; avoid try/catch around yield (not allowed).
musicSource.mute = true;
musicSource.Play();
// allow a few frames for audio system to start
yield return null;
musicSource.Stop();
Debug.Log("TestMode audio loaded into AudioSource");
// After loading audio, enable overlay and pause via PauseManager
var pm = PauseManager.Instance ?? FindObjectOfType<PauseManager>();
if (pm != null)
{
pm.Pause(true);
Debug.Log("PauseManager.Pause(true) invoked after TestMode audio load");
}
}
}
}
}
}
}
else
{
Debug.LogWarning("TestMode audioPath not provided");
}
// Preload background image into sprite renderer
if (backgroundRenderer != null)
{
if (!string.IsNullOrEmpty(bgPicPath))
{
if (!File.Exists(bgPicPath))
{
Debug.LogError($"TestMode background image not found: {bgPicPath}");
}
else
{
byte[] imgBytes = null;
try
{
imgBytes = File.ReadAllBytes(bgPicPath);
}
catch (System.Exception ex)
{
Debug.LogError($"ȡͼƬļ: {ex}");
}
if (imgBytes != null)
{
Texture2D tex = new Texture2D(2, 2);
if (tex.LoadImage(imgBytes))
{
Sprite s = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f));
backgroundRenderer.sprite = s;
// ޸ĵ㣺 SpriteRenderer ͸Ϊ 255 (1.0f)
Color color = backgroundRenderer.color;
color.a = 1.0f;
backgroundRenderer.color = color;
// ֱӦɳ־¼ assignment
Debug.Log("Background sprite assigned (ensure your SpriteRenderer size fits scene)");
}
else
{
Debug.LogError($"޷ֽڴ Texture2D: {bgPicPath}");
}
}
}
}
else
{
Debug.LogWarning("TestMode bgPicPath δá");
}
}
else
{
Debug.LogWarning("backgroundRenderer δãء");
}
// Read JSON from JSONPath and parse via BeatmapManager.ParseJsonOnly
if (!string.IsNullOrEmpty(JSONPath))
{
if (!File.Exists(JSONPath))
{
Debug.LogError($"TestMode beatmap JSON not found: {JSONPath}");
yield break; // abort
}
string jsonContent = null;
try
{
jsonContent = File.ReadAllText(JSONPath);
}
catch (System.Exception ex)
{
Debug.LogError($"ȡ TestMode JSON ļ: {ex}");
yield break;
}
bool parsed = beatmapManager.ParseJsonOnly(jsonContent);
if (!parsed)
{
Debug.LogError("ParseJsonOnly ʧܣֹͣģʽ");
yield break;
}
// Do not start spawning yet. We will start after unpausing.
Debug.Log("Beatmap parsed (deferred start). Ready to unpause.");
}
else
{
Debug.LogError("TestMode JSONPath δá");
yield break;
}
// Pause the system until Space pressed
// Ensure we are subscribed before invoking pause so we track audio state
SubscribeToPauseManager();
PauseManager.Instance?.Pause(true);
UpdateStatusOnConsole("Paused: press Space to start playback");
// Wait for space key down (use unscaled input loop)
while (!Input.GetKeyDown(KeyCode.Space))
{
yield return null;
}
// Resume using PauseManager
PauseManager.Instance?.Pause(false);
// small buffer to avoid hitching immediately after unpause: wait configured realtime delay
yield return new WaitForSecondsRealtime(Mathf.Max(0f, playbackStartDelay));
// Start spawning using the parsed beatmap
if (beatmapManager.beatmap != null)
{
beatmapManager.LoadBeatmap(beatmapManager.beatmap);
}
else
{
Debug.LogError("ʧܣbeatmap δΪ");
yield break;
}
// If audio clip was loaded into musicSource.clip, play now with delay from parsed globalDelaySeconds
float delaySeconds = beatmapManager != null ? beatmapManager.globalDelaySeconds : 0f;
PlayMusicWithDelay(delaySeconds);
UpdateStatusOnConsole("Playback started");
}
private IEnumerator HandleNormalModeStartup()
{
// If a Beatmap was already provided by previous scene (pendingSongData path), skip loading default JSON
if (beatmapManager != null && beatmapManager.beatmap != null)
{
Debug.Log("HandleNormalModeStartup: existing beatmap found on BeatmapManager; skipping default JSON load.");
// Pause the system until Space pressed
SubscribeToPauseManager();
PauseManager.Instance?.Pause(true);
UpdateStatusOnConsole("Paused: press Space to start playback");
// Wait for space
while (!Input.GetKeyDown(KeyCode.Space))
{
yield return null;
}
// Resume
PauseManager.Instance?.Pause(false);
// small buffer to avoid hitching immediately after unpause: wait configured realtime delay
yield return new WaitForSecondsRealtime(Mathf.Max(0f, playbackStartDelay));
// Start spawning using the existing parsed beatmap
if (beatmapManager.beatmap != null)
{
noteSpawner.LoadBeatmap(beatmapManager.beatmap);
}
else
{
Debug.LogError("HandleNormalModeStartup: beatmap was expected but is null");
yield break;
}
// Play background music if assigned
if (musicSource != null && musicSource.clip != null)
{
float delay = beatmapManager != null ? beatmapManager.globalDelaySeconds : 0f;
PlayMusicWithDelay(delay);
}
else
{
// try load via parsedMusicFile if available
if (beatmapManager != null && !string.IsNullOrEmpty(beatmapManager.parsedMusicFile))
{
AudioClip musicClip = Resources.Load<AudioClip>(beatmapManager.parsedMusicFile);
if (musicClip != null)
{
musicSource.clip = musicClip;
// ensure we don't accidentally autoplay when assigning clips
musicSource.playOnAwake = false;
musicSource.Stop();
float delay = beatmapManager.globalDelaySeconds;
PlayMusicWithDelay(delay);
// ensure overlay shows and pause logic runs after loading the clip
var pm2 = PauseManager.Instance ?? FindObjectOfType<PauseManager>();
if (pm2 != null)
{
pm2.Pause(true);
Debug.Log("PauseManager.Pause(true) invoked after assigning musicClip in normal startup");
}
}
}
}
UpdateStatusOnConsole("Playback started");
yield break;
}
// ԭ̣
string beatmapFilePath = Path.Combine(Application.streamingAssetsPath, "Emilia_demo.json");
if (!File.Exists(beatmapFilePath))
{
Debug.LogError($"ļ: {beatmapFilePath}");
yield break;
}
string json = File.ReadAllText(beatmapFilePath);
bool parsed = beatmapManager.ParseJsonOnly(json);
if (!parsed)
{
Debug.LogError("ParseJsonOnly ʧ");
yield break;
}
// ͣϵͳ
SubscribeToPauseManager();
PauseManager.Instance?.Pause(true);
UpdateStatusOnConsole("Paused: press Space to start playback");
// ȴո
while (!Input.GetKeyDown(KeyCode.Space))
{
yield return null;
}
// ָ
PauseManager.Instance?.Pause(false);
// small buffer to avoid hitching immediately after unpause: wait configured realtime delay
yield return new WaitForSecondsRealtime(Mathf.Max(0f, playbackStartDelay));
//
if (beatmapManager.beatmap != null)
{
noteSpawner.LoadBeatmap(beatmapManager.beatmap);
}
else
{
Debug.LogError("beatmap δ");
yield break;
}
// ű֣ӳٲ beatmapManager.globalDelaySeconds
if (!string.IsNullOrEmpty(beatmapManager.parsedMusicFile))
{
AudioClip musicClip = Resources.Load<AudioClip>(beatmapManager.parsedMusicFile);
if (musicClip == null)
{
Debug.LogError($"ļʧ: {beatmapManager.parsedMusicFile}");
}
else
{
musicSource.clip = musicClip;
// ensure we don't accidentally autoplay when assigning clips
musicSource.playOnAwake = false;
musicSource.Stop();
float delay = beatmapManager.globalDelaySeconds;
PlayMusicWithDelay(delay);
// After assigning clip, enable overlay and pause
var pm3 = PauseManager.Instance ?? FindObjectOfType<PauseManager>();
if (pm3 != null)
{
pm3.Pause(true);
Debug.Log("PauseManager.Pause(true) invoked after assigning parsedMusicFile clip");
}
}
}
else
{
Debug.LogError(" musicFile Ϊգ");
}
UpdateStatusOnConsole("Playback started");
}
private void UpdateStatusOnConsole(string message)
{
Debug.Log(message);
}
}