using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines; using Common; using DarkTonic.MasterAudio; using DragonLi.Core; using LitJson; 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; /// /// 游戏状态 /// public enum GameState { None = 0, Playing = 1, /// /// 胜利 /// Victory = 2, /// /// 失败 /// Failur = 3, Settle } public class GameManager : MonoBehaviour { public static GameManager Ins { get; private set; } public GameState gameState; [NonSerialized] public float vistEnd = 60 * 15; public float curGameTime = 0; //预制体 public GameObject playerPre; public GameObject enemyPre; public GameObject gameStartDoor; public GameObject mirrorPre; public GameObject witchPre; public GameObject crystalStatuePre; // 水晶雕像预制体 public RightHand playerRightHand; public Enemy enemy; public bool isStartGame = false; //添加 [Header("AI角色")] public GameObject aiCharacterPre;//AI角色预制体 private GameObject aiCharacter;//AI角色实例 #region 指引系统 // 新增:指引系统 [Header("指引系统")] 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(); #endregion #region 事件参数 public List cutscenes=new List(); #endregion void Awake() { Ins = this; } private void Start() { isStartGame = false; // 新增:初始化指引系统 } public void GameStart() { //CreateAICharacter(); //CleanupGuideArrow(); //CreateEnemy(GameLocal.Ins.enemyPos.position,GameLocal.Ins.enemyPos.eulerAngles); StartCutscene(0); } public void StartCutscene(int id) { cutscenes[id].StartCutscene(); } //修改处:添加创建AI角色的方法 private void CreateAICharacter() { //检查是否已经存在AI角色 if (aiCharacter != null) { Debug.Log("AI角色已经存在,不再创建新的"); return; } if (aiCharacterPre != null) { Debug.Log("创建AI角色"); //在玩家前方创建AI角色 Vector3 spawnPosition = playerPre.transform.position + playerPre.transform.forward * 3f; aiCharacter = Instantiate(aiCharacterPre, GameLocal.Ins.startDoorPos.position, Quaternion.identity); //获取AIController并启动开场白 AIController aiController = aiCharacter.GetComponent(); if (aiController != null) { //注册AI介绍完成回调 aiController.OnIntroductionComplete += StartGameAfterIntroduction; //添加延迟,确保所有组件已经完成初始化 StartCoroutine(DelayedStartIntroduction(aiController)); } else { Debug.LogError("AI预制体中的AIController组件丢失"); } } else { Debug.LogError("AI预制体没有在GameManager分配!"); } } public void StartGameAfterIntroduction() { isStartGame = true; Debug.Log("AI介绍完成,开始游戏正常流程"); HUDPanel.Show(); CreateEnemy(GameLocal.Ins.enemyPos.position, new Vector3(0, 180, 0)); } private IEnumerator DelayedStartIntroduction(AIController aiController) { yield return new WaitForSeconds(0.1f); // 短暂延迟 aiController.StartIntroduction(); } public void LoginGame() { CreatePlayer(); PlayBGM(0); CreateGameStartDoor(GameLocal.Ins.startDoorPos.position); } public void PlayBGM(int id) { foreach (var item in GameLocal.Ins.BGM) { item.SetActive(false); } GameLocal.Ins.BGM[id].SetActive(true); } public void GameOver(GameState state) { } /// /// 更新配置表 /// 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); // // TableReader infoReader = DB["EnemysInfo"].GetReader(); // while (infoReader.Read()) // { // EnemyInfo info = new EnemyInfo(infoReader); // // } Debug.Log("游戏数值更新 -> complete"); } public void StopBgm() { } public void PlaySound2DRPC(string sound) { MasterAudio.PlaySound(sound); } public void PlaySound3DRPC(string sound,Transform soundTran,bool isStop=false) { if(isStop) MasterAudio.StopAllSoundsOfTransform(soundTran); MasterAudio.PlaySound3DAtTransform(sound, soundTran); } public void CreateGameStartDoor(Vector3 pos) { var door= Instantiate(gameStartDoor, pos, Quaternion.identity); // 延迟开始指引,确保玩家和门都已初始化 CoroutineTaskManager.Instance.WaitSecondTodo(() => { StartGuide(); }, 0.5f); if (GameLocal.Ins.place == Place.Jiangsu_Xvzhou_Suning_Guangchang ||GameLocal.Ins.place == Place.Hunan_Changde_Lixian_WandaGuangchang ||GameLocal.Ins.place == Place.Hunan_Zhuzhou_Wanda_Shennongcheng_Chaowanshe ) { door.transform.eulerAngles = new Vector3(0, 90, 0); } if ( GameLocal.Ins.place == Place.Hunan_Zhuzhou_Wanda_Shennongcheng_Chaowanshe || GameLocal.Ins.place == Place.Hebei_Hengshui_Taocheng_WandaGuangchang || GameLocal.Ins.place == Place.Ningxia_Yinchuan_Jinfeng_XinhualianGuangchang ) { door.transform.eulerAngles = new Vector3(0, -90, 0); } else { door.transform.eulerAngles = new Vector3(0, 180, 0); } MonoSingleton.Instance.WaitSecondTodo(() => { if (!isStartGame) { if (door.gameObject==null) return; door.gameObject.GetComponent().enabled = false; door.gameObject.SetActive(false); Destroy(door.gameObject); GameStart(); } },5); } public void CreatePlayer() { Instantiate(playerPre); } public void CreateEnemy(Vector3 pos,Vector3 eulerAngles) { var curEnemy=Instantiate(enemyPre,pos,Quaternion.identity); curEnemy.transform.eulerAngles = eulerAngles; curEnemy.GetComponent().Init(); enemy = curEnemy.GetComponent(); } public void CreateMirrorPre() { var curMirror=Instantiate(mirrorPre,GameLocal.Ins.mirrorPos.position,Quaternion.identity); curMirror.transform.eulerAngles = GameLocal.Ins.mirrorPos.eulerAngles; curMirror.GetComponent().Init(); //enemy = curEnemy.GetComponent(); } public void PlayerHit() { if(enemy.isDie) return; //玩家UI模糊 HUDPanel.Ins.ShowEgg(); Debug.Log("击中玩家"); PlaySound2DRPC("1.50"); } public void EnemyHit(Vector3 pos) { if(enemy.isDie) return; enemy.Hit(); PlaySound3DRPC("1.49",enemy.transform,true); } public void EnemyTimeHit() { enemy.isTimeHit = true; } public void StartGameEnd() { //任务结束 PlaySound2DRPC("1.24"); playerRightHand.ChangeHand(); isStartGame = false; CreateGameStartDoor(GameLocal.Ins.self.transform.position.ReflectVectorXOZ()+new Vector3(0,0,2)); } private void Update() { //更新指引箭头位置 //UpdateGuideArrowPosition(); if (gameState == GameState.Playing) { curGameTime+=Time.deltaTime; } } public int GetNowTime() { return Mathf.RoundToInt(curGameTime); } #region 工具 public string GetLessTimeStr() { string res = ""; if (gameState == GameState.Playing) { 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 #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.startDoorPos == 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.startDoorPos.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.startDoorPos != null && GameLocal.Ins.self != null) { guideArrowComponent.ShowPath(); isGuideArrowActive = true; // 初始化路径 Vector3 playerPosition = GameLocal.Ins.self.transform.position; Vector3 doorPosition = GameLocal.Ins.startDoorPos.transform.position; UpdatePathWithCurveDetection(playerPosition, doorPosition); // 记录初始位置 lastPlayerPosition = playerPosition; } } /// /// 隐藏指引箭头 /// public void HideGuideArrow() { if (guideArrowComponent != null) { guideArrowComponent.ClosePath(); isGuideArrowActive = false; } } /// /// 开始指引(在创建门后调用) /// public void StartGuide() { if (GameLocal.Ins.startDoorPos != null && GameLocal.Ins.self != null) { ShowGuideArrow(); // 初始化路径 Vector3 playerPosition = GameLocal.Ins.self.transform.position; Vector3 doorPosition = GameLocal.Ins.startDoorPos.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 }