using System.Collections.Generic; using System.Collections; using UnityEngine; using UnityEngine.UI; public class MapGenerator3D : MonoBehaviour { public MapConfigSO mapConfig1; public MapConfigSO mapConfig2; public MapConfigSO mapConfig3; private MapConfigSO mapConfig; [Header("3D布局参数")] public float depthGap = 12f; public float horizontalSpread = 6f; public float verticalSpacing = 8f; [Header("房间参数")] public float roomRadius = 1.5f; public float roomHeight = 1f; public Color roomColor = new Color(0.3f, 0.7f, 0.3f); [Header("房间数据")] public RoomDataSO minorEnemyRoomData; public RoomDataSO eliteEnemyRoomData; public RoomDataSO restRoomData; public RoomDataSO bossRoomData; [Header("房间颜色")] public Color minorEnemyColor = new Color(0.3f, 0.7f, 0.3f); public Color eliteEnemyColor = new Color(0.8f, 0.3f, 0.3f); public Color restRoomColor = new Color(0.5f, 0.8f, 0.5f); public Color bossColor = new Color(0.8f, 0.2f, 0.8f); [Header("路径参数")] public float pathWidth = 0.6f; public Color pathColor = new Color(1f, 0.8f, 0f); [Header("触发器参数")] public float triggerRadius = 2f; public float triggerHeight = 0.5f; [Header("题目库")] public List allQuestions = new List(); [Header("UI参数")] public GameObject questionPanel; public Text questionText; public Button[] answerButtons; [Header("血量系统")] public int baseHealth = 10; public int currentHealth; public Text healthText; public Slider healthSlider; public GameObject gameOverPanel; [Header("玩家等级系统")] public int playerLevel = 1; public const int MAX_LEVEL = 30; public int currentExperience = 0; public int attackPower = 1; public Text levelText; public Text attackText; public Text expText; [Header("金币UI")] public Text goldText; [Header("战斗系统")] public GameObject battlePanel; public Image playerIcon; public Image monsterIcon; public Slider monsterHealthSlider; public Text monsterHealthText; public Text battleStatusText; [Header("怪物图标")] public Sprite minorEnemyIcon; public Sprite eliteEnemyIcon; public Sprite bossIcon; public Sprite playerBattleIcon; [Header("玩家战斗血条")] public Slider playerBattleHealthSlider; public Text playerBattleHealthText; [Header("战斗动画参数")] public float attackMoveDistance = 50f; public float attackDuration = 0.15f; public float shakeDuration = 0.2f; public float shakeIntensity = 10f; [Header("子弹效果参数")] public Color bulletColor = new Color(1f, 0.5f, 0f); public float bulletSize = 15f; public float bulletSpeed = 800f; public float bulletDuration = 0.2f; private bool isInBattle = false; private int monsterMaxHealth = 5; private int monsterCurrentHealth; private RoonType currentBattleRoomType; private bool isAnsweringQuestion = false; private List rooms = new(); private List paths = new(); private List triggers = new(); private const string GUEST_STUDY_ABILITY = "guest_studyAbility"; private const string GUEST_TOTAL_PLAYTIME = "guest_totalPlayTime"; private const string GUEST_TOTAL_ROOMS = "guest_totalRooms"; private const string GUEST_TOTAL_CORRECT = "guest_totalCorrect"; private const string GUEST_TOTAL_WRONG = "guest_totalWrong"; private const string GUEST_TOTAL_GOLD = "guest_totalGold"; private const string GUEST_PLAYER_LEVEL = "guest_playerLevel"; private const string GUEST_EXPERIENCE = "guest_experience"; [Header("学习参数")] public int studyAbility = 1; [Header("游戏统计")] public float gameStartTime; public float totalPlayTime; public int currentDifficulty = 1; public int correctAnswerCount = 0; public int wrongAnswerCount = 0; public int totalRoomsCompleted = 0; public bool isGameCompleted = false; [Header("场景设置")] public string menuSceneName = "MenuScene"; public int GetMaxHealth() { return baseHealth + (playerLevel - 1); } public int GetAttackPower() { return 1 + (playerLevel / 10); } public void AddExperience(int amount) { if (playerLevel >= MAX_LEVEL) return; currentExperience += amount; while (currentExperience >= GetExperienceToNextLevel() && playerLevel < MAX_LEVEL) { currentExperience -= GetExperienceToNextLevel(); LevelUp(); } UpdateLevelUI(); } public int GetExperienceToNextLevel() { return 100 * playerLevel; } void LevelUp() { int oldMaxHealth = GetMaxHealth(); playerLevel++; int newMaxHealth = GetMaxHealth(); currentHealth += (newMaxHealth - oldMaxHealth); attackPower = GetAttackPower(); Debug.Log($"升级!当前等级: {playerLevel}, 最大血量: {newMaxHealth}, 攻击力: {attackPower}"); UpdateHealthUI(); UpdatePlayerBattleHealthUI(); } void UpdateLevelUI() { if (levelText != null) { levelText.text = $"Lv.{playerLevel}"; } if (attackText != null) { attackText.text = $"ATK:{attackPower}"; } if (expText != null) { expText.text = $"EXP: {currentExperience}/{GetExperienceToNextLevel()}"; } } [Header("金币和道具系统")] public int currentGold = 0; public int shield = 0; public bool hasHint = false; public int doubleGoldTurns = 0; public List inventory = new List(); public List shopItems = new List(); private GameObject currentTriggerRoom; private MathQuestionSO currentQuestion; private QuestionData currentOnlineQuestion; private int currentQuestionId = -1; private List onlineQuestions = new List(); private bool onlineQuestionsLoadStarted = false; private bool onlineQuestionsLoadFinished = false; private bool onlineQuestionsLoadFailed = false; private string onlineQuestionsLoadError = ""; [Header("2D地图设置")] public GameObject mapPanelPrefab; public GameObject roomButtonPrefab; public GameObject pathLinePrefab; public Transform player; private GameObject mapPanel; private RectTransform mapPanelRect; private GameObject mapContent; private List roomButtons = new(); private Dictionary roomToButtonMap = new(); // ========== 游戏进度相关 ========== private int currentMaxColumn = 0; private Dictionary> columnGroups = new(); private HashSet completedRooms = new(); private HashSet attemptedRooms = new(); // ========== 房间连接关系(记录所有连接,无论方向) ========== private Dictionary> allConnections = new(); // 所有房间之间的连接 private GameObject currentPlayerRoom = null; // 玩家当前所在的房间 private bool isAtRootNode = true; // 是否在逻辑根节点(初始状态) // ========== 小车移动相关 ========== [Header("小车移动参数")] public float maxSpeed = 8f; public float arrivalDistance = 2f; public float stopDistance = 0.5f; private Vector3 targetPosition; private bool isMoving = false; private GameObject targetRoom; // ========== 结束 ========== private void Start() { gameStartTime = Time.time; InitPlayerLevel(); currentHealth = GetMaxHealth(); currentGold = 0; shield = 0; hasHint = false; doubleGoldTurns = 0; inventory.Clear(); isInBattle = false; correctAnswerCount = 0; wrongAnswerCount = 0; totalRoomsCompleted = 0; isGameCompleted = false; UpdateHealthUI(); UpdateGoldUI(); UpdateLevelUI(); if (battlePanel != null) battlePanel.SetActive(false); if (LoginManager.Instance != null && !LoginManager.Instance.IsGuest()) { studyAbility = LoginManager.Instance.GetStudyAbility(); LoadOnlineQuestions(); } else { LoadGuestData(); } ChooseMap(); CreateMap(); Create2DMapPanel(); Create2DMap(); currentMaxColumn = 0; FindInitialPlayerRoom(); if (player != null && columnGroups.ContainsKey(0) && columnGroups[0].Count > 0) { GameObject firstRoom = columnGroups[0][0]; Vector3 initialPos = new Vector3(firstRoom.transform.position.x, 0.6f, firstRoom.transform.position.z); player.position = initialPos; Debug.Log($"玩家物理位置放置在第一关: {firstRoom.name}"); } if (questionPanel != null) questionPanel.SetActive(false); if (gameOverPanel != null) gameOverPanel.SetActive(false); } void InitPlayerLevel() { if (LoginManager.Instance != null && !LoginManager.Instance.IsGuest()) { UserData user = LoginManager.Instance.GetCurrentUser(); if (user != null) { playerLevel = Mathf.Clamp(user.currentLevel, 1, MAX_LEVEL); currentExperience = user.experience; } } else { playerLevel = PlayerPrefs.GetInt(GUEST_PLAYER_LEVEL, 1); currentExperience = PlayerPrefs.GetInt(GUEST_EXPERIENCE, 0); } attackPower = GetAttackPower(); Debug.Log($"初始化玩家等级: {playerLevel}, 攻击力: {attackPower}, 最大血量: {GetMaxHealth()}"); } void LoadOnlineQuestions() { onlineQuestionsLoadStarted = true; onlineQuestionsLoadFinished = false; onlineQuestionsLoadFailed = false; onlineQuestionsLoadError = ""; onlineQuestions.Clear(); if (NetworkManager.Instance == null) { onlineQuestionsLoadFinished = true; onlineQuestionsLoadFailed = true; onlineQuestionsLoadError = "NetworkManager未初始化。"; Debug.LogWarning($"在线题目不可用: {onlineQuestionsLoadError}"); Debug.LogWarning("NetworkManager未初始化,使用本地题目"); return; } int difficulty = currentDifficulty; bool isReviewMode = GameModeManager.Instance != null && GameModeManager.Instance.IsReviewMode(); if (isReviewMode) { Debug.Log("加载复习题库..."); NetworkManager.Instance.GetReviewQuestions(difficulty, response => { if (response.success) { onlineQuestions.Clear(); if (response.data != null) { onlineQuestions.AddRange(response.data); } onlineQuestionsLoadFinished = true; onlineQuestionsLoadFailed = onlineQuestions.Count == 0; onlineQuestionsLoadError = onlineQuestionsLoadFailed ? "复习题目接口返回0道题目。" : ""; Debug.Log($"成功加载 {onlineQuestions.Count} 道复习题目"); } else { onlineQuestionsLoadFinished = true; onlineQuestionsLoadFailed = true; onlineQuestionsLoadError = response.message; Debug.LogWarning($"加载复习题目失败: {response.message}"); } }, error => { onlineQuestionsLoadFinished = true; onlineQuestionsLoadFailed = true; onlineQuestionsLoadError = error; Debug.LogWarning($"加载复习题目失败: {error}"); } ); } else { Debug.Log("加载普通题库..."); NetworkManager.Instance.GetQuestionsByDifficulty(difficulty, response => { if (response.success) { onlineQuestions.Clear(); if (response.data != null) { onlineQuestions.AddRange(response.data); } onlineQuestionsLoadFinished = true; onlineQuestionsLoadFailed = onlineQuestions.Count == 0; onlineQuestionsLoadError = onlineQuestionsLoadFailed ? "题目接口返回0道题目。" : ""; Debug.Log($"成功加载 {onlineQuestions.Count} 道在线题目"); } else { onlineQuestionsLoadFinished = true; onlineQuestionsLoadFailed = true; onlineQuestionsLoadError = response.message; Debug.LogWarning($"加载在线题目失败: {response.message}"); } }, error => { onlineQuestionsLoadFinished = true; onlineQuestionsLoadFailed = true; onlineQuestionsLoadError = error; Debug.LogWarning($"加载在线题目失败: {error}"); } ); } } void ChooseMap() { if (studyAbility <= 5) mapConfig = mapConfig1; else if (studyAbility <= 10) mapConfig = mapConfig2; else mapConfig = mapConfig3; } void CreateMap() { List previousColumn = new(); columnGroups.Clear(); allConnections.Clear(); for (int column = 0; column < mapConfig.roomBlueprints.Count; column++) { var blueprint = mapConfig.roomBlueprints[column]; int amount = Random.Range(blueprint.min, blueprint.max); float z = column * depthGap; List currentColumn = new(); float totalWidth = (amount - 1) * horizontalSpread; float startX = -totalWidth / 2f; for (int i = 0; i < amount; i++) { float x; float y = 0f; if (column == 0 && i == 0) { x = 0f; } else { x = startX + i * horizontalSpread; } Vector3 pos = new Vector3(x, y, z); RoonType roomType = GetRandomRoomType(column, mapConfig.roomBlueprints.Count); GameObject room = CreateRoom(pos, roomType); room.name = $"Room_{column}_{i}"; currentColumn.Add(room); rooms.Add(room); GameObject trigger = CreateTrigger(room, pos); triggers.Add(trigger); allConnections[room] = new List(); } if (previousColumn.Count > 0) { CreateConnections(previousColumn, currentColumn); } previousColumn = currentColumn; columnGroups[column] = currentColumn; } // 输出连接关系用于调试 Debug.Log("=== 房间连接关系 ==="); foreach (var kvp in allConnections) { string connections = ""; foreach (var target in kvp.Value) { connections += target.name + " "; } Debug.Log($"{kvp.Key.name} 连接到: {connections}"); } } // ========================= // 找到初始玩家房间 // ========================= void FindInitialPlayerRoom() { isAtRootNode = true; currentPlayerRoom = null; Debug.Log("初始化玩家位置:逻辑根节点,物理位置在1-1"); } GameObject CreateRoom(Vector3 pos, RoonType roomType) { GameObject room = GameObject.CreatePrimitive(PrimitiveType.Cylinder); room.name = "Room"; room.transform.position = pos; room.transform.localScale = new Vector3( roomRadius * 2, roomHeight * 0.5f, roomRadius * 2 ); Destroy(room.GetComponent()); BoxCollider boxCollider = room.AddComponent(); boxCollider.size = new Vector3(roomRadius * 2, roomHeight, roomRadius * 2); Renderer r = room.GetComponent(); r.material = new Material(Shader.Find("Universal Render Pipeline/Lit")); r.material.color = GetRoomColor(roomType); RoomDataSO roomData = GetRoomData(roomType); RoomInfo roomInfo = room.AddComponent(); roomInfo.roomType = roomType; roomInfo.roomData = roomData; return room; } RoomDataSO GetRoomData(RoonType roomType) { return roomType switch { RoonType.MinorEnemy => minorEnemyRoomData, RoonType.EliteEnemy => eliteEnemyRoomData, RoonType.RestRoom => restRoomData, RoonType.Boss => bossRoomData, _ => minorEnemyRoomData }; } Color GetRoomColor(RoonType roomType) { return roomType switch { RoonType.MinorEnemy => minorEnemyColor, RoonType.EliteEnemy => eliteEnemyColor, RoonType.RestRoom => restRoomColor, RoonType.Boss => bossColor, _ => roomColor }; } RoonType GetRandomRoomType(int column, int totalColumns) { if (column == 0) { return RoonType.MinorEnemy; } if (column == totalColumns - 1) { return RoonType.Boss; } float random = Random.value; if (random < 0.5f) { return RoonType.MinorEnemy; } else if (random < 0.75f) { return RoonType.EliteEnemy; } else { return RoonType.RestRoom; } } GameObject CreateTrigger(GameObject room, Vector3 roomPos) { GameObject triggerObj = new GameObject("RoomTrigger_" + room.name); triggerObj.transform.position = roomPos + Vector3.up * (roomHeight + triggerHeight); SphereCollider collider = triggerObj.AddComponent(); collider.isTrigger = true; collider.radius = triggerRadius; RoomTrigger triggerScript = triggerObj.AddComponent(); triggerScript.SetRoom(room, this); return triggerObj; } void Create2DMapPanel() { if (mapPanelPrefab == null) { Canvas canvas = FindObjectOfType(); if (canvas == null) { GameObject canvasObj = new GameObject("Canvas"); canvas = canvasObj.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvasObj.AddComponent(); canvasObj.AddComponent(); } mapPanel = new GameObject("MapPanel"); mapPanel.transform.SetParent(canvas.transform, false); mapPanelRect = mapPanel.AddComponent(); mapPanelRect.sizeDelta = new Vector2(620, 1080); mapPanelRect.anchorMin = new Vector2(1, 0.5f); mapPanelRect.anchorMax = new Vector2(1, 0.5f); mapPanelRect.pivot = new Vector2(1, 0.5f); mapPanelRect.anchoredPosition = new Vector2(-20, 0); Image panelImage = mapPanel.AddComponent(); panelImage.color = new Color(0.1f, 0.1f, 0.1f, 0.8f); ScrollRect scrollRect = mapPanel.AddComponent(); GameObject viewport = new GameObject("Viewport"); viewport.transform.SetParent(mapPanel.transform, false); RectTransform viewportRect = viewport.AddComponent(); viewportRect.sizeDelta = new Vector2(0, 0); viewportRect.anchorMin = Vector2.zero; viewportRect.anchorMax = Vector2.one; viewportRect.offsetMin = new Vector2(10, 10); viewportRect.offsetMax = new Vector2(-10, -10); Image viewportImage = viewport.AddComponent(); viewportImage.color = new Color(0.2f, 0.2f, 0.2f, 0.5f); Mask mask = viewport.AddComponent(); mask.showMaskGraphic = true; mapContent = new GameObject("Content"); mapContent.transform.SetParent(viewport.transform, false); RectTransform contentRect = mapContent.AddComponent(); contentRect.anchorMin = new Vector2(0, 1); contentRect.anchorMax = new Vector2(1, 1); contentRect.pivot = new Vector2(0.5f, 1); contentRect.sizeDelta = new Vector2(0, 0); ContentSizeFitter sizeFitter = mapContent.AddComponent(); sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; VerticalLayoutGroup layoutGroup = mapContent.AddComponent(); layoutGroup.childAlignment = TextAnchor.UpperCenter; layoutGroup.spacing = 10; layoutGroup.padding = new RectOffset(10, 10, 20, 20); layoutGroup.childForceExpandWidth = true; layoutGroup.childForceExpandHeight = false; layoutGroup.childControlWidth = true; layoutGroup.childControlHeight = false; scrollRect.viewport = viewportRect; scrollRect.content = contentRect; scrollRect.horizontal = false; scrollRect.vertical = true; GameObject titleObj = new GameObject("Title"); titleObj.transform.SetParent(mapPanel.transform, false); RectTransform titleRect = titleObj.AddComponent(); titleRect.anchorMin = new Vector2(0, 1); titleRect.anchorMax = new Vector2(1, 1); titleRect.sizeDelta = new Vector2(0, 40); titleRect.anchoredPosition = new Vector2(0, -20); Text titleText = titleObj.AddComponent(); titleText.text = "地图导航"; titleText.font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); titleText.fontSize = 20; titleText.alignment = TextAnchor.MiddleCenter; titleText.color = Color.white; } else { mapPanel = Instantiate(mapPanelPrefab, FindObjectOfType().transform); mapPanelRect = mapPanel.GetComponent(); mapContent = mapPanel.transform.Find("Viewport/Content")?.gameObject; if (mapContent == null) { Debug.LogError("MapPanel预制体结构不正确!"); } } if (player == null) { player = GameObject.FindGameObjectWithTag("Player")?.transform; } CreateHealthUI(); } void CreateHealthUI() { Canvas canvas = FindObjectOfType(); if (canvas == null) return; GameObject healthPanel = new GameObject("HealthPanel"); healthPanel.transform.SetParent(canvas.transform, false); RectTransform healthPanelRect = healthPanel.AddComponent(); healthPanelRect.anchorMin = new Vector2(0, 0); healthPanelRect.anchorMax = new Vector2(0, 0); healthPanelRect.pivot = new Vector2(0, 0); healthPanelRect.anchoredPosition = new Vector2(20, 20); healthPanelRect.sizeDelta = new Vector2(300, 60); Image panelBg = healthPanel.AddComponent(); panelBg.color = new Color(0, 0, 0, 0.5f); GameObject sliderBg = new GameObject("HealthSlider"); sliderBg.transform.SetParent(healthPanel.transform, false); RectTransform sliderRect = sliderBg.AddComponent(); sliderRect.anchorMin = new Vector2(0, 0.5f); sliderRect.anchorMax = new Vector2(1, 0.5f); sliderRect.pivot = new Vector2(0.5f, 0.5f); sliderRect.anchoredPosition = Vector2.zero; sliderRect.sizeDelta = new Vector2(-20, 20); Slider slider = sliderBg.AddComponent(); Image sliderBgImage = sliderBg.AddComponent(); sliderBgImage.color = Color.gray; GameObject fillArea = new GameObject("Fill Area"); fillArea.transform.SetParent(sliderBg.transform, false); RectTransform fillRect = fillArea.AddComponent(); fillRect.anchorMin = Vector2.zero; fillRect.anchorMax = Vector2.one; fillRect.sizeDelta = Vector2.zero; GameObject fill = new GameObject("Fill"); fill.transform.SetParent(fillArea.transform, false); RectTransform fillImageRect = fill.AddComponent(); fillImageRect.anchorMin = Vector2.zero; fillImageRect.anchorMax = Vector2.one; fillImageRect.sizeDelta = Vector2.zero; Image fillImage = fill.AddComponent(); fillImage.color = Color.red; slider.fillRect = fillImageRect; slider.handleRect = null; slider.maxValue = GetMaxHealth(); slider.value = currentHealth; slider.interactable = false; healthSlider = slider; GameObject healthTextObj = new GameObject("HealthText"); healthTextObj.transform.SetParent(healthPanel.transform, false); RectTransform textRect = healthTextObj.AddComponent(); textRect.anchorMin = Vector2.zero; textRect.anchorMax = Vector2.one; textRect.sizeDelta = Vector2.zero; healthText = healthTextObj.AddComponent(); healthText.text = $"{currentHealth}/{GetMaxHealth()}"; healthText.font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); healthText.fontSize = 18; healthText.alignment = TextAnchor.MiddleCenter; healthText.color = Color.white; CreateLevelUI(); } void CreateLevelUI() { Canvas canvas = FindObjectOfType(); if (canvas == null) return; GameObject levelPanel = new GameObject("LevelPanel"); levelPanel.transform.SetParent(canvas.transform, false); RectTransform levelPanelRect = levelPanel.AddComponent(); levelPanelRect.anchorMin = new Vector2(0, 0); levelPanelRect.anchorMax = new Vector2(0, 0); levelPanelRect.pivot = new Vector2(0, 0); levelPanelRect.anchoredPosition = new Vector2(20, 90); levelPanelRect.sizeDelta = new Vector2(200, 70); Image panelBg = levelPanel.AddComponent(); panelBg.color = new Color(0, 0, 0, 0.5f); GameObject levelTextObj = new GameObject("LevelText"); levelTextObj.transform.SetParent(levelPanel.transform, false); RectTransform levelTextRect = levelTextObj.AddComponent(); levelTextRect.anchorMin = new Vector2(0, 0.5f); levelTextRect.anchorMax = new Vector2(0.5f, 1); levelTextRect.sizeDelta = Vector2.zero; levelText = levelTextObj.AddComponent(); levelText.text = $"Lv.{playerLevel}"; levelText.font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); levelText.fontSize = 22; levelText.alignment = TextAnchor.MiddleCenter; levelText.color = Color.yellow; levelText.fontStyle = FontStyle.Bold; GameObject expTextObj = new GameObject("ExpText"); expTextObj.transform.SetParent(levelPanel.transform, false); RectTransform expTextRect = expTextObj.AddComponent(); expTextRect.anchorMin = new Vector2(0, 0); expTextRect.anchorMax = new Vector2(1, 0.5f); expTextRect.sizeDelta = Vector2.zero; expText = expTextObj.AddComponent(); expText.text = $"EXP: {currentExperience}/{GetExperienceToNextLevel()}"; expText.font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); expText.fontSize = 14; expText.alignment = TextAnchor.MiddleCenter; expText.color = Color.white; GameObject attackTextObj = new GameObject("AttackText"); attackTextObj.transform.SetParent(levelPanel.transform, false); RectTransform attackTextRect = attackTextObj.AddComponent(); attackTextRect.anchorMin = new Vector2(0.5f, 0.5f); attackTextRect.anchorMax = new Vector2(1, 1); attackTextRect.sizeDelta = Vector2.zero; attackText = attackTextObj.AddComponent(); attackText.text = $"ATK:{attackPower}"; attackText.font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); attackText.fontSize = 16; attackText.alignment = TextAnchor.MiddleCenter; attackText.color = Color.red; } void UpdateHealthUI() { if (healthText != null) { healthText.text = $"{currentHealth}/{GetMaxHealth()}"; } if (healthSlider != null) { healthSlider.value = currentHealth; } } void TakeDamage(int damage) { if (shield > 0) { int absorbed = Mathf.Min(shield, damage); shield -= absorbed; damage -= absorbed; Debug.Log($"护盾吸收了 {absorbed} 点伤害!剩余护盾: {shield}"); } currentHealth -= damage; currentHealth = Mathf.Max(0, currentHealth); UpdateHealthUI(); UpdatePlayerBattleHealthUI(); Debug.Log($"受到{damage}点伤害!当前血量:{currentHealth}/{GetMaxHealth()}"); if (currentHealth <= 0) { GameOver(); } } void UpdateGoldUI() { if (goldText != null) { goldText.text = $"金币: {currentGold}"; } } void AddGold(int amount) { if (doubleGoldTurns > 0) { amount *= 2; Debug.Log($"金币翻倍!获得 {amount} 金币"); } currentGold += amount; UpdateGoldUI(); Debug.Log($"获得 {amount} 金币!当前金币: {currentGold}"); } public void HealPlayer(int amount) { currentHealth = Mathf.Min(currentHealth + amount, GetMaxHealth()); UpdateHealthUI(); UpdatePlayerBattleHealthUI(); Debug.Log($"恢复 {amount} 点生命!当前生命: {currentHealth}/{GetMaxHealth()}"); } public void AddShield(int amount) { shield += amount; Debug.Log($"获得 {amount} 点护盾!当前护盾: {shield}"); } public void ActivateDoubleGold(int turns) { doubleGoldTurns = turns; Debug.Log($"激活金币翻倍!持续 {turns} 个房间"); } public void ActivateHint() { hasHint = true; Debug.Log("激活提示!下次答题将显示提示"); } void UseHint() { if (!hasHint) return; hasHint = false; if (currentQuestion != null) { Debug.Log($"提示:正确答案是 {currentQuestion.correctAnswer}"); } } void AddItemToInventory(ItemDataSO item) { inventory.Add(item); Debug.Log($"获得道具:{item.itemName}"); } void UseItem(int index) { if (index < 0 || index >= inventory.Count) return; ItemDataSO item = inventory[index]; IItemEffect effect = item.GetEffect(); if (effect != null) { effect.ApplyEffect(this); inventory.RemoveAt(index); Debug.Log($"使用道具:{item.itemName}"); } } void GameOver() { Debug.Log("游戏结束!"); totalPlayTime = Time.time - gameStartTime; UpdateAchievementsOnGameEnd(); SaveGameSession(); Time.timeScale = 0f; if (gameOverPanel != null) { gameOverPanel.SetActive(true); } else { CreateGameOverPanel(false); } } void Victory() { Debug.Log("通关成功!"); totalPlayTime = Time.time - gameStartTime; UpdateAchievementsOnGameEnd(); SaveGameSession(); Time.timeScale = 0f; if (gameOverPanel != null) { gameOverPanel.SetActive(true); } else { CreateGameOverPanel(true); } } void UpdateAchievementsOnGameEnd() { if (AchievementManager.Instance != null) { AchievementManager.Instance.UpdateAchievement(AchievementType.CollectGold, currentGold); AchievementManager.Instance.UpdateAchievement(AchievementType.PlayTime, (int)totalPlayTime); } } void UpdateAchievementProgress(AchievementType type, int value) { if (AchievementManager.Instance != null) { AchievementManager.Instance.UpdateAchievement(type, value); } } void SaveGameSession() { if (LoginManager.Instance == null || LoginManager.Instance.IsGuest()) { SaveGuestData(); return; } if (NetworkManager.Instance == null) { Debug.LogWarning("NetworkManager未初始化,无法保存游戏数据"); return; } GameResultRequest resultRequest = new GameResultRequest { playTime = totalPlayTime, roomsCompleted = totalRoomsCompleted, correctAnswers = correctAnswerCount, wrongAnswers = wrongAnswerCount, difficulty = currentDifficulty, isCompleted = isGameCompleted, goldCollected = currentGold }; NetworkManager.Instance.SaveGameResult(resultRequest, response => { if (response.success) { ApplyServerStudyAbility(response.data); Debug.Log($"游戏数据保存成功!时长: {totalPlayTime:F1}秒, 房间: {totalRoomsCompleted}, 正确: {correctAnswerCount}, 错误: {wrongAnswerCount}"); } else { Debug.LogWarning($"保存游戏数据失败: {response.message}"); } }, error => { Debug.LogWarning($"保存游戏数据失败: {error}"); } ); SyncPlayerLevelToServer(); SyncAchievementsToServer(); } void ApplyServerStudyAbility(GameResultData resultData) { if (resultData == null || resultData.nextStudyAbility <= 0) { return; } studyAbility = resultData.nextStudyAbility; if (LoginManager.Instance != null) { LoginManager.Instance.SetStudyAbility(studyAbility); } Debug.Log($"服务器学习力已同步,新学习力: {studyAbility}"); } void SyncPlayerLevelToServer() { if (LoginManager.Instance == null || LoginManager.Instance.IsGuest()) return; if (NetworkManager.Instance == null) return; NetworkManager.Instance.UpdatePlayerLevel( playerLevel, currentExperience, response => { if (response.success) { Debug.Log($"等级同步成功!等级: {playerLevel}, 经验: {currentExperience}"); } else { Debug.LogWarning($"等级同步失败: {response.message}"); } }, error => { Debug.LogWarning($"等级同步请求失败: {error}"); } ); } void SaveGuestData() { float savedPlayTime = PlayerPrefs.GetFloat(GUEST_TOTAL_PLAYTIME, 0f); int savedRooms = PlayerPrefs.GetInt(GUEST_TOTAL_ROOMS, 0); int savedCorrect = PlayerPrefs.GetInt(GUEST_TOTAL_CORRECT, 0); int savedWrong = PlayerPrefs.GetInt(GUEST_TOTAL_WRONG, 0); int savedGold = PlayerPrefs.GetInt(GUEST_TOTAL_GOLD, 0); PlayerPrefs.SetFloat(GUEST_TOTAL_PLAYTIME, savedPlayTime + totalPlayTime); PlayerPrefs.SetInt(GUEST_TOTAL_ROOMS, savedRooms + totalRoomsCompleted); PlayerPrefs.SetInt(GUEST_TOTAL_CORRECT, savedCorrect + correctAnswerCount); PlayerPrefs.SetInt(GUEST_TOTAL_WRONG, savedWrong + wrongAnswerCount); PlayerPrefs.SetInt(GUEST_TOTAL_GOLD, savedGold + currentGold); PlayerPrefs.SetInt(GUEST_PLAYER_LEVEL, playerLevel); PlayerPrefs.SetInt(GUEST_EXPERIENCE, currentExperience); PlayerPrefs.Save(); UpdateGuestStudyAbility(); if (AchievementManager.Instance != null) { AchievementManager.Instance.SaveGuestAchievements(); } Debug.Log($"游客数据已保存!等级: {playerLevel}, 经验: {currentExperience}, 总时长: {savedPlayTime + totalPlayTime:F1}秒"); } void UpdateGuestStudyAbility() { float correctRate = (correctAnswerCount + wrongAnswerCount) > 0 ? (float)correctAnswerCount / (correctAnswerCount + wrongAnswerCount) : 0f; int abilityChange = 0; if (correctRate >= 0.9f && totalRoomsCompleted >= 5) { abilityChange = 1; } else if (correctRate < 0.5f && wrongAnswerCount > 5) { abilityChange = -1; } if (abilityChange != 0) { int currentAbility = PlayerPrefs.GetInt(GUEST_STUDY_ABILITY, 1); int newAbility = Mathf.Max(1, currentAbility + abilityChange); PlayerPrefs.SetInt(GUEST_STUDY_ABILITY, newAbility); PlayerPrefs.Save(); studyAbility = newAbility; Debug.Log($"游客学习力更新!新学习力: {newAbility}"); } } void LoadGuestData() { studyAbility = PlayerPrefs.GetInt(GUEST_STUDY_ABILITY, 1); Debug.Log($"加载游客数据,学习力: {studyAbility}"); } public static int GetGuestStudyAbility() { return PlayerPrefs.GetInt(GUEST_STUDY_ABILITY, 1); } public static float GetGuestTotalPlayTime() { return PlayerPrefs.GetFloat(GUEST_TOTAL_PLAYTIME, 0f); } public static int GetGuestTotalRooms() { return PlayerPrefs.GetInt(GUEST_TOTAL_ROOMS, 0); } public static int GetGuestTotalCorrect() { return PlayerPrefs.GetInt(GUEST_TOTAL_CORRECT, 0); } public static int GetGuestTotalWrong() { return PlayerPrefs.GetInt(GUEST_TOTAL_WRONG, 0); } void UpdateStudyAbilityOnGameEnd() { if (LoginManager.Instance == null || LoginManager.Instance.IsGuest()) return; float correctRate = (correctAnswerCount + wrongAnswerCount) > 0 ? (float)correctAnswerCount / (correctAnswerCount + wrongAnswerCount) : 0f; int abilityChange = 0; if (correctRate >= 0.9f && totalRoomsCompleted >= 5) { abilityChange = 1; } else if (correctRate < 0.5f && wrongAnswerCount > 5) { abilityChange = -1; } if (abilityChange != 0) { int newAbility = Mathf.Max(1, studyAbility + abilityChange); NetworkManager.Instance.UpdateStudyAbility(newAbility, response => { if (response.success) { studyAbility = newAbility; if (LoginManager.Instance != null) { LoginManager.Instance.SetStudyAbility(newAbility); } Debug.Log($"学习力更新成功!新学习力: {newAbility}"); } }, error => { Debug.LogWarning($"更新学习力失败: {error}"); } ); } } void SyncAchievementsToServer() { if (LoginManager.Instance == null || LoginManager.Instance.IsGuest()) return; if (AchievementManager.Instance == null) return; AchievementManager.Instance.SyncToServer(); } void CreateGameOverPanel(bool isVictory) { Canvas canvas = FindObjectOfType(); if (canvas == null) return; gameOverPanel = new GameObject("GameOverPanel"); gameOverPanel.transform.SetParent(canvas.transform, false); RectTransform panelRect = gameOverPanel.AddComponent(); panelRect.anchorMin = Vector2.zero; panelRect.anchorMax = Vector2.one; panelRect.sizeDelta = Vector2.zero; Image panelImage = gameOverPanel.AddComponent(); panelImage.color = isVictory ? new Color(0, 0.3f, 0, 0.85f) : new Color(0.3f, 0, 0, 0.85f); GameObject textObj = new GameObject("GameOverText"); textObj.transform.SetParent(gameOverPanel.transform, false); RectTransform textRect = textObj.AddComponent(); textRect.anchorMin = new Vector2(0.5f, 0.5f); textRect.anchorMax = new Vector2(0.5f, 0.5f); textRect.pivot = new Vector2(0.5f, 0.5f); textRect.sizeDelta = new Vector2(500, 200); Text gameOverText = textObj.AddComponent(); if (isVictory) { gameOverText.text = $"通关成功!\n\n用时: {totalPlayTime:F1}秒\n完成房间: {totalRoomsCompleted}\n正确率: {(correctAnswerCount + wrongAnswerCount > 0 ? (float)correctAnswerCount / (correctAnswerCount + wrongAnswerCount) * 100 : 0):F1}%\n\n点击返回菜单"; gameOverText.color = Color.yellow; } else { gameOverText.text = $"游戏结束\n\n用时: {totalPlayTime:F1}秒\n完成房间: {totalRoomsCompleted}\n正确率: {(correctAnswerCount + wrongAnswerCount > 0 ? (float)correctAnswerCount / (correctAnswerCount + wrongAnswerCount) * 100 : 0):F1}%\n\n点击返回菜单"; gameOverText.color = Color.white; } gameOverText.font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); gameOverText.fontSize = 28; gameOverText.alignment = TextAnchor.MiddleCenter; Button restartButton = gameOverPanel.AddComponent