using System; using System.Collections; using System.Collections.Generic; using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines; using Common; using DragonLi.Core; using Mirror; using UnityEngine; using UnityEngine.PlayerLoop; using XPlugin.Data.JsonLiteDB; using static XPlugin.Data.JsonLiteDB.JsonLiteDB; using LitJson; using Pathfinding; using DarkTonic.MasterAudio; using NaughtyAttributes; using UnityEngine.UIElements; using Random = UnityEngine.Random; /// /// 游戏状态 /// public enum GameState { None = 0, Playing = 1, /// /// 胜利 /// Victory = 2, /// /// 失败 /// Failur = 3, Settle=4, /// /// 准备阶段 /// Wave=5, } public class GameManager : NetworkBehaviour { public static GameManager Ins { get; private set; } #region 预制体 public GameObject DoorPre; public GameObject gunPropPre; public GameObject itemPropPre; // 炮塔预制体集合 //public GameObject[] TowerPres; // 怪物预制集合 public GameObject[] EnemyPres; public GameObject explosionPre; // 怪物ui预制体 public GameObject EnemyUIPre; #endregion // json数据库 private JsonLiteDB DB; // 怪物信息集合 public Dictionary EnemyInfos = new Dictionary(); // 炮塔信息集合 public Dictionary> TowerInfos = new Dictionary>(); // 枪械信息集合 public Dictionary GunInfos = new Dictionary(); // 子弹信息集合 public Dictionary BulletInfos = new Dictionary(); // 防线信息 public List DefenseInfos = new List(); // 剧情信息 public Dictionary CombatUnitInfos = new Dictionary(); private List curGunPropList = new List(); public Dictionary players = new Dictionary(); /// /// 敌人自增 /// private int enemyIndex = 0; /// /// 所有敌人 /// public Dictionary EnemyList = new Dictionary(); /// /// 所有敌人UI /// public Dictionary EnemyUIList = new Dictionary(); /// /// 炮塔自增 /// public int towerIndex = 0; /// /// 所有炮塔 /// public Dictionary TowerList = new Dictionary(); public Dictionary> TowerList2 = new Dictionary>(); public Dictionary SettleInfos = new Dictionary(); [SyncVar] public bool isStart; /// /// 波次自增 /// [SyncVar] public int roundIndex = 0; // 游玩结束时间 [NonSerialized] [SyncVar] public long vistEnd = 0; // 总游玩时长 private int vistAllTime = (int)(60*10 ); [SyncVar] public string settleData = ""; [SyncVar] public GameState gameState = GameState.None; [SoundGroup] public string JointIn; [SoundGroup] public string roundSound; public int roundWaveTime; public int curRoundWaveTime; void Awake() { Ins = this; } void Start() { if (isClient) { isStart = false; CreateDoor(); } } /// /// 创建门 /// public void CreateDoor() { UpdateConf(); if(!isServer) return; GameObject door = Instantiate(DoorPre); door.transform.position = GameLocal.Ins.doorPos.position.ReflectVectorXOZ(); NetworkServer.Spawn(door); } /// /// 创建初回合 /// public void CreateFirstRound() { RpcShowHUD(); roundIndex = 0; roundWaveTime = 15; curRoundWaveTime = 12; SetGameState(GameState.Wave); RpcMessageRound(); } /// /// 创建下一回合 /// public void CreateNextRound() { roundIndex++; SetGameState(GameState.Wave); roundWaveTime = 15; curRoundWaveTime = 12; RpcMessageRound(); } [Server] public void GameStart() { gameState = GameState.Playing; vistEnd = (long)(DateTime.Now.Subtract(new DateTime(1970, 1, 1))).TotalSeconds + vistAllTime; isStart = true; ChangeBgmRpc(1); // CreateTowers(); AstarPath.active.Scan(); // CreateFirstRound(); CreateFirstRound(); // 延迟1s后给所有人发放武器 CoroutineTaskManager.Instance.WaitSecondTodo(() => { GivePistol(); }, 1f); CoroutineTaskManager.Instance.WaitSecondTodo(() => { GameOver(GameState.Settle); }, 60f * 15f); } [ClientRpc] public void GivePistol() { Debug.Log("创建武器中..."); GameLocal.Ins.self.PickUpGun(GunType.Pistol, -999); } [Server] public void SetGameState(GameState state) { gameState = state; } //1.游戏时间到 //2.所有怪物被消灭 //3.玩家被消灭 //以上都要跳出结算 [Server] public void GameOver(GameState state) { RpcShow(); DamageAllEnemy(); gameState = state; isStart = false; // gameState = state; foreach (string key in SettleInfos.Keys) { string[] titles = { "初露锋芒", "小菜一碟", "熟手", "痛并快乐着", "不死传说" ,"最强守护者", "独孤求败", "佛系玩家", "午时已到", "神枪手", "弹无虚发", "团队护盾", "我叫MT", "钢铁之躯","道具大师","行走的仓库","永不停歇" }; SetTitle(key, titles[Random.Range(0, titles.Length)]); SetPlayerName(key); } string jsonStr = JsonMapper.ToJson(SettleInfos); settleData = jsonStr; // //结算页面 // RpcShow(); // if (blueScore >= redScore) // { // RpcShowWin(true); // } // else // { // RpcShowWin(false); // } } [ClientRpc] public void RpcShowWin(bool isBlue) { } [ClientRpc] public void RpcShow() { SettlePanel.Show(); } /// /// 下一波进攻开始 /// [Server] public void RpcMessageRound() { if(!isStart) return; CoroutineTaskManager.Instance.WaitSecondTodo(() => { if(!isStart) return; ShowHudRoundTime(); }, curRoundWaveTime); CoroutineTaskManager.Instance.WaitSecondTodo(() => { if(!isStart) return; DesGunProList(); GetRoundEnemy(); PlaySound2DRPC(roundSound); SetGameState(GameState.Playing); }, roundWaveTime); } [ClientRpc] public void ShowHudRoundTime() { DragonLi.Core.EventDispatcher.TriggerEvent("NewWaveStart", roundIndex); } [ClientRpc] public void ChangeBgmRpc(int i) { GameLocal.Ins.BGMState.StateChange(i); } public int curRoundEnemyCount; /// /// 创建敌方单位 /// IEnumerator CreateEnemy(CombatUnitInfo info) { curRoundEnemyCount = info.EnemyTypeList.Length; for (int i = 0; i < info.EnemyTypeList.Length; i++) { GameObject enemy = Instantiate(EnemyPres[info.EnemyTypeList[i]]); NetworkServer.Spawn(enemy); int posId = Random.Range(0, 4); int posX=Random.Range(-1, 1); int posZ=Random.Range(-1, 1); enemy.transform.position = GameLocal.Ins.enemyStartPos[posId].position+new Vector3(posX,0,posZ); enemy.transform.eulerAngles = new Vector3(0, 0, 0); enemyIndex++; Enemy enemyScript = enemy.GetComponent(); enemyScript.OnSpawn(enemyIndex, (EnemyType)info.EnemyTypeList[i], 1); EnemyList.Add(enemyIndex, enemyScript); yield return new WaitForSeconds(info.BornTime); } CloseWu(); } [ClientRpc] public void CloseWu() { GameLocal.Ins.CloseWu(); } public void CreateBoss() { GameObject enemy = Instantiate(EnemyPres[(int)EnemyType.ZombieBoss]); NetworkServer.Spawn(enemy); int posId = Random.Range(0, 4); int posX=Random.Range(-1, 1); int posZ=Random.Range(-1, 1); enemy.transform.position = GameLocal.Ins.enemyStartPos[posId].position+new Vector3(posX,0,posZ); enemy.transform.eulerAngles = new Vector3(0, 0, 0); enemyIndex++; Enemy enemyScript = enemy.GetComponent(); enemyScript.OnSpawn(enemyIndex, EnemyType.ZombieBoss, 1); EnemyList.Add(enemyIndex, enemyScript); curRoundEnemyCount++; } public void CreateExplosion(Transform pos) { if(!isServer) return; var ex= Instantiate(explosionPre, pos.position, Quaternion.identity); NetworkServer.Spawn(ex); ex.GetComponent().Init(0); } [SyncVar] public int gunProp1; [SyncVar] public int gunProp2; [Server] public void CreateGunProp() { if(!isStart) return; List numbers = new List() { 1, 2, 3, 4, 5 }; gunProp1 = numbers[Random.Range(0, numbers.Count)]; numbers.Remove(gunProp1); gunProp2 = numbers[Random.Range(0, numbers.Count)]; var gun1= Instantiate(gunPropPre, GameLocal.Ins.gunPropPos[0]); NetworkServer.Spawn(gun1); gun1.GetComponent().Init((GunType)gunProp1); curGunPropList.Add(gun1); var gun2= Instantiate(gunPropPre, GameLocal.Ins.gunPropPos[1]); NetworkServer.Spawn(gun2); gun2.GetComponent().Init((GunType)gunProp2); curGunPropList.Add(gun2); } public void CreateItemProp(Transform pos) { if(!isStart) return; var item= Instantiate(itemPropPre); NetworkServer.Spawn(item); item.transform.position=new Vector3(pos.position.x,0.5f,pos.position.z); item.GetComponent().SetItemProp(ItemPropType.Hp); } /// ///删除枪械 /// public void DesGunProList() { if(curGunPropList.Count<=0) return; NetworkServer.Destroy(curGunPropList[1]); NetworkServer.Destroy(curGunPropList[0]); curGunPropList.Clear(); } public List GetRoundEnemy() { List curEnemyList = new List(); if (roundIndex <= 6) { var combatUnitInfo= CombatUnitInfos[roundIndex]; StartCoroutine(CreateEnemy(combatUnitInfo)); } else { int curId = roundIndex; CombatUnitInfo info = new CombatUnitInfo(curId, curId, GenerateMonsterTypes(), 1); StartCoroutine(CreateEnemy(info)); } if (roundIndex % 5 == 0&&roundIndex!=0) { CreateBoss(); } return curEnemyList; } public int[] GenerateMonsterTypes() { int[] weights = { 2, 6, 1, 3 }; List monsterTypes = new List(); int totalWeight = 0; int targetWeight = Random.Range(24, 27); // 24-26 int targetCount = Random.Range(6, 10); // 4-7 // 随机添加怪物直到接近目标 while (monsterTypes.Count < targetCount && totalWeight < targetWeight) { int index = GetRandomMonsterIndex(weights); int weight = weights[index]; // 如果剩余位置不够,跳出 if (monsterTypes.Count == targetCount) break; // 如果加上这个怪物不会超过目标权重,添加 if (totalWeight + weight <= targetWeight) { monsterTypes.Add(index); totalWeight += weight; } else { break; } } // 如果权重还没达到目标,填充最小权重怪物 while (totalWeight < targetWeight && monsterTypes.Count < targetCount) { int minIndex = GetMinWeightIndex(weights); monsterTypes.Add(minIndex); totalWeight += weights[minIndex]; } return monsterTypes.ToArray(); } // 根据权重随机选择怪物 private int GetRandomMonsterIndex(int[] weights) { int sumWeight = 0; foreach (var w in weights) sumWeight += w; int randomValue = Random.Range(0, sumWeight); int currentSum = 0; for (int i = 0; i < weights.Length; i++) { currentSum += weights[i]; if (randomValue < currentSum) return i; } return 0; } // 获取最小权重怪物的索引 private int GetMinWeightIndex(int[] weights) { int minIndex = 0; for (int i = 1; i < weights.Length; i++) { if (weights[i] < weights[minIndex]) minIndex = i; } return minIndex; } /// /// 删除敌方单位 /// [Server] public void DeleteEnemy(int id,Transform pos) { GameObject enemy = EnemyList[id].gameObject; int hpItemPropIndex = 101;//道具爆率 int randomItemPropIndex = Random.Range(1, 101); if(randomItemPropIndex /// 痛击场上所有敌方单位 /// [Command(requiresAuthority = false)] public void DamageAllEnemy() { foreach (Enemy enemy in EnemyList.Values) { enemy.ApplyDamage(999999, null, null); } } /// /// 更新配置表 /// public void UpdateConf() { string text = Resources.Load("Data").text; if (text != null) { ParseGameJson(text); } } public void ParseGameJson(string text) { DB = new JsonLiteDB(); DB.Load(text); roundWaveTime = 15; curRoundWaveTime = 12; TableReader infoReader = DB["EnemysInfo"].GetReader(); EnemyInfos.Clear(); while (infoReader.Read()) { EnemyInfo info = new EnemyInfo(infoReader); EnemyInfos.Add((EnemyType)info.Type,info); } infoReader = DB["TowersInfo"].GetReader(); while (infoReader.Read()) { TowerInfo info = new TowerInfo(infoReader); TowerInfos.TryGetValue((TowerType)info.Type, out Dictionary infoList); if (infoList == null) { Dictionary list = new Dictionary(); list.Add(info.Lvl, info); TowerInfos.Add((TowerType)info.Type, list); } else { infoList.Add(info.Lvl, info); } } infoReader = DB["GunsInfo"].GetReader(); GunInfos.Clear(); while (infoReader.Read()) { GunInfo info = new GunInfo(infoReader); GunInfos.Add((GunType)info.Type,info); } infoReader = DB["BulletsInfo"].GetReader(); BulletInfos.Clear(); while (infoReader.Read()) { BulletInfo info = new BulletInfo(infoReader); BulletInfos.Add((BulletType)info.Type,info); } infoReader = DB["DefensesInfo"].GetReader(); while (infoReader.Read()) { DefenseInfo info = new DefenseInfo(infoReader); DefenseInfos.Add(info); } infoReader = DB["StoryProgressInfo"].GetReader(); while (infoReader.Read()) { CombatUnitInfo info = new CombatUnitInfo(infoReader); CombatUnitInfos.Add(info.Belong,info); CombatUnitInfos.TryGetValue(info.Belong, out info); } Debug.Log("游戏数值更新 -> complete"); } /// /// 获取范围内敌人 /// public int GetRangeEnemyId(Vector3 pos, float radius) { int res = -1; foreach (Enemy enemy in EnemyList.Values) { float dis = Vector3.Distance(enemy.transform.position, pos); if (dis <= radius) { radius = dis; res = enemy.id; break; } } return res; } /// /// 获取最近的玩家 /// /// public GameObject GetPlayer() { if (players == null || players.Count == 0) return null; GameObject nearestPlayer = null; float minDistance = float.MaxValue; foreach (var player in players.Values) { if (player == null) continue; // 计算XZ平面距离(使用你的 ReflectVectorXOZ 方法) float dis = Vector3.Distance( player.transform.position.ReflectVectorXOZ(), transform.position.ReflectVectorXOZ() ); if (dis < minDistance) { minDistance = dis; nearestPlayer = player.gameObject; } } return nearestPlayer; } [Server] public void CreateEnemyUI(Enemy enemy) { GameObject enemyUI = Instantiate(EnemyUIPre); NetworkServer.Spawn(enemyUI); EnemyUI enemyUIScript = enemyUI.GetComponent(); enemyUIScript.Init(enemy); EnemyUIList.Add(enemy.id, enemyUIScript); } [Server] public void DeleteEnemyUI(int id) { GameObject enemyUI = EnemyUIList[id].gameObject; EnemyUIList.Remove(id); NetworkServer.Destroy(enemyUI); } [ClientRpc] public void RpcShowHUD() { HUDPanel.Show(); } #region 空投道具 /// /// 修复炮塔 /// public void RepairTower() { } /// /// 进入联控 /// [Server] public void JoinControlTower(int playerIndex) { PlayJointMusic(); // 修改所有炮塔模式 foreach (Tower tower in TowerList.Values) { if (tower.controllerId == -1) { tower.controllerId = playerIndex; tower.mode = TowerMode.Joint; } } TriggerEvent("JoinControlStart", playerIndex); CoroutineTaskManager.Instance.WaitSecondTodo(() => { ChangeBgmRpc(1); foreach (Tower tower in TowerList.Values) { if (tower.mode == TowerMode.Joint) { tower.controllerId = playerIndex; tower.mode = tower.originalMode; } TriggerEvent("JoinControlEnd", playerIndex); } }, 30f); } #endregion [ClientRpc] public void TriggerEvent(string key, int param) { DragonLi.Core.EventDispatcher.TriggerEvent(key, param); } public void AddScore(string index, int damage) { if (SettleInfos.ContainsKey(index)) { SettleInfos[index].Score += damage; } string jsonStr = JsonMapper.ToJson(SettleInfos); settleData = jsonStr; } public void SetTitle(string index, string title) { if (SettleInfos.ContainsKey(index)) { SettleInfos[index].Title = title; } Debug.Log(SettleInfos); } public void SetPlayerName(string index) { if (SettleInfos.ContainsKey(index)) { SettleInfos[index].playerName = int.Parse(index); } } [Server] public void AddData(int playerIndex) { SettleInfos.Add(playerIndex.ToString(), new SettleInfo()); } public string SerializeSettleInfos() { return JsonUtility.ToJson(SettleInfos); } #region 工具 public string GetLessTimeStr() { string res = ""; if (isStart) { res = FormatTime((int)(vistEnd - DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds)); } return res; } public int GetLessTimeSeconds() { return (int)(vistEnd - DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds); } // 时分秒 public string FormatTime(int totalSeconds) { int hours = totalSeconds / 3600; // string hh = hours < 10 ? "0" + hours : hours.ToString(); int minutes = (totalSeconds - hours * 3600) / 60; string mm = minutes < 10f ? "0" + minutes : minutes.ToString(); int seconds = totalSeconds - hours * 3600 - minutes * 60; string ss = seconds < 10 ? "0" + seconds : seconds.ToString(); return string.Format("{0}:{1}", mm, ss); } #endregion public void PlaySound2DRPC(string sound) { MasterAudio.PlaySound(sound); } [ClientRpc] public void PlaySound3DRPC(string sound,Transform tran,bool isStop) { if(isStop) MasterAudio.StopAllSoundsOfTransform(tran); MasterAudio.PlaySound3DAtTransform(sound, tran); } public void PlayJointMusic() { MasterAudio.PlaySound(JointIn); GameLocal.Ins.BGMState.StateChange(2); } }