using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines; using Common; using DarkTonic.MasterAudio; using DragonLi.Core; using LitJson; using Mirror; using NaughtyAttributes; using Pathfinding; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.PlayerLoop; using UnityEngine.UIElements; using XPlugin.Data.JsonLiteDB; using static XPlugin.Data.JsonLiteDB.JsonLiteDB; 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 List curItemPropList = 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 * 15); [SyncVar] public string settleData = ""; [SyncVar] public GameState gameState = GameState.None; [SoundGroup] public string JointIn; [SoundGroup] public string roundSound; public int roundWaveTime; public int curRoundWaveTime; // 新增:指引系统 public GameObject GuideArrowPre; // 指引箭头预制体 private GameObject guideArrowInstance; // 指引箭头实例 private GuideArrowPath guideArrowComponent; // 指引箭头组件 private bool isGuideArrowActive = false; private Vector3 lastPlayerPosition; // 记录玩家上一次的位置 private float updatePathThreshold = 0.5f; // 更新路径的阈值(玩家移动超过这个距离才更新路径) private float updatePathCooldown = 0.3f; // 更新路径的冷却时间 private float lastPathUpdateTime = 0f; private Vector3[] lastPathPoints; // 上一次的路径点 private bool isPathSmoothed = false; private List smoothedPath = new List(); void Awake() { Ins = this; } void Start() { // 新增:初始化指引系统 InitializeGuideArrow(); if (isClient) { isStart = false; CreateDoor(); } } public void Update() { // 更新指引箭头位置 UpdateGuideArrowPosition(); } /// /// 创建门 /// public void CreateDoor() { UpdateConf(); if (!isServer) return; GameObject door = Instantiate(DoorPre); door.transform.position = GameLocal.Ins.doorPos.position.ReflectVectorXOZ(); NetworkServer.Spawn(door); // 延迟开始指引,确保玩家和门都已初始化 CoroutineTaskManager.Instance.WaitSecondTodo(() => { StartGuide(); }, 0.5f); } /// /// 创建初回合 /// 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); }, vistAllTime); } [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; MonoSingleton.Instance.WaitSecondTodo(() => { Debug.Log("游戏结束,5秒后退出"); Application.Quit(); }, 5f); // //结算页面 // 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; if (GameLocal.Ins.enemyStartPos.Length == 0) { Debug.LogError("没有设置敌人出生点!"); yield break; } for (int i = 0; i < info.EnemyTypeList.Length; i++) { GameObject enemy = Instantiate(EnemyPres[info.EnemyTypeList[i]]); NetworkServer.Spawn(enemy); // 循环使用出生点 int posId = i % GameLocal.Ins.enemyStartPos.Length; int posX = Random.Range(-1, 2); int posZ = Random.Range(-1, 2); enemy.transform.position = GameLocal.Ins.enemyStartPos[posId].position + new Vector3(posX, 0, posZ); enemy.transform.eulerAngles = Vector3.zero; 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); // FIX: Check if enemyStartPos has elements before accessing if (GameLocal.Ins.enemyStartPos.Length == 0) { Debug.LogError("No enemy start positions configured!"); return; } int posId = Random.Range(0, GameLocal.Ins.enemyStartPos.Length); // Use actual length int posX = Random.Range(-1, 2); int posZ = Random.Range(-1, 2); 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); curItemPropList.Add(item); } /// ///删除枪械 /// public void DesGunProList() { if (curGunPropList.Count <= 0) return; NetworkServer.Destroy(curGunPropList[1]); NetworkServer.Destroy(curGunPropList[0]); curGunPropList.Clear(); } public void DesItemProp(GameObject item) { if (curItemPropList.Count <= 0) return; item.GetComponent().isDeal = true; curItemPropList.Remove(item); NetworkServer.Destroy(item); } 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);// * players.Count; // 24-26 int targetCount = Random.Range(6, 10);// * players.Count; // 4-7 //if (targetCount > 15) //{ // targetCount = 15; // targetCount = 15; //} // 随机添加怪物直到接近目标 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; } #region 指引系统 /// /// 初始化指引箭头 /// private void InitializeGuideArrow() { // 检查预制体是否存在 if (GuideArrowPre == null) { Debug.LogError("GuideArrowPre 预制体未分配!"); return; } // 实例化指引箭头预制体 guideArrowInstance = Instantiate(GuideArrowPre); guideArrowInstance.name = "GuideArrow"; // 获取指引箭头组件 guideArrowComponent = guideArrowInstance.GetComponent(); if (guideArrowComponent == null) { Debug.LogError("GuideArrowPre 预制体上没有找到 GuideArrowPath 组件!"); Destroy(guideArrowInstance); guideArrowInstance = null; return; } // 设置指引箭头的层级和高度 guideArrowComponent.obstacleMask = LayerMask.GetMask("Default"); // 根据实际障碍物层级设置 guideArrowComponent.pathHeight = 0.5f; // 设置路径显示高度 // 初始隐藏指引 guideArrowComponent.ClosePath(); // 可选:设置父物体,保持场景整洁 guideArrowInstance.transform.SetParent(this.transform); // 初始化玩家位置 if (GameLocal.Ins.self != null) { lastPlayerPosition = GameLocal.Ins.self.transform.position; } } /// /// 更新指引箭头位置(实时跟随玩家移动) /// // 修改 UpdateGuideArrowPosition 方法 private void UpdateGuideArrowPosition() { if (!isGuideArrowActive || GameLocal.Ins.doorPos == null || GameLocal.Ins.self == null) return; // 获取玩家当前位置 Vector3 currentPlayerPosition = GameLocal.Ins.self.transform.position; // 检查冷却时间 if (Time.time - lastPathUpdateTime < updatePathCooldown) return; // 检查玩家是否移动了足够远的距离 float distanceMoved = Vector3.Distance(currentPlayerPosition, lastPlayerPosition); if (distanceMoved > updatePathThreshold) { // 获取门的位置 Vector3 doorPosition = GameLocal.Ins.doorPos.transform.position; // 使用曲线检测和路径平滑 UpdatePathWithCurveDetection(currentPlayerPosition, doorPosition); // 更新记录的位置和时间 lastPlayerPosition = currentPlayerPosition; lastPathUpdateTime = Time.time; } } // 新增:使用曲线检测和路径平滑的方法 private void UpdatePathWithCurveDetection(Vector3 start, Vector3 end) { if (guideArrowComponent == null) return; // 1. 检测是否为直接可见路径 if (IsDirectPathClear(start, end)) { // 直接路径,使用简单的贝塞尔曲线 smoothedPath = GenerateBezierCurve(start, end, 0.2f); guideArrowComponent.SetPath(smoothedPath); // 这里使用 List 参数 isPathSmoothed = true; return; } // 2. 间接路径,使用优化的绕路算法 List newPath = CalculateObstacleAvoidancePath(start, end); if (newPath != null && newPath.Count > 1) { // 应用路径平滑 smoothedPath = SmoothPath(newPath); guideArrowComponent.SetPath(smoothedPath); // 这里使用 List 参数 isPathSmoothed = true; lastPathPoints = smoothedPath.ToArray(); } } // 新增:检查直接路径是否畅通 private bool IsDirectPathClear(Vector3 start, Vector3 end) { Vector3 direction = (end - start).normalized; float distance = Vector3.Distance(start, end); // 使用射线检测,同时检查多个点 int checkPoints = Mathf.CeilToInt(distance / 0.5f); for (int i = 0; i <= checkPoints; i++) { float t = (float)i / checkPoints; Vector3 checkPoint = Vector3.Lerp(start, end, t); // 检查周围小范围的碰撞 if (Physics.CheckSphere(checkPoint, 0.3f, guideArrowComponent.obstacleMask)) { return false; } } return true; } // 新增:生成贝塞尔曲线路径 private List GenerateBezierCurve(Vector3 start, Vector3 end, float curveHeight) { List curvePoints = new List(); int segments = 20; // 曲线分段数 // 计算控制点(在中间稍微抬起形成曲线) Vector3 controlPoint = (start + end) * 0.5f + Vector3.up * curveHeight; for (int i = 0; i <= segments; i++) { float t = (float)i / segments; // 二次贝塞尔曲线公式 Vector3 point = (1 - t) * (1 - t) * start + 2 * (1 - t) * t * controlPoint + t * t * end; curvePoints.Add(point); } return curvePoints; } // 新增:优化后的绕障碍物路径计算 private List CalculateObstacleAvoidancePath(Vector3 start, Vector3 end) { List path = new List(); path.Add(start); // 尝试寻找最佳绕行点 Vector3 bypassPoint = FindOptimalBypassPoint(start, end); if (bypassPoint != start) { // 如果有绕行点,构建曲线路径 List curve1 = GenerateBezierCurve(start, bypassPoint, 0.3f); List curve2 = GenerateBezierCurve(bypassPoint, end, 0.3f); path.AddRange(curve1.Skip(1)); path.AddRange(curve2.Skip(1)); } else { // 没有找到绕行点,使用简单的曲线 path = GenerateBezierCurve(start, end, 0.2f); } return path; } // 新增:寻找最优绕行点 private Vector3 FindOptimalBypassPoint(Vector3 from, Vector3 to) { Vector3 direction = (to - from).normalized; float distance = Vector3.Distance(from, to); // 定义多个探测方向 Vector3[] probeDirections = new Vector3[] { Vector3.Cross(direction, Vector3.up).normalized, // 右侧 -Vector3.Cross(direction, Vector3.up).normalized, // 左侧 (Vector3.Cross(direction, Vector3.up).normalized + Vector3.up * 0.3f).normalized, // 右上 (-Vector3.Cross(direction, Vector3.up).normalized + Vector3.up * 0.3f).normalized // 左上 }; float[] probeDistances = new float[] { 2f, 3f, 4f, 5f }; Vector3 bestBypassPoint = from; float bestScore = float.MaxValue; foreach (Vector3 probeDir in probeDirections) { foreach (float probeDist in probeDistances) { Vector3 probePoint = from + probeDir * probeDist; // 检查探测点是否可行 if (!Physics.CheckSphere(probePoint, 0.5f, guideArrowComponent.obstacleMask)) { // 计算路径分数(距离 + 转向角度) float pathLength = Vector3.Distance(from, probePoint) + Vector3.Distance(probePoint, to); float angleCost = Vector3.Angle(probePoint - from, to - probePoint) * 0.1f; float score = pathLength + angleCost; if (score < bestScore) { bestScore = score; bestBypassPoint = probePoint; } } } } return bestBypassPoint; } // 新增:路径平滑算法 private List SmoothPath(List rawPath) { if (rawPath.Count < 3) return rawPath; List smoothed = new List(); smoothed.Add(rawPath[0]); // 使用简单的平均平滑 for (int i = 1; i < rawPath.Count - 1; i++) { Vector3 smoothedPoint = (rawPath[i - 1] + rawPath[i] + rawPath[i + 1]) / 3f; smoothed.Add(smoothedPoint); } smoothed.Add(rawPath[rawPath.Count - 1]); return smoothed; } /// /// 显示指引箭头 /// public void ShowGuideArrow() { if (guideArrowComponent != null && GameLocal.Ins.doorPos != null && GameLocal.Ins.self != null) { guideArrowComponent.ShowPath(); isGuideArrowActive = true; // 初始化路径 Vector3 playerPosition = GameLocal.Ins.self.transform.position; Vector3 doorPosition = GameLocal.Ins.doorPos.transform.position; UpdatePathWithCurveDetection(playerPosition, doorPosition); // 记录初始位置 lastPlayerPosition = playerPosition; } } /// /// 隐藏指引箭头 /// public void HideGuideArrow() { if (guideArrowComponent != null) { guideArrowComponent.ClosePath(); isGuideArrowActive = false; } } /// /// 开始指引(在创建门后调用) /// public void StartGuide() { if (GameLocal.Ins.doorPos != null && GameLocal.Ins.self != null) { ShowGuideArrow(); // 初始化路径 Vector3 playerPosition = GameLocal.Ins.self.transform.position; Vector3 doorPosition = GameLocal.Ins.doorPos.transform.position; // 使用新的路径计算方法 UpdatePathWithCurveDetection(playerPosition, doorPosition); // 记录初始位置 lastPlayerPosition = playerPosition; } } /// /// 停止指引(在游戏开始或删除门时调用) /// public void StopGuide() { HideGuideArrow(); } /// /// 清理指引箭头实例 /// public void CleanupGuideArrow() { if (guideArrowInstance != null) { Destroy(guideArrowInstance); guideArrowInstance = null; guideArrowComponent = null; isGuideArrowActive = false; } } #endregion [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); } }