Files
bansonic_beta_main/Assets/scripts/Main_main/pressStart.cs
T
2026-07-20 22:19:25 +08:00

608 lines
20 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 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;
using Bansonic;
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 = 2f; // UI starts showing after 2 seconds; allow clicking then.
[Header("UI_UI Jump Blocker")]
public bool blockUIUISceneJump = false;
public string blockUIUISceneJumpMessage = "暂不可进入。";
// polling
private Coroutine pollCoroutine;
private float pollInterval = 3f;
private UI_PanelPopupTween helpPopupTween;
// 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(LocalizationService.Get("press_start.idle", "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)
{
helpPopupTween = helpContentObject.GetComponent<UI_PanelPopupTween>();
if (helpPopupTween == null)
{
helpPopupTween = helpContentObject.AddComponent<UI_PanelPopupTween>();
}
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<Bloom>(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;
// Keep the click lock aligned with when the main UI starts appearing.
float activationDelay = Mathf.Max(0f, startButtonDelay);
if (mainCanvasGroup != null)
{
activationDelay = Mathf.Min(activationDelay, Mathf.Max(0f, fadeDelay));
}
if (activationDelay > 0f)
{
yield return new WaitForSecondsRealtime(activationDelay);
}
// 启用按钮
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;
if (isActive)
{
HideHelpContentWithExitAnim();
}
else
{
if (helpPopupTween == null)
{
helpPopupTween = helpContentObject.GetComponent<UI_PanelPopupTween>();
if (helpPopupTween == null)
{
helpPopupTween = helpContentObject.AddComponent<UI_PanelPopupTween>();
}
}
helpContentObject.SetActive(true);
}
Debug.Log("[pressStart] Help button clicked. Help content active: " + !isActive);
}
}
private void OnCloseButtonClick()
{
if (helpContentObject != null)
{
HideHelpContentWithExitAnim();
Debug.Log("[pressStart] Close button clicked. Help content hidden.");
}
}
private void HideHelpContentWithExitAnim()
{
if (helpContentObject == null || !helpContentObject.activeInHierarchy)
{
return;
}
UI_PanelExitUtility.PlayExitThen(helpContentObject, () =>
{
if (helpContentObject != null)
{
helpContentObject.SetActive(false);
}
});
}
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 = "<color=orange>当前处于测试阶段</color><color=red>未授权版本</color><color=orange>版本号:</color><color=red>v1.0.0</color><color=orange>,请注意风险。</color>";
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 (blockUIUISceneJump)
{
string message = string.IsNullOrWhiteSpace(blockUIUISceneJumpMessage)
? "暂不可进入。"
: blockUIUISceneJumpMessage;
gNotice.error.display(message);
Debug.LogWarning("[pressStart] UI_UI scene jump blocked: " + message);
return;
}
if (warningText != null)
{
warningText.gameObject.SetActive(true);
warningText.text = LocalizationService.Get("press_start.warning_content", WARNING_TEXT_CONTENT);
}
// 启动进入游戏的异步序列
StartCoroutine(StartGameTransitionSequence());
}
private IEnumerator StartGameTransitionSequence()
{
// 1. 0.5秒内将 Global Volume 的 Bloom Intensity 从 0 变到 3
if (globalVolume != null && globalVolume.profile.TryGet<Bloom>(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;
if (!gTransition.LoadScene("UI_UI", LoadSceneMode.Single))
{
SceneManager.LoadScene("UI_UI");
}
}
private IEnumerator PollForBanflagAndProceed()
{
UpdateStatus(LocalizationService.Get("press_start.waiting_banflag", "Waiting for banflag..."), new Color(1f, 0.5f, 0f)); // orange
while (true)
{
bool found = check_banflag_testBanflag();
if (found)
{
UpdateStatus(LocalizationService.Get("press_start.loading_test_mode", "Banflag detected. Loading test mode..."), Color.green);
// small delay to show status
yield return new WaitForSeconds(0.5f);
if (gTransition.LoadScene(testModeSceneName, LoadSceneMode.Single))
{
while (gTransition.IsBusy)
{
yield return null;
}
yield break;
}
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(testModeSceneName);
while (asyncLoad != null && !asyncLoad.isDone)
{
yield return null;
}
yield break;
}
else
{
UpdateStatus(LocalizationService.Get("press_start.waiting_banflag", "Waiting for banflag..."), new Color(1f, 0.5f, 0f)); // orange
}
yield return new WaitForSeconds(pollInterval);
}
}
private IEnumerator LoadSceneAsync(string sceneName)
{
if (gTransition.LoadScene(sceneName, LoadSceneMode.Single))
{
while (gTransition.IsBusy)
{
yield return null;
}
yield break;
}
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName);
while (asyncLoad != null && !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(LocalizationService.Get("press_start.error_path_not_configured", "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} bytesBase64 前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(LocalizationService.Get("press_start.banflag_found", "Banflag found"), Color.green);
return banflag_exists;
}
catch (System.Exception ex)
{
Debug.LogError($"读取 banflag 文件时发生错误: {ex}");
UpdateStatus(LocalizationService.Get("press_start.error_reading_banflag", "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;
}
}
}