using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using System.IO; using System.Text; using System.Text.RegularExpressions; using UnityEngine.UI; using TMPro; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; public class pressStart : MonoBehaviour { public string sceneName_toNextScene = "selectYourSongFirst"; public string testModeSceneName = "gamePlay_gamePlay"; [SerializeField] private string banflag_filePath = "C:/ProgramData/Bansonic/Caches/Bansonic_TestOutput"; private bool banflag_exists; public static string testmode_audioFile_path; public static string testmode_bgPicFile_path; public static string testmode_beatmapJSON_path; // new: store banflag content for other scenes to read public static string banflagContent = string.Empty; // UI text to show status public Text statusText; public Text warningText; [Header("New UI Buttons")] public Button startButton; public Button helpButton; public Button closeButton; public Button exitButton; public GameObject helpContentObject; [Header("Fade Settings")] public CanvasGroup mainCanvasGroup; public float fadeDelay = 0f; public float fadeDuration = 1f; [Header("TMP Flashing Settings")] public TextMeshProUGUI flashingText; public float flashInterval = 0.5f; [Header("Start Sequence Settings")] public Volume globalVolume; public Image fadeOutImage; public float startButtonDelay = 6f; // 6秒后才允许点击 Start // polling private Coroutine pollCoroutine; private float pollInterval = 3f; // Start is called before the first frame update void Start() { // sceneName_toNextScene = "Songs_Select"; banflag_exists = false; testmode_audioFile_path = string.Empty; testmode_bgPicFile_path = string.Empty; testmode_beatmapJSON_path = string.Empty; banflagContent = string.Empty; // Ensure status text shows idle UpdateStatus("Press Enter to continue.", Color.green); // Bind buttons if (startButton != null) { startButton.onClick.AddListener(OnStartButtonClick); } if (helpButton != null) { helpButton.onClick.AddListener(OnHelpButtonClick); } if (closeButton != null) { closeButton.onClick.AddListener(OnCloseButtonClick); } if (exitButton != null) { exitButton.onClick.AddListener(OnExitButtonClick); } if (helpContentObject != null) { helpContentObject.SetActive(false); } // Initialize fadeOutImage if (fadeOutImage != null) { Color c = fadeOutImage.color; c.a = 0f; fadeOutImage.color = c; fadeOutImage.gameObject.SetActive(false); } // Initialize Global Volume Bloom intensity to 0 if (globalVolume != null && globalVolume.profile.TryGet(out var bloom)) { bloom.intensity.Override(0f); } // Initialize CanvasGroup and start fade-in if (mainCanvasGroup != null) { mainCanvasGroup.alpha = 0f; StartCoroutine(FadeInMainCanvasGroup()); } // Start flashing logic if (flashingText != null) { StartCoroutine(FlashTMPText()); } // Start button delay logic if (startButton != null) { StartCoroutine(StartButtonActivationDelay()); } } private IEnumerator StartButtonActivationDelay() { if (startButton == null) yield break; // 初始禁用按钮 startButton.interactable = false; // 等待指定时间 (使用 unscaledTime 以防 timeScale 为 0) yield return new WaitForSecondsRealtime(startButtonDelay); // 启用按钮 startButton.interactable = true; Debug.Log("[pressStart] Start button is now active."); } private IEnumerator FlashTMPText() { if (flashingText == null) yield break; float elapsed = 0f; while (true) { elapsed += Time.deltaTime; // 使用 Mathf.PingPong 在 0 到 1 之间往复 // 除以 flashInterval 可以控制循环的速度 float alpha = Mathf.PingPong(elapsed / flashInterval, 1f); Color color = flashingText.color; color.a = alpha; flashingText.color = color; yield return null; } } private IEnumerator FadeInMainCanvasGroup() { if (fadeDelay > 0) yield return new WaitForSeconds(fadeDelay); float elapsed = 0f; while (elapsed < fadeDuration) { elapsed += Time.deltaTime; mainCanvasGroup.alpha = Mathf.Lerp(0f, 1f, elapsed / fadeDuration); yield return null; } mainCanvasGroup.alpha = 1f; } private void OnStartButtonClick() { Debug.Log("[pressStart] Start button clicked."); HandleGameStartLogic(); } private void OnHelpButtonClick() { if (helpContentObject != null) { bool isActive = helpContentObject.activeSelf; helpContentObject.SetActive(!isActive); Debug.Log("[pressStart] Help button clicked. Help content active: " + !isActive); } } private void OnCloseButtonClick() { if (helpContentObject != null) { helpContentObject.SetActive(false); Debug.Log("[pressStart] Close button clicked. Help content hidden."); } } private void OnExitButtonClick() { Debug.Log("[pressStart] Exit button clicked. Application quitting."); #if UNITY_EDITOR UnityEditor.EditorApplication.isPlaying = false; #else Application.Quit(); #endif } // Update is called once per frame private bool check_enterNextScene = false; private static readonly string WARNING_TEXT_CONTENT = "当前处于测试阶段未授权版本版本号:v1.0.0,请注意风险。"; void Update() { if (!(Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter))) return; // 如果按钮未激活 (还在倒计时),不允许通过键盘进入 if (startButton != null && !startButton.interactable) { Debug.Log("[pressStart] Start request ignored. Button is not active yet."); return; } HandleGameStartLogic(); } private void HandleGameStartLogic() { bool requestTestMode = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift); if (requestTestMode) { Debug.Log("[pressStart] Enter+Shift or button start requested, starting test mode polling."); GameConfig.testMode = true; if (pollCoroutine != null) StopCoroutine(pollCoroutine); pollCoroutine = StartCoroutine(PollForBanflagAndProceed()); return; } // 修改为点击一次即可开始进入游戏序列 Debug.Log("[pressStart] Start requested, initiating transition sequence."); GameConfig.testMode = false; if (warningText != null) { warningText.gameObject.SetActive(true); warningText.text = WARNING_TEXT_CONTENT; } // 启动进入游戏的异步序列 StartCoroutine(StartGameTransitionSequence()); } private IEnumerator StartGameTransitionSequence() { // 1. 0.5秒内将 Global Volume 的 Bloom Intensity 从 0 变到 3 if (globalVolume != null && globalVolume.profile.TryGet(out var bloom)) { float elapsed = 0f; float duration = 0.5f; float startVal = bloom.intensity.value; float targetVal = 3f; while (elapsed < duration) { elapsed += Time.deltaTime; bloom.intensity.Override(Mathf.Lerp(startVal, targetVal, elapsed / duration)); yield return null; } bloom.intensity.Override(targetVal); } // 2. 结束变 3 后,将 Image 的不透明度在 0.5 秒内从 0 变到 255 (alpha = 1) if (fadeOutImage != null) { fadeOutImage.gameObject.SetActive(true); float elapsed = 0f; float duration = 0.5f; Color color = fadeOutImage.color; while (elapsed < duration) { elapsed += Time.deltaTime; color.a = Mathf.Lerp(0f, 1f, elapsed / duration); fadeOutImage.color = color; yield return null; } color.a = 1f; fadeOutImage.color = color; } // 3. 切换场景 Debug.Log("[pressStart] Transition sequence complete. Loading UI_UI scene."); Time.timeScale = 1f; SceneManager.LoadScene("UI_UI"); } private IEnumerator PollForBanflagAndProceed() { UpdateStatus("Waiting for banflag...", new Color(1f, 0.5f, 0f)); // orange while (true) { bool found = check_banflag_testBanflag(); if (found) { UpdateStatus("Banflag detected. Loading test mode...", Color.green); // small delay to show status yield return new WaitForSeconds(0.5f); AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(testModeSceneName); while (!asyncLoad.isDone) { yield return null; } yield break; } else { UpdateStatus("Waiting for banflag...", new Color(1f, 0.5f, 0f)); // orange } yield return new WaitForSeconds(pollInterval); } } private IEnumerator LoadSceneAsync(string sceneName) { AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName); while (!asyncLoad.isDone) { yield return null; } } private void UpdateStatus(string message, Color color) { if (statusText != null) { statusText.text = message; statusText.color = color; } Debug.Log(message); } private string NormalizeToForwardSlashes(string path) { if (string.IsNullOrEmpty(path)) return string.Empty; try { // Get full absolute path to remove any relative segments string full = Path.GetFullPath(path); // Replace backslashes with forward slashes string fwd = full.Replace('\\', '/'); // Collapse multiple slashes into single string collapsed = Regex.Replace(fwd, "/{2,}", "/"); // Remove trailing slash except when path is root like "C:/" if (collapsed.Length > 3 && collapsed.EndsWith("/")) collapsed = collapsed.TrimEnd('/'); return collapsed; } catch { // Fallback: replace backslashes and collapse string f = path.Replace('\\', '/'); string c = Regex.Replace(f, "/{2,}", "/"); if (c.Length > 3 && c.EndsWith("/")) c = c.TrimEnd('/'); return c; } } // returns true if banflag detected private bool check_banflag_testBanflag() { try { // reset previous results banflag_exists = false; testmode_audioFile_path = string.Empty; testmode_bgPicFile_path = string.Empty; testmode_beatmapJSON_path = string.Empty; banflagContent = string.Empty; if (string.IsNullOrEmpty(banflag_filePath)) { Debug.LogWarning("banflag_filePath 未设置"); UpdateStatus("Error: banflag path not configured", Color.red); return false; } string filePath = Path.Combine(banflag_filePath, "test.banflag"); if (!File.Exists(filePath)) { Debug.LogWarning($"未找到对应 banflag 文件: {filePath}"); return false; } // mark exists banflag_exists = true; byte[] data = File.ReadAllBytes(filePath); if (data == null || data.Length == 0) { Debug.LogWarning($"banflag 文件为空: {filePath}"); } else { // Documentation text normalized. string text = null; try { text = Encoding.UTF8.GetString(data); } catch { text = null; } bool looksLikeText = false; if (!string.IsNullOrEmpty(text)) { // Documentation text normalized. int nonPrintable = 0; int checkLen = Mathf.Min(256, text.Length); for (int i = 0; i < checkLen; i++) { char c = text[i]; if (char.IsControl(c) && c != '\r' && c != '\n' && c != '\t') nonPrintable++; } looksLikeText = (nonPrintable == 0); } if (looksLikeText) { Debug.Log($"已读取 banflag 文件: {filePath}\n内容:\n{text}"); // store the readable content for other scenes banflagContent = text; } else { // Documentation text normalized. string base64 = System.Convert.ToBase64String(data); Debug.Log($"已读取 banflag 文件(二进制): {filePath},长度={data.Length} bytes,Base64 前200字符预览:\n{(base64.Length > 200 ? base64.Substring(0,200) + "..." : base64)}"); banflagContent = $"[Binary Data] Length: {data.Length} bytes"; } } // Documentation text normalized. string dir = Path.GetDirectoryName(filePath); if (string.IsNullOrEmpty(dir)) dir = banflag_filePath; // find JSON string foundJson = string.Empty; try { string[] jsons = Directory.GetFiles(dir, "*.json", SearchOption.TopDirectoryOnly); if (jsons != null && jsons.Length > 0) { foundJson = jsons[0]; } } catch { } // find audio: mp3, wav, ogg (in that priority) string foundAudio = string.Empty; try { string[] exts = new string[] { "*.mp3", "*.wav", "*.ogg" }; foreach (var pat in exts) { string[] matches = Directory.GetFiles(dir, pat, SearchOption.TopDirectoryOnly); if (matches != null && matches.Length > 0) { foundAudio = matches[0]; break; } } } catch { } // find image: jpg/jpeg, png (priority jpg then png) string foundImage = string.Empty; try { string[] imgExts = new string[] { "*.jpg", "*.jpeg", "*.png" }; foreach (var pat in imgExts) { string[] matches = Directory.GetFiles(dir, pat, SearchOption.TopDirectoryOnly); if (matches != null && matches.Length > 0) { foundImage = matches[0]; break; } } } catch { } // normalize and assign testmode_beatmapJSON_path = string.IsNullOrEmpty(foundJson) ? string.Empty : NormalizeToForwardSlashes(foundJson); testmode_audioFile_path = string.IsNullOrEmpty(foundAudio) ? string.Empty : NormalizeToForwardSlashes(foundAudio); testmode_bgPicFile_path = string.IsNullOrEmpty(foundImage) ? string.Empty : NormalizeToForwardSlashes(foundImage); // Debug the normalized paths Debug.Log($"banflag_exists={banflag_exists}"); Debug.Log($"testmode_beatmapJSON_path = {testmode_beatmapJSON_path}"); Debug.Log($"testmode_audioFile_path = {testmode_audioFile_path}"); Debug.Log($"testmode_bgPicFile_path = {testmode_bgPicFile_path}"); UpdateStatus("Banflag found", Color.green); return banflag_exists; } catch (System.Exception ex) { Debug.LogError($"读取 banflag 文件时发生错误: {ex}"); UpdateStatus("Error reading banflag", Color.red); // ensure flags cleared on error banflag_exists = false; testmode_audioFile_path = string.Empty; testmode_bgPicFile_path = string.Empty; testmode_beatmapJSON_path = string.Empty; banflagContent = string.Empty; return false; } } }