| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643 |
- 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<MathQuestionSO> allQuestions = new List<MathQuestionSO>();
- [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<GameObject> rooms = new();
- private List<GameObject> paths = new();
- private List<GameObject> 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<ItemDataSO> inventory = new List<ItemDataSO>();
- public List<ItemDataSO> shopItems = new List<ItemDataSO>();
-
- private GameObject currentTriggerRoom;
- private MathQuestionSO currentQuestion;
- private QuestionData currentOnlineQuestion;
- private int currentQuestionId = -1;
- private List<QuestionData> onlineQuestions = new List<QuestionData>();
- 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<MapRoomButton> roomButtons = new();
- private Dictionary<GameObject, MapRoomButton> roomToButtonMap = new();
-
- // ========== 游戏进度相关 ==========
- private int currentMaxColumn = 0;
- private Dictionary<int, List<GameObject>> columnGroups = new();
- private HashSet<GameObject> completedRooms = new();
- private HashSet<GameObject> attemptedRooms = new();
-
- // ========== 房间连接关系(记录所有连接,无论方向) ==========
- private Dictionary<GameObject, List<GameObject>> 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<GameObject> 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<GameObject> 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<GameObject>();
- }
- 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<CapsuleCollider>());
- BoxCollider boxCollider = room.AddComponent<BoxCollider>();
- boxCollider.size = new Vector3(roomRadius * 2, roomHeight, roomRadius * 2);
- Renderer r = room.GetComponent<Renderer>();
- r.material = new Material(Shader.Find("Universal Render Pipeline/Lit"));
- r.material.color = GetRoomColor(roomType);
-
- RoomDataSO roomData = GetRoomData(roomType);
- RoomInfo roomInfo = room.AddComponent<RoomInfo>();
- 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<SphereCollider>();
- collider.isTrigger = true;
- collider.radius = triggerRadius;
-
- RoomTrigger triggerScript = triggerObj.AddComponent<RoomTrigger>();
- triggerScript.SetRoom(room, this);
-
- return triggerObj;
- }
- void Create2DMapPanel()
- {
- if (mapPanelPrefab == null)
- {
- Canvas canvas = FindObjectOfType<Canvas>();
- if (canvas == null)
- {
- GameObject canvasObj = new GameObject("Canvas");
- canvas = canvasObj.AddComponent<Canvas>();
- canvas.renderMode = RenderMode.ScreenSpaceOverlay;
- canvasObj.AddComponent<CanvasScaler>();
- canvasObj.AddComponent<GraphicRaycaster>();
- }
- mapPanel = new GameObject("MapPanel");
- mapPanel.transform.SetParent(canvas.transform, false);
-
- mapPanelRect = mapPanel.AddComponent<RectTransform>();
- 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<Image>();
- panelImage.color = new Color(0.1f, 0.1f, 0.1f, 0.8f);
-
- ScrollRect scrollRect = mapPanel.AddComponent<ScrollRect>();
-
- GameObject viewport = new GameObject("Viewport");
- viewport.transform.SetParent(mapPanel.transform, false);
- RectTransform viewportRect = viewport.AddComponent<RectTransform>();
- 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<Image>();
- viewportImage.color = new Color(0.2f, 0.2f, 0.2f, 0.5f);
-
- Mask mask = viewport.AddComponent<Mask>();
- mask.showMaskGraphic = true;
-
- mapContent = new GameObject("Content");
- mapContent.transform.SetParent(viewport.transform, false);
- RectTransform contentRect = mapContent.AddComponent<RectTransform>();
- 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<ContentSizeFitter>();
- sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
-
- VerticalLayoutGroup layoutGroup = mapContent.AddComponent<VerticalLayoutGroup>();
- 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<RectTransform>();
- 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<Text>();
- titleText.text = "地图导航";
- titleText.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
- titleText.fontSize = 20;
- titleText.alignment = TextAnchor.MiddleCenter;
- titleText.color = Color.white;
- }
- else
- {
- mapPanel = Instantiate(mapPanelPrefab, FindObjectOfType<Canvas>().transform);
- mapPanelRect = mapPanel.GetComponent<RectTransform>();
- 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<Canvas>();
- if (canvas == null) return;
-
- GameObject healthPanel = new GameObject("HealthPanel");
- healthPanel.transform.SetParent(canvas.transform, false);
- RectTransform healthPanelRect = healthPanel.AddComponent<RectTransform>();
- 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<Image>();
- panelBg.color = new Color(0, 0, 0, 0.5f);
-
- GameObject sliderBg = new GameObject("HealthSlider");
- sliderBg.transform.SetParent(healthPanel.transform, false);
- RectTransform sliderRect = sliderBg.AddComponent<RectTransform>();
- 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<Slider>();
- Image sliderBgImage = sliderBg.AddComponent<Image>();
- sliderBgImage.color = Color.gray;
-
- GameObject fillArea = new GameObject("Fill Area");
- fillArea.transform.SetParent(sliderBg.transform, false);
- RectTransform fillRect = fillArea.AddComponent<RectTransform>();
- 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<RectTransform>();
- fillImageRect.anchorMin = Vector2.zero;
- fillImageRect.anchorMax = Vector2.one;
- fillImageRect.sizeDelta = Vector2.zero;
-
- Image fillImage = fill.AddComponent<Image>();
- 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<RectTransform>();
- textRect.anchorMin = Vector2.zero;
- textRect.anchorMax = Vector2.one;
- textRect.sizeDelta = Vector2.zero;
-
- healthText = healthTextObj.AddComponent<Text>();
- healthText.text = $"{currentHealth}/{GetMaxHealth()}";
- healthText.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
- healthText.fontSize = 18;
- healthText.alignment = TextAnchor.MiddleCenter;
- healthText.color = Color.white;
-
- CreateLevelUI();
- }
-
- void CreateLevelUI()
- {
- Canvas canvas = FindObjectOfType<Canvas>();
- if (canvas == null) return;
-
- GameObject levelPanel = new GameObject("LevelPanel");
- levelPanel.transform.SetParent(canvas.transform, false);
- RectTransform levelPanelRect = levelPanel.AddComponent<RectTransform>();
- 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<Image>();
- panelBg.color = new Color(0, 0, 0, 0.5f);
-
- GameObject levelTextObj = new GameObject("LevelText");
- levelTextObj.transform.SetParent(levelPanel.transform, false);
- RectTransform levelTextRect = levelTextObj.AddComponent<RectTransform>();
- levelTextRect.anchorMin = new Vector2(0, 0.5f);
- levelTextRect.anchorMax = new Vector2(0.5f, 1);
- levelTextRect.sizeDelta = Vector2.zero;
-
- levelText = levelTextObj.AddComponent<Text>();
- levelText.text = $"Lv.{playerLevel}";
- levelText.font = Resources.GetBuiltinResource<Font>("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<RectTransform>();
- expTextRect.anchorMin = new Vector2(0, 0);
- expTextRect.anchorMax = new Vector2(1, 0.5f);
- expTextRect.sizeDelta = Vector2.zero;
-
- expText = expTextObj.AddComponent<Text>();
- expText.text = $"EXP: {currentExperience}/{GetExperienceToNextLevel()}";
- expText.font = Resources.GetBuiltinResource<Font>("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<RectTransform>();
- attackTextRect.anchorMin = new Vector2(0.5f, 0.5f);
- attackTextRect.anchorMax = new Vector2(1, 1);
- attackTextRect.sizeDelta = Vector2.zero;
-
- attackText = attackTextObj.AddComponent<Text>();
- attackText.text = $"ATK:{attackPower}";
- attackText.font = Resources.GetBuiltinResource<Font>("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<Canvas>();
- if (canvas == null) return;
-
- gameOverPanel = new GameObject("GameOverPanel");
- gameOverPanel.transform.SetParent(canvas.transform, false);
- RectTransform panelRect = gameOverPanel.AddComponent<RectTransform>();
- panelRect.anchorMin = Vector2.zero;
- panelRect.anchorMax = Vector2.one;
- panelRect.sizeDelta = Vector2.zero;
-
- Image panelImage = gameOverPanel.AddComponent<Image>();
- 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<RectTransform>();
- 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<Text>();
- 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<Font>("LegacyRuntime.ttf");
- gameOverText.fontSize = 28;
- gameOverText.alignment = TextAnchor.MiddleCenter;
-
- Button restartButton = gameOverPanel.AddComponent<Button>();
- restartButton.onClick.AddListener(RestartGame);
- }
-
- void RestartGame()
- {
- Time.timeScale = 1f;
- UnityEngine.SceneManagement.SceneManager.LoadScene(menuSceneName);
- }
-
- void Create2DMap()
- {
- if (mapContent == null)
- {
- Debug.LogError("Map Content未创建!");
- return;
- }
-
- roomToButtonMap.Clear();
- roomButtons.Clear();
-
- for (int col = 0; col < mapConfig.roomBlueprints.Count; col++)
- {
- if (!columnGroups.ContainsKey(col)) continue;
-
- GameObject columnHeader = new GameObject($"Column_{col}_Header");
- columnHeader.transform.SetParent(mapContent.transform, false);
- RectTransform headerRect = columnHeader.AddComponent<RectTransform>();
- headerRect.sizeDelta = new Vector2(0, 30);
-
- Text headerText = columnHeader.AddComponent<Text>();
- headerText.text = $"第{col + 1}关";
- headerText.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
- headerText.fontSize = 18;
- headerText.fontStyle = FontStyle.Bold;
- headerText.alignment = TextAnchor.MiddleCenter;
- headerText.color = Color.white;
-
- foreach (GameObject room in columnGroups[col])
- {
- CreateRoomButton(room, col);
- }
-
- if (col < mapConfig.roomBlueprints.Count - 1)
- {
- GameObject separator = new GameObject("Separator");
- separator.transform.SetParent(mapContent.transform, false);
- RectTransform sepRect = separator.AddComponent<RectTransform>();
- sepRect.sizeDelta = new Vector2(0, 2);
-
- Image sepImage = separator.AddComponent<Image>();
- sepImage.color = new Color(0.5f, 0.5f, 0.5f, 0.5f);
- }
- }
-
- UpdateRoomButtonsState();
- }
-
- void CreateRoomButton(GameObject room, int columnIndex)
- {
- GameObject buttonObj;
-
- if (roomButtonPrefab != null)
- {
- buttonObj = Instantiate(roomButtonPrefab, mapContent.transform);
- }
- else
- {
- buttonObj = new GameObject($"RoomButton_{room.name}");
- buttonObj.transform.SetParent(mapContent.transform, false);
-
- RectTransform btnRect = buttonObj.AddComponent<RectTransform>();
- btnRect.sizeDelta = new Vector2(0, 50);
-
- Image btnImage = buttonObj.AddComponent<Image>();
- btnImage.color = new Color(0.3f, 0.6f, 0.3f);
-
- Button button = buttonObj.AddComponent<Button>();
- button.targetGraphic = btnImage;
-
- GameObject textObj = new GameObject("Text");
- textObj.transform.SetParent(buttonObj.transform, false);
- RectTransform textRect = textObj.AddComponent<RectTransform>();
- textRect.anchorMin = Vector2.zero;
- textRect.anchorMax = Vector2.one;
- textRect.sizeDelta = Vector2.zero;
-
- Text text = textObj.AddComponent<Text>();
- text.text = $"房间 {columnIndex + 1}-{room.name.Split('_')[2]}";
- text.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
- text.fontSize = 14;
- text.alignment = TextAnchor.MiddleCenter;
- text.color = Color.white;
- }
-
- MapRoomButton roomButton = buttonObj.GetComponent<MapRoomButton>();
- if (roomButton == null)
- {
- roomButton = buttonObj.AddComponent<MapRoomButton>();
- }
-
- roomButton.Initialize(room, this, columnIndex);
-
- roomToButtonMap[room] = roomButton;
- roomButtons.Add(roomButton);
- }
-
- private int GetRoomColumnIndex(GameObject room)
- {
- string[] nameParts = room.name.Split('_');
- if (nameParts.Length >= 2)
- {
- int columnIndex;
- if (int.TryParse(nameParts[1], out columnIndex))
- {
- return columnIndex;
- }
- }
- return -1;
- }
-
- // =========================
- // 更新房间按钮状态(只允许向前移动)
- // =========================
- public void UpdateRoomButtonsState()
- {
- if (player == null) return;
-
- // 更新玩家当前所在的房间
- UpdateCurrentPlayerRoom();
-
- // 获取从当前房间可到达的房间列表(只向前)
- HashSet<GameObject> reachableRooms = GetForwardReachableRoomsFromCurrent();
-
- foreach (var button in roomButtons)
- {
- if (button.room == null) continue;
-
- float distance = Vector3.Distance(player.position, button.room.transform.position);
-
- GameObject trigger = triggers.Find(t =>
- t.GetComponent<RoomTrigger>()?.GetRoom() == button.room);
-
- bool isTriggerActive = trigger != null;
- bool isCompleted = completedRooms.Contains(button.room);
- bool isAttempted = attemptedRooms.Contains(button.room);
-
- int roomColumn = button.columnIndex;
- bool isCurrentRoom = (currentPlayerRoom == button.room);
-
- // 判断是否可以传送
- bool canTeleport = !isAnsweringQuestion && !isMoving && !isCompleted && isTriggerActive &&
- (isCurrentRoom || reachableRooms.Contains(button.room));
-
- // 额外检查:不能传送到当前列或之前的房间(当前房间除外)
- if (currentPlayerRoom != null && !isCurrentRoom)
- {
- int currentColumn = GetRoomColumnIndex(currentPlayerRoom);
- if (roomColumn <= currentColumn)
- {
- canTeleport = false;
- }
- }
-
- // 更新按钮状态
- button.UpdateState(distance, isTriggerActive, isCompleted, isAttempted, canTeleport, isCurrentRoom);
- }
-
- UpdateColumnHeaders();
- }
-
- // =========================
- // 更新玩家当前所在的房间
- // =========================
- private void UpdateCurrentPlayerRoom()
- {
- if (player == null) return;
-
- if (isAtRootNode)
- {
- return;
- }
-
- GameObject closestRoom = null;
- float minDistance = float.MaxValue;
-
- foreach (var room in rooms)
- {
- float distance = Vector3.Distance(player.position, room.transform.position);
- if (distance < minDistance)
- {
- minDistance = distance;
- closestRoom = room;
- }
- }
-
- // 如果玩家距离房间足够近(5个单位内),则认为玩家在这个房间
- if (closestRoom != null && minDistance < 5f)
- {
- if (currentPlayerRoom != closestRoom)
- {
- currentPlayerRoom = closestRoom;
- Debug.Log($"玩家进入房间: {currentPlayerRoom.name}");
- }
- }
- }
-
- // =========================
- // 核心方法:获取从当前房间可向前到达的房间
- // 使用BFS探索所有连接,但只允许向列索引更大的方向移动
- // =========================
- private HashSet<GameObject> GetForwardReachableRoomsFromCurrent()
- {
- HashSet<GameObject> reachable = new HashSet<GameObject>();
-
- if (currentPlayerRoom == null)
- {
- // 初始状态,只能进入第一列第一个房间
- if (columnGroups.ContainsKey(0) && columnGroups[0].Count > 0)
- {
- reachable.Add(columnGroups[0][0]);
- }
- return reachable;
- }
-
- int currentColumn = GetRoomColumnIndex(currentPlayerRoom);
-
- // 使用BFS查找所有可到达的未完成房间
- // 关键:探索所有连接,但在添加到可达列表时只添加列索引大于等于当前列的房间
- Queue<GameObject> queue = new Queue<GameObject>();
- HashSet<GameObject> visited = new HashSet<GameObject>();
-
- queue.Enqueue(currentPlayerRoom);
- visited.Add(currentPlayerRoom);
-
- while (queue.Count > 0)
- {
- GameObject current = queue.Dequeue();
- int currentCol = GetRoomColumnIndex(current);
-
- // 获取当前房间的所有连接
- if (allConnections.ContainsKey(current))
- {
- foreach (GameObject nextRoom in allConnections[current])
- {
- if (!visited.Contains(nextRoom))
- {
- visited.Add(nextRoom);
- int nextCol = GetRoomColumnIndex(nextRoom);
-
- // 如果房间未完成,并且列索引大于当前玩家所在列,添加到可达列表
- if (!completedRooms.Contains(nextRoom))
- {
- // 只允许向前移动:目标列索引 > 玩家当前所在列
- if (nextCol > currentColumn)
- {
- reachable.Add(nextRoom);
- }
- }
-
- // 如果房间已完成或已尝试,可以继续探索其所有连接
- if (completedRooms.Contains(nextRoom) || attemptedRooms.Contains(nextRoom))
- {
- queue.Enqueue(nextRoom);
- }
- }
- }
- }
- }
-
- return reachable;
- }
-
- // =========================
- // 获取玩家当前所在列
- // =========================
- private int GetPlayerCurrentColumn()
- {
- if (currentPlayerRoom != null)
- {
- return GetRoomColumnIndex(currentPlayerRoom);
- }
- return -1;
- }
-
- // =========================
- // 判断是否可以传送
- // =========================
- private bool CanTeleportToRoom(GameObject room)
- {
- if (isAnsweringQuestion) return false;
- if (isMoving) return false;
- if (completedRooms.Contains(room)) return false;
-
- // 检查触发器是否存在
- GameObject trigger = triggers.Find(t =>
- t.GetComponent<RoomTrigger>()?.GetRoom() == room);
- if (trigger == null) return false;
-
- // 如果是当前房间,可以传送
- if (currentPlayerRoom == room) return true;
-
- // 检查列索引:不能传送到当前列或之前的房间(当前房间除外)
- if (currentPlayerRoom != null)
- {
- int currentColumn = GetRoomColumnIndex(currentPlayerRoom);
- int targetColumn = GetRoomColumnIndex(room);
-
- if (targetColumn <= currentColumn)
- {
- return false; // 不能后退或停留在同一列
- }
- }
-
- // 检查是否在可达房间列表中
- HashSet<GameObject> reachable = GetForwardReachableRoomsFromCurrent();
- return reachable.Contains(room);
- }
-
- private void UpdateColumnHeaders()
- {
- int playerColumn = GetPlayerCurrentColumn();
-
- for (int i = 0; i < mapContent.transform.childCount; i++)
- {
- Transform child = mapContent.transform.GetChild(i);
- if (child.name.StartsWith("Column_") && child.name.EndsWith("_Header"))
- {
- Text headerText = child.GetComponent<Text>();
- if (headerText != null)
- {
- string[] parts = child.name.Split('_');
- if (parts.Length >= 2)
- {
- int colIndex;
- if (int.TryParse(parts[1], out colIndex))
- {
- headerText.color = colIndex == playerColumn ? Color.yellow : Color.white;
- }
- }
- }
- }
- }
- }
-
- // =========================
- // 传送逻辑
- // =========================
- public void TeleportToRoom(GameObject room)
- {
- if (player == null)
- {
- Debug.LogError("Player未设置!");
- return;
- }
-
- if (isAnsweringQuestion)
- {
- Debug.LogWarning("正在答题中,无法移动!");
- return;
- }
-
- if (isMoving)
- {
- Debug.LogWarning("正在移动中,无法切换目标!");
- return;
- }
-
- if (!CanTeleportToRoom(room))
- {
- Debug.LogWarning($"无法移动到房间 {room.name}!只能向前移动到已连接且未完成的房间。");
- return;
- }
-
- targetRoom = room;
- targetPosition = new Vector3(room.transform.position.x, 0.6f, room.transform.position.z);
- isMoving = true;
-
- Debug.Log($"开始移动到房间: {room.name}");
-
- UpdateRoomButtonsState();
- }
-
- void SelectRandomQuestion(RoonType roomType)
- {
- int targetDifficulty = GetDifficultyByRoomType(roomType);
-
- currentOnlineQuestion = null;
- currentQuestion = null;
- currentQuestionId = -1;
-
- bool isLoggedInUser = LoginManager.Instance != null && !LoginManager.Instance.IsGuest();
- bool isReviewMode = GameModeManager.Instance != null && GameModeManager.Instance.IsReviewMode();
- if (isLoggedInUser && onlineQuestions.Count > 0)
- {
- SelectOnlineQuestion(targetDifficulty);
- }
- else if (isLoggedInUser && isReviewMode)
- {
- if (!onlineQuestionsLoadStarted)
- {
- Debug.LogError("复习模式需要接口题目,但题目加载尚未开始。");
- }
- else if (!onlineQuestionsLoadFinished)
- {
- Debug.LogWarning("复习题目仍在加载,请等待接口请求完成。");
- }
- else
- {
- Debug.LogError($"复习模式没有可用的接口题目。{onlineQuestionsLoadError}");
- }
- }
- else
- {
- SelectLocalQuestion(targetDifficulty);
- }
- }
-
- void SelectOnlineQuestion(int targetDifficulty)
- {
- if (onlineQuestions == null || onlineQuestions.Count == 0)
- {
- Debug.LogError("没有可用的在线题目!");
- return;
- }
-
- List<QuestionData> availableQuestions = onlineQuestions.FindAll(q =>
- q.difficulty == targetDifficulty);
-
- if (availableQuestions.Count == 0)
- {
- Debug.LogWarning($"没有找到难度 {targetDifficulty} 的在线题目,使用所有题目");
- availableQuestions = onlineQuestions;
- }
-
- int randomIndex = Random.Range(0, availableQuestions.Count);
- currentOnlineQuestion = availableQuestions[randomIndex];
- currentQuestionId = currentOnlineQuestion.questionId;
-
- currentQuestion = ScriptableObject.CreateInstance<MathQuestionSO>();
- currentQuestion.questionText = currentOnlineQuestion.questionText;
- currentQuestion.correctAnswer = currentOnlineQuestion.correctAnswer;
- currentQuestion.wrongAnswers = new List<int>(currentOnlineQuestion.wrongAnswers);
- currentQuestion.difficulty = currentOnlineQuestion.difficulty;
- }
-
- void SelectLocalQuestion(int targetDifficulty)
- {
- if (allQuestions == null || allQuestions.Count == 0)
- {
- Debug.LogError("没有可用的题目!请在Inspector中添加MathQuestionSO资源。");
- return;
- }
- List<MathQuestionSO> availableQuestions = allQuestions.FindAll(q =>
- q.difficulty == targetDifficulty);
-
- if (availableQuestions.Count == 0)
- {
- Debug.LogWarning($"没有找到难度 {targetDifficulty} 的题目,使用所有题目");
- availableQuestions = allQuestions;
- }
- int randomIndex = Random.Range(0, availableQuestions.Count);
- currentQuestion = availableQuestions[randomIndex];
- currentQuestionId = -1;
- }
-
- //
- int GetDifficultyByRoomType(RoonType roomType)
- {
- return roomType switch
- {
- RoonType.MinorEnemy => 1,
- RoonType.EliteEnemy => 2,
- RoonType.Boss => 3,
- _ => 1
- };
- }
-
- int GetGoldRewardByRoomType(RoonType roomType)
- {
- return roomType switch
- {
- RoonType.MinorEnemy => 10,
- RoonType.EliteEnemy => 30,
- RoonType.Boss => 100,
- _ => 10
- };
- }
-
- int GetExperienceRewardByRoomType(RoonType roomType)
- {
- return roomType switch
- {
- RoonType.MinorEnemy => 20,
- RoonType.EliteEnemy => 50,
- RoonType.Boss => 200,
- _ => 20
- };
- }
- public void OnPlayerEnterRoom(GameObject room)
- {
- if (currentTriggerRoom != null) return;
- if (currentHealth <= 0) return;
-
- if (attemptedRooms.Contains(room))
- {
- Debug.Log("这个房间已经尝试过了!");
- return;
- }
-
- currentTriggerRoom = room;
-
- RoomInfo roomInfo = room.GetComponent<RoomInfo>();
- if (roomInfo == null)
- {
- Debug.LogError("房间没有RoomInfo组件!");
- return;
- }
-
- switch (roomInfo.roomType)
- {
- case RoonType.MinorEnemy:
- case RoonType.EliteEnemy:
- case RoonType.Boss:
- StartBattle(room);
- break;
- case RoonType.RestRoom:
- Rest(room);
- break;
- }
-
- UpdateRoomButtonsState();
- }
-
- void StartBattle(GameObject room)
- {
- RoomInfo roomInfo = room.GetComponent<RoomInfo>();
- if (roomInfo == null) return;
-
- currentBattleRoomType = roomInfo.roomType;
-
- monsterMaxHealth = GetMonsterHealthByRoomType(currentBattleRoomType);
- monsterCurrentHealth = monsterMaxHealth;
-
- isInBattle = true;
- isAnsweringQuestion = true;
-
- SetMonsterIcon(currentBattleRoomType);
-
- if (battlePanel != null)
- {
- battlePanel.SetActive(true);
- UpdateBattleUI();
- }
-
- UpdatePlayerBattleHealthUI();
-
- ShowNextQuestion();
-
- Debug.Log($"开始战斗!怪物类型:{currentBattleRoomType},怪物血量:{monsterMaxHealth}");
- }
-
- void SetMonsterIcon(RoonType roomType)
- {
- if (monsterIcon == null) return;
-
- Sprite iconToUse = roomType switch
- {
- RoonType.MinorEnemy => minorEnemyIcon,
- RoonType.EliteEnemy => eliteEnemyIcon,
- RoonType.Boss => bossIcon,
- _ => minorEnemyIcon
- };
-
- if (iconToUse != null)
- {
- monsterIcon.sprite = iconToUse;
- }
-
- if (playerIcon != null && playerBattleIcon != null)
- {
- playerIcon.sprite = playerBattleIcon;
- }
- }
-
- void UpdatePlayerBattleHealthUI()
- {
- if (playerBattleHealthSlider != null)
- {
- playerBattleHealthSlider.maxValue = GetMaxHealth();
- playerBattleHealthSlider.value = currentHealth;
- }
-
- if (playerBattleHealthText != null)
- {
- playerBattleHealthText.text = $"玩家血量: {currentHealth}/{GetMaxHealth()}";
- }
- }
-
- int GetMonsterHealthByRoomType(RoonType roomType)
- {
- return roomType switch
- {
- RoonType.MinorEnemy => 3,
- RoonType.EliteEnemy => 5,
- RoonType.Boss => 10,
- _ => 3
- };
- }
-
- void UpdateBattleUI()
- {
- if (monsterHealthSlider != null)
- {
- monsterHealthSlider.maxValue = monsterMaxHealth;
- monsterHealthSlider.value = monsterCurrentHealth;
- }
-
- if (monsterHealthText != null)
- {
- monsterHealthText.text = $"怪物血量: {monsterCurrentHealth}/{monsterMaxHealth}";
- }
-
- if (battleStatusText != null)
- {
- string roomTypeName = currentBattleRoomType switch
- {
- RoonType.MinorEnemy => "普通怪物",
- RoonType.EliteEnemy => "精英怪物",
- RoonType.Boss => "Boss",
- _ => "怪物"
- };
- battleStatusText.text = $"战斗中 - {roomTypeName}";
- }
- }
-
- void ShowNextQuestion()
- {
- SelectRandomQuestion(currentBattleRoomType);
-
- if (currentQuestion == null)
- {
- Debug.LogError("无法获取题目!");
- EndBattle(false);
- return;
- }
-
- if (hasHint)
- {
- UseHint();
- }
-
- ShowQuestionUI();
- }
-
- void EndBattle(bool playerWon)
- {
- isInBattle = false;
- isAnsweringQuestion = false;
-
- if (battlePanel != null)
- {
- battlePanel.SetActive(false);
- }
-
- if (playerWon)
- {
- Debug.Log("战斗胜利!");
- totalRoomsCompleted++;
- UpdateAchievementProgress(AchievementType.CompleteRooms, 1);
-
- int expReward = GetExperienceRewardByRoomType(currentBattleRoomType);
- AddExperience(expReward);
-
- if (currentBattleRoomType == RoonType.Boss)
- {
- isGameCompleted = true;
- Victory();
- }
-
- if (currentTriggerRoom != null)
- {
- completedRooms.Add(currentTriggerRoom);
- attemptedRooms.Add(currentTriggerRoom);
-
- int goldReward = GetGoldRewardByRoomType(currentBattleRoomType);
- AddGold(goldReward);
-
- if (doubleGoldTurns > 0)
- {
- doubleGoldTurns--;
- Debug.Log($"金币翻倍剩余回合:{doubleGoldTurns}");
- }
-
- GameObject triggerToDestroy = triggers.Find(t =>
- t.GetComponent<RoomTrigger>()?.GetRoom() == currentTriggerRoom);
- if (triggerToDestroy != null)
- {
- triggers.Remove(triggerToDestroy);
- Destroy(triggerToDestroy);
- }
- }
- }
- else
- {
- Debug.Log("战斗失败!游戏结束!");
- GameOver();
- }
-
- currentTriggerRoom = null;
- currentQuestion = null;
- UpdateRoomButtonsState();
- }
-
- void Rest(GameObject room)
- {
- Debug.Log("休息室!");
-
- HealPlayer(1);
-
- completedRooms.Add(room);
- attemptedRooms.Add(room);
- totalRoomsCompleted++;
- UpdateAchievementProgress(AchievementType.CompleteRooms, 1);
- currentTriggerRoom = null;
-
- Debug.Log($"休息恢复 1 点生命!当前生命: {currentHealth}/{GetMaxHealth()}");
- }
- void ShowQuestionUI()
- {
- if (questionPanel == null)
- {
- Debug.LogError("Question Panel is not assigned!");
- return;
- }
-
- if (currentQuestion == null)
- {
- Debug.LogError("当前题目为空!");
- return;
- }
-
- questionPanel.SetActive(true);
-
- if (questionText != null)
- {
- questionText.text = currentQuestion.questionText;
- }
-
- List<int> allAnswers = new List<int>(currentQuestion.wrongAnswers);
- allAnswers.Add(currentQuestion.correctAnswer);
-
- if (currentQuestion.wrongAnswers.Count != 3)
- {
- Debug.LogWarning($"题目 '{currentQuestion.questionText}' 的错误答案数量不是3个,当前为{currentQuestion.wrongAnswers.Count}个");
- }
-
- for (int i = 0; i < allAnswers.Count; i++)
- {
- int randomIndex = Random.Range(i, allAnswers.Count);
- int temp = allAnswers[i];
- allAnswers[i] = allAnswers[randomIndex];
- allAnswers[randomIndex] = temp;
- }
-
- for (int i = 0; i < answerButtons.Length && i < allAnswers.Count; i++)
- {
- int answer = allAnswers[i];
- answerButtons[i].gameObject.SetActive(true);
- answerButtons[i].GetComponentInChildren<Text>().text = answer.ToString();
-
- answerButtons[i].onClick.RemoveAllListeners();
- answerButtons[i].onClick.AddListener(() => OnAnswerSelected(answer));
- }
-
- Debug.Log($"显示题目: {currentQuestion.questionText}, 题目ID: {currentQuestionId}");
- }
- void OnAnswerSelected(int selectedAnswer)
- {
- StartCoroutine(OnAnswerSelectedWithAnimation(selectedAnswer));
- }
- GameObject CreateBullet(Vector2 startPos)
- {
- GameObject bullet = new GameObject("Bullet");
- Image bulletImage = bullet.AddComponent<Image>();
-
- Texture2D bulletTexture = new Texture2D(1, 1);
- bulletTexture.SetPixel(0, 0, bulletColor);
- bulletTexture.Apply();
-
- Sprite bulletSprite = Sprite.Create(bulletTexture, new Rect(0, 0, 1, 1), new Vector2(0.5f, 0.5f));
- bulletImage.sprite = bulletSprite;
- bulletImage.color = bulletColor;
-
- RectTransform rectTransform = bullet.GetComponent<RectTransform>();
- rectTransform.sizeDelta = new Vector2(bulletSize, bulletSize);
- rectTransform.anchoredPosition = startPos;
-
- if (battlePanel != null)
- {
- bullet.transform.SetParent(battlePanel.transform, false);
- }
-
- return bullet;
- }
- IEnumerator PlayAttackAnimation(bool playerAttacking)
- {
- if (playerIcon == null || monsterIcon == null)
- {
- yield break;
- }
- RectTransform attackerRect = playerAttacking ? playerIcon.rectTransform : monsterIcon.rectTransform;
- RectTransform targetRect = playerAttacking ? monsterIcon.rectTransform : playerIcon.rectTransform;
-
- Vector2 attackerOriginalPos = attackerRect.anchoredPosition;
- Vector2 targetOriginalPos = targetRect.anchoredPosition;
-
- Vector2 direction = (targetOriginalPos - attackerOriginalPos).normalized;
-
- float elapsed = 0f;
- while (elapsed < attackDuration)
- {
- elapsed += Time.deltaTime;
- float progress = elapsed / attackDuration;
- float curve = Mathf.Sin(progress * Mathf.PI);
- Vector2 offset = direction * (attackMoveDistance * curve);
- attackerRect.anchoredPosition = attackerOriginalPos + offset;
- yield return null;
- }
- attackerRect.anchoredPosition = attackerOriginalPos;
-
- GameObject bullet = CreateBullet(attackerOriginalPos);
- RectTransform bulletRect = bullet.GetComponent<RectTransform>();
-
- elapsed = 0f;
- while (elapsed < bulletDuration)
- {
- elapsed += Time.deltaTime;
- float progress = elapsed / bulletDuration;
- bulletRect.anchoredPosition = Vector2.Lerp(attackerOriginalPos, targetOriginalPos, progress);
- yield return null;
- }
-
- Destroy(bullet);
-
- elapsed = 0f;
- Vector3 originalRotation = Vector3.zero;
- while (elapsed < shakeDuration)
- {
- elapsed += Time.deltaTime;
- float progress = elapsed / shakeDuration;
- float decay = 1f - progress;
- float offsetX = Mathf.Sin(elapsed * 30f) * shakeIntensity * decay;
- targetRect.anchoredPosition = targetOriginalPos + new Vector2(offsetX, 0);
- yield return null;
- }
- targetRect.anchoredPosition = targetOriginalPos;
- }
- IEnumerator OnAnswerSelectedWithAnimation(int selectedAnswer)
- {
- bool isCorrect = (selectedAnswer == currentQuestion.correctAnswer);
-
- ReportQuestionStatsToServer(isCorrect);
-
- if (isCorrect)
- {
- correctAnswerCount++;
- UpdateAchievementProgress(AchievementType.AnswerCorrect, 1);
- Debug.Log($"回答正确!题目:{currentQuestion.questionText} 答案:{currentQuestion.correctAnswer}");
-
- if (isInBattle)
- {
- yield return StartCoroutine(PlayAttackAnimation(true));
-
- monsterCurrentHealth -= attackPower;
- UpdateBattleUI();
-
- Debug.Log($"怪物受到{attackPower}点伤害!剩余血量:{monsterCurrentHealth}/{monsterMaxHealth}");
-
- if (monsterCurrentHealth <= 0)
- {
- questionPanel.SetActive(false);
- EndBattle(true);
- yield break;
- }
- }
- }
- else
- {
- wrongAnswerCount++;
- Debug.Log($"回答错误!题目:{currentQuestion.questionText} 正确答案是:{currentQuestion.correctAnswer},你选择了:{selectedAnswer}");
-
- if (isInBattle)
- {
- yield return StartCoroutine(PlayAttackAnimation(false));
- }
-
- TakeDamage(1);
-
- if (currentHealth <= 0)
- {
- questionPanel.SetActive(false);
- if (isInBattle)
- {
- EndBattle(false);
- }
- else
- {
- isAnsweringQuestion = false;
- currentTriggerRoom = null;
- currentQuestion = null;
- }
- yield break;
- }
- }
-
- if (isInBattle)
- {
- ShowNextQuestion();
- }
- else
- {
- questionPanel.SetActive(false);
- isAnsweringQuestion = false;
- currentTriggerRoom = null;
- currentQuestion = null;
- UpdateRoomButtonsState();
- }
- }
-
- void ReportQuestionStatsToServer(bool isCorrect)
- {
- if (LoginManager.Instance == null || LoginManager.Instance.IsGuest())
- {
- return;
- }
-
- if (NetworkManager.Instance == null)
- {
- return;
- }
-
- if (currentQuestionId <= 0)
- {
- return;
- }
-
- NetworkManager.Instance.ReportQuestionStats(
- currentQuestionId,
- isCorrect,
- currentQuestion.difficulty,
- response =>
- {
- if (response.success)
- {
- Debug.Log($"题目统计上报成功!ID: {currentQuestionId}, 正确: {isCorrect}");
- }
- },
- error =>
- {
- Debug.LogWarning($"题目统计上报失败: {error}");
- }
- );
-
- AddQuestionToReviewPool();
- }
-
- void AddQuestionToReviewPool()
- {
- if (LoginManager.Instance == null || LoginManager.Instance.IsGuest())
- {
- return;
- }
-
- if (NetworkManager.Instance == null)
- {
- return;
- }
-
- if (currentQuestionId <= 0)
- {
- return;
- }
-
- bool isReviewMode = GameModeManager.Instance != null && GameModeManager.Instance.IsReviewMode();
-
- if (isReviewMode)
- {
- return;
- }
-
- NetworkManager.Instance.AddQuestionToReview(
- currentQuestionId,
- response =>
- {
- if (response.success)
- {
- Debug.Log($"题目已添加到复习题库!ID: {currentQuestionId}");
- }
- },
- error =>
- {
- Debug.LogWarning($"添加题目到复习题库失败: {error}");
- }
- );
- }
- // =========================
- // 创建连接时记录所有连接关系(双向记录)
- // =========================
- void CreateConnections(List<GameObject> col1, List<GameObject> col2)
- {
- HashSet<GameObject> connected = new();
- foreach (var r in col1)
- {
- var target = Connect(r, col2);
- connected.Add(target);
-
- // 记录双向连接
- allConnections[r].Add(target);
- allConnections[target].Add(r);
- }
- foreach (var r in col2)
- {
- if (!connected.Contains(r))
- {
- var source = Connect(r, col1);
-
- // 记录双向连接
- allConnections[r].Add(source);
- allConnections[source].Add(r);
- }
- }
- }
- GameObject Connect(GameObject a, List<GameObject> targets)
- {
- GameObject b = targets[Random.Range(0, targets.Count)];
- GameObject path = CreateBridge(a.transform.position, b.transform.position);
- paths.Add(path);
- return b;
- }
- GameObject CreateBridge(Vector3 start, Vector3 end)
- {
- GameObject bridge = GameObject.CreatePrimitive(PrimitiveType.Cube);
- bridge.name = "Path";
- Vector3 dir = end - start;
- float length = dir.magnitude;
- bridge.transform.position = (start + end) / 2f;
- bridge.transform.rotation = Quaternion.LookRotation(dir);
- bridge.transform.localScale = new Vector3(pathWidth, pathWidth, length);
- Renderer r = bridge.GetComponent<Renderer>();
- r.material = new Material(Shader.Find("Universal Render Pipeline/Lit"));
- r.material.color = pathColor;
- return bridge;
- }
- [ContextMenu("ReGenerate")]
- public void ReGenerate()
- {
- ChooseMap();
- foreach (var r in rooms) Destroy(r);
- foreach (var p in paths) Destroy(p);
- foreach (var t in triggers) Destroy(t);
- rooms.Clear();
- paths.Clear();
- triggers.Clear();
- completedRooms.Clear();
- attemptedRooms.Clear();
- allConnections.Clear();
- currentMaxColumn = 0;
- currentPlayerRoom = null;
- isAtRootNode = true;
-
- currentHealth = 10;
- currentGold = 0;
- shield = 0;
- hasHint = false;
- doubleGoldTurns = 0;
- inventory.Clear();
- isInBattle = false;
- isAnsweringQuestion = false;
- isMoving = false;
- targetRoom = null;
-
- if (battlePanel != null)
- battlePanel.SetActive(false);
-
- UpdateHealthUI();
- UpdateGoldUI();
-
- if (mapContent != null)
- {
- foreach (Transform child in mapContent.transform)
- {
- Destroy(child.gameObject);
- }
- }
- roomButtons.Clear();
- roomToButtonMap.Clear();
- columnGroups.Clear();
- CreateMap();
- Create2DMap();
- FindInitialPlayerRoom();
- }
-
- private void Update()
- {
- if (Time.frameCount % 30 == 0)
- {
- UpdateRoomButtonsState();
- }
-
- if (isMoving && player != null)
- {
- float distance = Vector3.Distance(player.position, targetPosition);
-
- if (distance <= stopDistance)
- {
- isMoving = false;
-
- if (isAtRootNode)
- {
- isAtRootNode = false;
- Debug.Log("离开根节点,进入第一关");
- }
-
- Debug.Log($"已到达目标房间!");
-
- if (targetRoom != null)
- {
- currentPlayerRoom = targetRoom;
- OnPlayerEnterRoom(targetRoom);
- targetRoom = null;
- }
-
- UpdateRoomButtonsState();
- }
- }
- }
-
- private void FixedUpdate()
- {
- if (!isMoving || player == null)
- return;
-
- Vector3 currentPos = player.position;
- Vector3 targetPos = new Vector3(targetPosition.x, 0.6f, targetPosition.z);
-
- Vector3 direction = (targetPos - currentPos);
- direction.y = 0;
- direction = direction.normalized;
-
- float distance = Vector3.Distance(new Vector3(currentPos.x, 0, currentPos.z),
- new Vector3(targetPos.x, 0, targetPos.z));
-
- float currentSpeed = maxSpeed;
-
- if (distance <= arrivalDistance)
- {
- float slowdownFactor = distance / arrivalDistance;
- currentSpeed = maxSpeed * slowdownFactor;
- }
-
- Vector3 newPos = Vector3.MoveTowards(
- new Vector3(currentPos.x, 0.6f, currentPos.z),
- targetPos,
- currentSpeed * Time.fixedDeltaTime
- );
- newPos.y = 0.6f;
- player.position = newPos;
-
- if (direction != Vector3.zero)
- {
- Quaternion targetRotation = Quaternion.LookRotation(direction);
- player.rotation = Quaternion.Slerp(player.rotation, targetRotation, Time.fixedDeltaTime * 5f);
- }
- }
- }
- public class MapRoomButton : MonoBehaviour
- {
- public GameObject room { get; private set; }
- public int columnIndex { get; private set; }
- private MapGenerator3D mapGenerator;
- private Button button;
- private Image buttonImage;
- private Text buttonText;
-
- private Color lockedColor = new Color(0.3f, 0.3f, 0.3f);
- private Color availableColor = new Color(0.3f, 0.7f, 0.3f);
- private Color completedColor = new Color(0.2f, 0.5f, 0.8f);
- private Color attemptedColor = new Color(0.8f, 0.5f, 0.2f);
- private Color currentColor = new Color(1f, 0.8f, 0f);
- private Color unavailableColor = new Color(0.5f, 0.5f, 0.5f);
-
- public void Initialize(GameObject roomObj, MapGenerator3D generator, int colIndex)
- {
- this.room = roomObj;
- this.mapGenerator = generator;
- this.columnIndex = colIndex;
-
- button = GetComponent<Button>();
- buttonImage = GetComponent<Image>();
- buttonText = GetComponentInChildren<Text>();
-
- if (button != null)
- {
- button.onClick.AddListener(OnButtonClick);
- }
-
- if (buttonText != null)
- {
- string[] nameParts = room.name.Split('_');
- string roomTypeText = GetRoomTypeText(room);
-
- if (nameParts.Length >= 3)
- {
- buttonText.text = $"{roomTypeText}\n{int.Parse(nameParts[1]) + 1}-{int.Parse(nameParts[2]) + 1}";
- }
- else
- {
- buttonText.text = $"{roomTypeText}\n{room.name}";
- }
- }
- }
-
- string GetRoomTypeText(GameObject room)
- {
- RoomInfo roomInfo = room.GetComponent<RoomInfo>();
- if (roomInfo == null) return "普通";
-
- return roomInfo.roomType switch
- {
- RoonType.MinorEnemy => "普通",
- RoonType.EliteEnemy => "精英",
- RoonType.RestRoom => "休息",
- RoonType.Boss => "Boss",
- _ => "普通"
- };
- }
-
- public void UpdateState(float distanceToPlayer, bool isTriggerActive, bool isCompleted, bool isAttempted, bool canTeleport, bool isCurrentRoom)
- {
- if (buttonImage == null) return;
-
- if (buttonText != null)
- {
- buttonText.text = buttonText.text.Replace(" ✓", "").Replace(" ✗", "").Replace(" 🔒", "").Replace(" 📍", "");
- }
-
- if (isCompleted)
- {
- buttonImage.color = completedColor;
- button.interactable = false;
- if (buttonText != null)
- {
- buttonText.text += " ✓";
- }
- }
- else if (isAttempted && !isCompleted)
- {
- buttonImage.color = attemptedColor;
- button.interactable = false;
- if (buttonText != null)
- {
- buttonText.text += " ✗";
- }
- }
- else if (!canTeleport)
- {
- buttonImage.color = lockedColor;
- button.interactable = false;
- if (buttonText != null && !isCurrentRoom)
- {
- buttonText.text += " 🔒";
- }
- }
- else if (isCurrentRoom)
- {
- buttonImage.color = currentColor;
- button.interactable = true;
- if (buttonText != null)
- {
- buttonText.text += " 📍";
- }
- }
- else if (canTeleport && isTriggerActive)
- {
- buttonImage.color = availableColor;
- button.interactable = true;
- }
- else
- {
- buttonImage.color = unavailableColor;
- button.interactable = false;
- }
- }
-
- private void OnButtonClick()
- {
- if (room != null && mapGenerator != null)
- {
- mapGenerator.TeleportToRoom(room);
- }
- }
- }
- public class RoomTrigger : MonoBehaviour
- {
- private GameObject room;
- private MapGenerator3D mapGenerator;
-
- public void SetRoom(GameObject roomObj, MapGenerator3D generator)
- {
- room = roomObj;
- mapGenerator = generator;
- }
-
- public GameObject GetRoom()
- {
- return room;
- }
-
- private void OnTriggerEnter(Collider other)
- {
- if (other.CompareTag("Player"))
- {
- if (mapGenerator != null)
- {
- mapGenerator.OnPlayerEnterRoom(room);
- }
- }
- }
- }
|