using BehaviorDesigner.Runtime;
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,
///
/// 冲锋阶段
///
EndEvent,
PKEvent,
}
public enum GameEnemyEventType
{
None=0,//普通事件
Snipe=1,//狙击事件
Mortar=2,//迫击炮事件
MachineGun=3,//机关枪事件
SubmachineGun=4,//冲锋枪事件
Grenade=5,//手榴弹事件
Biochemical=6,//生化兵事件
Tank=7,//坦克兵事件
Bomber=8,//轰炸机事件
HelpNpc=9,//拯救平民事件
BulletUp=10,//子弹拾取事件
CleanUp=11,//清场事件
LastGame=12,//最终冲锋事件
}
public enum GameMode
{
OnePlayer=0,
TwoPlayers=1,
}
public class GameManager : NetworkBehaviour
{
public static GameManager Ins { get; private set; }
#region 预制体
public GameObject DoorPre;
public GameObject itemPropPre;
public GameObject mortarBulletPre;
public GameObject gqBulletPre;
public GameObject gqMuzzleBulletPre;
// 炮塔预制体集合
//public GameObject[] TowerPres;
// 怪物预制集合
public GameObject[] EnemyPres;
public GameObject[] playerAiPres;
public GameObject playerEndAiPres;
public GameObject explosionPre;
public GameObject enemyGrenadePre;
public GameObject enemyGasBombPre;
public GameObject enemyEndAiPre;
public GameObject enemyPlanePre;
public GameObject[] playerNpcPre;
//public GameObject PathGuidePre;
//public GuideArrowPath pathGuide;//引导路径
// 怪物ui预制体
public GameObject EnemyUIPre;
#endregion
// json数据库
private JsonLiteDB DB;
// 怪物信息集合
//public Dictionary EnemyInfos = new Dictionary();
public Dictionary PlayerAiInfos = new Dictionary();
// 炮塔信息集合
public Dictionary> TowerInfos = new Dictionary>();
// 枪械信息集合
//public Dictionary GunInfos = new Dictionary();
// 子弹信息集合
public Dictionary BulletInfos = new Dictionary();
public Dictionary AiInfos = new Dictionary();
public Dictionary RoundInfos = new Dictionary();
// 剧情信息
public Dictionary CombatUnitInfos = new Dictionary();
private List curGunPropList = new List();
public Dictionary players = new Dictionary();
public GameMode gameMode = GameMode.OnePlayer;
///
/// 敌人自增
///
private int enemyIndex = 0;
///
/// 所有敌人
///
public Dictionary EnemyList = new Dictionary();
public Dictionary PlayerAiList = new Dictionary();
///
/// 所有敌人UI
///
public Dictionary EnemyUIList = new Dictionary();
///
/// 所有炮塔
///
public Dictionary TowerList = new Dictionary();
public Dictionary> TowerList2 = new Dictionary>();
public Dictionary SettleInfos = new Dictionary();
//public List curEnemyList = new List();
[SyncVar]
public bool isStart;
///
/// 波次自增
///
[SyncVar]
public int roundIndex = 0;
// 游玩结束时间
[NonSerialized]
[SyncVar]
public long vistEnd = 0;
// 总游玩时长
private int vistAllTime = (int)(60*12);//开启最后拼刺刀模式
[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 player;
[SyncVar] public bool isPkEvent;
//添加
[Header("AI角色")]
public GameObject aiCharacterPre;//AI角色预制体
private GameObject aiCharacter;//AI角色实例
private bool isAIIntroductionComplete = false;
[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();
public void GamePlay()
{
//CreateAICharacter();
isAIIntroductionComplete = true;
GameLocal .Ins .BGMState .gameObject .SetActive (true);
if (isClient)
{
isStart = false;
CreateDoor();
}
}
//修改处:添加AI介绍完成后的游戏开始方法
public void StartGameAfterIntroduction()
{
isAIIntroductionComplete = true;
GameLocal .Ins .BGMState .gameObject .SetActive (true);
if (isClient)
{
isStart = false;
CreateDoor();
}
}
//修改处:添加创建AI角色的方法
private void CreateAICharacter()
{
//检查是否已经存在AI角色
if (aiCharacter != null)
{
Debug.Log("AI角色已经存在,不再创建新的");
return;
}
if (aiCharacterPre != null)
{
Debug.Log("创建AI角色");
//获取第一个玩家
//Transform player = players[0].transform;
if (player == null)
{
Debug.LogError("找不到玩家,无法创建AI角色");
return;
}
//在玩家前方创建AI角色
Vector3 spawnPosition = player.transform.position + player.transform.forward * 3f;
spawnPosition.y = 0f; // 固定Y坐标为0
aiCharacter = Instantiate(aiCharacterPre, spawnPosition, Quaternion.identity);
//获取AIController并启动开场白
AIController aiController = aiCharacter.GetComponent();
if (aiController != null)
{
//注册AI介绍完成回调
aiController.OnIntroductionComplete += StartGameAfterIntroduction;
// 新增:注册AI离开回调
// aiController.OnIntroductionComplete += CreateGuidancePathToDoor;
//添加延迟,确保所有组件已经完成初始化
StartCoroutine(DelayedStartIntroduction(aiController));
}
else
{
Debug.LogError("AI预制体中的AIController组件丢失");
}
}
else
{
Debug.LogError("AI预制体没有在GameManager分配!");
}
}
private IEnumerator DelayedStartIntroduction(AIController aiController)
{
yield return new WaitForSeconds(0.1f); // 短暂延迟
aiController.StartIntroduction();
}
void Awake()
{
Ins = this;
}
void Start()
{
// 新增:初始化指引系统
InitializeGuideArrow();
}
///
/// 创建门
///
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;
PlaySound2DRPC("1.0");
// CoroutineTaskManager.Instance.WaitSecondTodo(() =>
// {
// PlaySound2DRPC("1.1");
// }, 10f);
CreatePlayerAi();
//SetGameState(GameState.Wave);
RpcMessageRound();
}
///
/// 创建下一回合
///
public void CreateNextRound()
{
roundIndex++;
roundWaveTime = 3;
curRoundWaveTime = 1;
RpcMessageRound();
}
[Server]
public void GameStart()
{
gameState = GameState.Playing;
gameMode=players.Count<=1 ? GameMode.OnePlayer : GameMode.TwoPlayers;
vistEnd = (long)(DateTime.Now.Subtract(new DateTime(1970, 1, 1))).TotalSeconds + vistAllTime;
isStart = true;
ChangeBgmRpc(0);
AstarPath.active.Scan();
CreateFirstRound();
// 延迟1s后给所有人发放武器
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
GivePistol(GunType.Pistol);
}, 1f);
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
//GameOver(GameState.Settle);
StartSpecialEvent(GameEnemyEventType.CleanUp);
}, vistAllTime);
}
[ClientRpc]
public void GivePistol(GunType type)
{
Debug.Log("创建武器中...");
GameLocal.Ins.self.PickUpGun(type, -999);
}
[Server]
public void SetGameState(GameState state)
{
gameState = state;
}
//1.游戏时间到
//2.所有怪物被消灭
//3.玩家被消灭
//以上都要跳出结算
[Server]
public void GameOver()
{
RpcShow();
DamageAllEnemy();
isStart = false;
PlaySound2DRPC("1.60");
Debug.Log("游戏结束,5秒后退出");
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
Debug.Log("正在退出游戏...");
Application.Quit();
}, 10f);
}
[Server]
//public void PlayEndEvent()
//{
// Debug.LogError("开启End事件");
// gameState = GameState.EndEvent;
// GivePistol(GunType.MeleeWeapon);
// foreach (var item in PlayerAiList.Values)
// {
// item.EndEvent();
// }
// PlaySound2DRPC("1.61");
// OpenDoor();
// for (int i = 0; i < 7; i++)
// {
// Transform[] targetPos = GameLocal.Ins.enemyEndPos;
// GameObject enemy = Instantiate(enemyEndAiPre);
// NetworkServer.Spawn(enemy);
// int posId =i/3;
// enemy.transform.position = GameLocal.Ins.enemyStartPos[posId].position;
// enemy.transform.eulerAngles = targetPos[posId].eulerAngles;
// enemyIndex++;
// Enemy enemyScript = enemy.GetComponent();
// enemyScript.OnSpawn(enemyIndex, 3, 1,GameLocal.Ins.pkPos.position);
// enemyScript.ai.maxSpeed = 2;
// EnemyList.Add(enemyIndex, enemyScript);
// GameObject playerAi = Instantiate(playerEndAiPres);
// NetworkServer.Spawn(playerAi);
// playerAi.transform.position = GameLocal.Ins.endPlayerStartPos.position;
// playerAi.transform.eulerAngles = AiInfos[1].EulerAngles;
// PlayerAI playerAI = playerAi.GetComponent();
// playerAI.OnSpawn(i+2,PlayerAIType.EndPlayerAi, 1,enemy);
// playerAI.ai.maxSpeed = 2;
// PlayerAiList.Add(i+2, playerAI);
// }
// curRoundEnemyCount = EnemyList.Count;
//}
public void PlayEndEvent(bool isEnd)
{
Debug.LogError("开启End事件");
if (isEnd)
{
gameState = GameState.EndEvent;
PlaySound2DRPC("1.61");
OpenDoor();
}
else
{
// 如果是PK事件,设置游戏状态
gameState = GameState.PKEvent;
isPkEvent = true;
}
GivePistol(GunType.MeleeWeapon);
foreach (var item in PlayerAiList.Values)
{
item.EndEvent();
}
// 检查 enemyStartPos 数组是否为空或长度不足
if (GameLocal.Ins.enemyStartPos == null || GameLocal.Ins.enemyStartPos.Length == 0)
{
Debug.LogError("enemyStartPos 数组为空或未初始化");
return;
}
// 定义3x3范围的中心点和大小
Vector3 centerPos = GameLocal.Ins.pkPos.position;
float areaSize = 3f; // 3x3的范围
int createCount = isEnd ? 7 : 15;
// 修复:计算安全的数组索引
int enemyStartPosCount = GameLocal.Ins.enemyStartPos.Length;
int enemyEndPosCount = GameLocal.Ins.enemyEndPos?.Length ?? 0;
for (int i = 0; i < createCount; i++)
{
Transform[] targetPos = GameLocal.Ins.enemyEndPos;
// 检查 enemyEndPos 数组
if (targetPos == null || targetPos.Length == 0)
{
Debug.LogError("enemyEndPos 数组为空");
break;
}
GameObject enemy = Instantiate(enemyEndAiPre);
NetworkServer.Spawn(enemy);
// 检查是否为指定场地
if (GameLocal.Ins.place == Place.Jiangsu_Xvzhou_Guolou_Oulebao)
{
// 在3x3范围内随机生成位置
Vector3 randomOffset = new Vector3(
Random.Range(-areaSize / 2f, areaSize / 2f),
0,
Random.Range(-areaSize / 2f, areaSize / 2f)
);
enemy.transform.position = centerPos + randomOffset;
enemy.transform.eulerAngles = Vector3.zero;
}
else
{
// 修复:使用安全的数组索引
// 确保 posId 不超过数组边界
int posId = Mathf.Clamp(i / 3, 0, enemyStartPosCount - 1);
enemy.transform.position = GameLocal.Ins.enemyStartPos[posId].position;
// 同样确保 enemyEndPos 的索引安全
int targetPosId = Mathf.Clamp(i / 3, 0, enemyEndPosCount - 1);
enemy.transform.eulerAngles = targetPos[targetPosId].eulerAngles;
}
enemyIndex++;
Enemy enemyScript = enemy.GetComponent();
// 修复:检查 AiInfos 是否包含必要的键
Vector3 targetPosition = isEnd ? GameLocal.Ins.pkPos.position : GameLocal.Ins.self.transform.position;
enemyScript.OnSpawn(enemyIndex, 3, 1, targetPosition);
if (AiInfos.ContainsKey(3))
{
enemyScript.ai.maxSpeed = 2;
}
else
{
Debug.LogWarning("AiInfos 中不存在键为 3 的条目,使用默认速度");
enemyScript.ai.maxSpeed = 2; // 使用默认值
}
EnemyList.Add(enemyIndex, enemyScript);
if (isEnd)
{
GameObject playerAi = Instantiate(playerEndAiPres);
NetworkServer.Spawn(playerAi);
// 检查是否为指定场地
if (GameLocal.Ins.place == Place.Jiangsu_Xvzhou_Guolou_Oulebao)
{
Vector3 randomOffset;
bool positionValid;
int attempts = 0;
do
{
randomOffset = new Vector3(
Random.Range(-areaSize / 2f, areaSize / 2f),
0,
Random.Range(-areaSize / 2f, areaSize / 2f)
);
positionValid = true;
Vector3 proposedPos = centerPos + randomOffset;
foreach (var existingEnemy in EnemyList.Values)
{
if (Vector3.Distance(proposedPos, existingEnemy.transform.position) < 0.8f)
{
positionValid = false;
break;
}
}
attempts++;
if (attempts > 15) break;
} while (!positionValid);
playerAi.transform.position = centerPos + randomOffset;
playerAi.transform.eulerAngles = Vector3.zero;
}
else
{
// 非指定场地也需要防重叠
int posId = Mathf.Clamp(i / 3, 0, enemyStartPosCount - 1);
Vector3 basePosition = GameLocal.Ins.enemyStartPos[posId].position;
// 在基础位置上添加随机偏移
Vector3 randomOffset = new Vector3(
Random.Range(-1.5f, 1.5f),
0,
Random.Range(-1.5f, 1.5f)
);
Vector3 spawnPosition = basePosition + randomOffset;
// 检查位置是否有效
bool positionValid = true;
foreach (var existingEnemy in EnemyList.Values)
{
if (Vector3.Distance(spawnPosition, existingEnemy.transform.position) < 0.8f)
{
positionValid = false;
break;
}
}
// 如果位置无效,尝试另一个偏移
if (!positionValid)
{
randomOffset = new Vector3(
Random.Range(-2.0f, 2.0f),
0,
Random.Range(-2.0f, 2.0f)
);
spawnPosition = basePosition + randomOffset;
}
enemy.transform.position = spawnPosition;
int targetPosId = Mathf.Clamp(i / 3, 0, enemyEndPosCount - 1);
enemy.transform.eulerAngles = targetPos[targetPosId].eulerAngles;
}
PlayerAI playerAI = playerAi.GetComponent();
playerAI.OnSpawn(i + 2, PlayerAIType.EndPlayerAi, 1, enemy);
playerAI.ai.maxSpeed = 2;
PlayerAiList.Add(i + 2, playerAI);
}
}
// 对于现有的敌人,更新它们的目标
foreach (var enemy in EnemyList.Values)
{
if (enemy.behaviorTree != null)
{
// 如果isPkEvent为true,更新敌人的目标为玩家
if (isPkEvent)
{
GameObject player = GetPlayer(enemy.transform);
if (player != null)
{
enemy.target = player;
var sharedTarget = enemy.behaviorTree.GetVariable("target") as SharedGameObject;
if (sharedTarget != null)
{
sharedTarget.Value = player;
}
}
}
}
}
curRoundEnemyCount = EnemyList.Count;
// 可选:在指定场地时添加调试可视化
if (GameLocal.Ins.place == Place.Jiangsu_Xvzhou_Guolou_Oulebao)
{
Debug.Log($"在场地 {GameLocal.Ins.place} 中,所有单位已生成在3x3范围内,中心点: {centerPos}");
}
}
// 调试用:绘制3x3区域
private void DrawDebugArea(Vector3 center, float size)
{
Vector3 bottomLeft = center + new Vector3(-size / 2, 0, -size / 2);
Vector3 bottomRight = center + new Vector3(size / 2, 0, -size / 2);
Vector3 topLeft = center + new Vector3(-size / 2, 0, size / 2);
Vector3 topRight = center + new Vector3(size / 2, 0, size / 2);
Debug.DrawLine(bottomLeft, bottomRight, Color.red, 10f);
Debug.DrawLine(bottomRight, topRight, Color.red, 10f);
Debug.DrawLine(topRight, topLeft, Color.red, 10f);
Debug.DrawLine(topLeft, bottomLeft, Color.red, 10f);
}
[ClientRpc]
public void OpenDoor()
{
GameLocal.Ins.OpenDoor();
}
[ClientRpc]
public void RpcShowWin(bool isBlue)
{
}
[ClientRpc]
public void RpcShow()
{
SettlePanel.Show();
}
///
/// 下一波进攻开始
///
[Server]
public void RpcMessageRound()
{
if(!isStart)
return;
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
if(!isStart|| gameState== GameState.EndEvent)
return;
PlaySound2DRPC("1.4");
}, curRoundWaveTime);
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
if(!isStart|| gameState== GameState.EndEvent)
return;
if(isPkEvent ==true )
{
SetGameState(GameState.PKEvent );
}
else
{
SetGameState(GameState.Playing );
}
GetRoundEnemy();
}, 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;
///
/// 创建敌方单位
///
[Server]
IEnumerator CreateEnemy(RoundInfo info)
{
curRoundEnemyCount = info.EnemyList.Count;
for (int i = 0; i < info.EnemyList.Count; i++)
{
int enemyId = info.EnemyList[i];
bool isUerInfoAngles = (EnemyType)enemyId == EnemyType.Mortar;
Transform[] targetPos = GameLocal.Ins.enemyEndPos;
GameObject enemy = Instantiate(EnemyPres[enemyId-3]);
NetworkServer.Spawn(enemy);
int posId =i/3;
int posX=i%3==0? 0: i%3==1 ? 1 : -1;
if (isUerInfoAngles)
posX = 0;
switch ((EnemyType)enemyId)
{
case EnemyType.Ordinary:
case EnemyType.Sniper:
break;
case EnemyType.Mortar:
targetPos = GameLocal.Ins.mortarPos;
break;
}
enemy.transform.position = GameLocal.Ins.enemyStartPos[posId].position;
enemy.transform.eulerAngles =isUerInfoAngles? AiInfos[i+3].EulerAngles: targetPos[posId].eulerAngles;
enemyIndex++;
Enemy enemyScript = enemy.GetComponent();
Vector3 endPos = targetPos[posId].position + new Vector3(0, 0, posX);
if (enemyScript.type == EnemyType.Riflemen)
{
endPos = GameLocal.Ins.riflemenPos.position;
}
enemyScript.OnSpawn(enemyIndex, info.EnemyList[i], 1,endPos);
EnemyList.Add(enemyIndex, enemyScript);
yield return new WaitForSeconds(0.5f);
}
}
///
/// 创建辅助AI
///
public void CreatePlayerAi()
{
for (int i = 0; i < 2; i++)
{
GameObject playerAi = Instantiate(playerAiPres[i]);
NetworkServer.Spawn(playerAi);
playerAi.transform.position = GameLocal.Ins.playerAiPos[i].position;
playerAi.transform.eulerAngles = AiInfos[i+1].EulerAngles;
PlayerAI enemyScript = playerAi.GetComponent();
enemyScript.OnSpawn(i,(PlayerAIType)i, 1,GameLocal.Ins.playerAiEndPos[i].gameObject);
PlayerAiList.Add(i, enemyScript);
}
// else if(gameMode == GameMode.TwoPlayers)
// {
// GameObject playerAi = Instantiate(playerAiPres[0]);
// NetworkServer.Spawn(playerAi);
// playerAi.transform.position = GameLocal.Ins.playerAiPos[0].position;
// playerAi.transform.eulerAngles = AiInfos[1].EulerAngles;
// PlayerAI enemyScript = playerAi.GetComponent();
// enemyScript.OnSpawn(0,0, 1,GameLocal.Ins.playerAiEndPos[0].gameObject);
// PlayerAiList.Add(0, enemyScript);
// }
}
#region 创造敌人道具
[Server]
public void CreateExplosion(Vector3 pos,EnemyType type)
{
if(!isServer)
return;
var ex= Instantiate(explosionPre, pos, Quaternion.identity);
NetworkServer.Spawn(ex);
ex.GetComponent().Init(type);
}
public void CreateGrenade(Vector3 startPos)
{
if(!isServer)
return;
var ex= Instantiate(enemyGrenadePre, startPos, Quaternion.identity);
NetworkServer.Spawn(ex);
float x=Random.Range(-3,3);
float z=Random.Range(-3,3);
ex.GetComponent().Init(startPos, GameLocal.Ins.endMortarPos.position+new Vector3(x,0,z));
}
public void CreateGasBomb(Vector3 startPos)
{
if(!isServer)
return;
var ex= Instantiate(enemyGasBombPre, startPos, Quaternion.identity);
NetworkServer.Spawn(ex);
float x=Random.Range(-3,3);
float z=Random.Range(-3,3);
ex.GetComponent().Init(startPos,GameLocal.Ins.endMortarPos.position+new Vector3(x,0,z));
}
public void CreateEnemyPlane(Transform startPos)
{
if(!isServer)
return;
var ex= Instantiate(enemyPlanePre, startPos.position, Quaternion.identity);
NetworkServer.Spawn(ex);
}
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);
}
#endregion
public List GetRoundEnemy()
{
List curEnemyList = new List();
int curRoundIndex=roundIndex>= RoundInfos.Count? Random.Range(1,RoundInfos.Count):roundIndex;
var roundInfo=RoundInfos[curRoundIndex];
// curRoundIndex=5;
// roundInfo= RoundInfos[curRoundIndex];
bool isPk;
int pkIndex = Random.Range(0, 100);
isPk = pkIndex <= 0;
if (isPk)
{
isPkEvent = true;
PlayEndEvent(false);
}
else
{
isPkEvent = false;
GivePistol(GunType.Pistol);
StartEvent(roundInfo);
}
if (roundIndex==5)
{
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
StartSpecialEvent(GameEnemyEventType.HelpNpc);
}, 5);
}
return curEnemyList;
}
public GameEnemyEventType curEnemyEventType;
public void StartEvent(RoundInfo info)
{
curEnemyEventType = (GameEnemyEventType)info.Belong;
StartCoroutine(CreateEnemy(info));
switch (curEnemyEventType)
{
case GameEnemyEventType.SubmachineGun:
case GameEnemyEventType.None:
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
Debug.LogError("播放音效:1.10");
PlayerAiList[0].PlaySound3DRPC("1.10",true);
EnemyShowOutline(EnemyType.Ordinary);
EnemyShowOutline(EnemyType.Charge);
}, 10);
break;
case GameEnemyEventType.Snipe:
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.14",true);
}, 5);
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.15",true);
EnemyShowOutline(EnemyType.Sniper);
}, 7);
break;
case GameEnemyEventType.Mortar:
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.20",true);
StartCoroutine(CreateMortarBullet());
}, 7);
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.21",true);
EnemyShowOutline(EnemyType.Mortar);
}, 10);
break;
case GameEnemyEventType.MachineGun:
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.24",true);
StartCoroutine(CreateGQBullet());
}, 7);
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.25",true);
EnemyShowOutline( EnemyType.Riflemen);
}, 10);
break;
case GameEnemyEventType.Grenade:
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.35",true);
}, 5);
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.38",true);
EnemyShowOutline(EnemyType.Grenade);
}, 7);
break;
case GameEnemyEventType.Biochemical:
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.40",true);
}, 5);
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.42",true);
EnemyShowOutline(EnemyType.Virus);
}, 7);
break;
case GameEnemyEventType.Bomber:
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.56",true);
EnemyShowOutline(EnemyType.Commander);
EnemyShowOutline(EnemyType.Mortar);
EnemyShowOutline(EnemyType.Grenade);
EnemyShowOutline(EnemyType.Virus);
EnemyShowOutline(EnemyType.Riflemen);
StartCoroutine(CreateGQBullet());
StartCoroutine(CreateMortarBullet());
}, 10);
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.59",true);
}, 20);
break;
}
}
public void StartSpecialEvent(GameEnemyEventType type)
{
switch (type)
{
case GameEnemyEventType.HelpNpc:
CreateNpc();
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayerAiList[0].PlaySound3DRPC("1.67",true);
}, 5);
break;
case GameEnemyEventType.CleanUp:
CreateEnemyEndBullet(true);
break;
}
}
private void Update()
{
// 更新指引箭头位置
UpdateGuideArrowPosition();
// if (Input.GetKeyDown(KeyCode.Space))
// {
// StartSpecialEvent(GameEnemyEventType.HelpNpc);
// CoroutineTaskManager.Instance.WaitSecondTodo(() =>
// {
// StartSpecialEvent(GameEnemyEventType.CleanUp);
// }, 5);
// }
}
IEnumerator CreateMortarBullet()
{
Transform insPos=GameLocal.Ins.insMortarPos;
Transform endPos=GameLocal.Ins.endMortarPos;
bool isHaveMortar = IsHaveTypeEnemy(EnemyType.Mortar);
while (isHaveMortar)
{
var item= Instantiate(mortarBulletPre);
NetworkServer.Spawn(item);
item.transform.position=insPos.position;
int rangeIndexX = Random.Range(-5, 5);
int rangeIndexZ = Random.Range(-2, 2);
item.GetComponent().Init(insPos.position,endPos.position+new Vector3(rangeIndexX,0,rangeIndexZ));
yield return new WaitForSeconds(AiInfos[(int)EnemyType.Mortar].FiringRate);
isHaveMortar = IsHaveTypeEnemy(EnemyType.Mortar);
}
}
IEnumerator CreateGQBullet()
{
Transform insPos=GameLocal.Ins.gQPos;
Vector3 endPos=GameLocal.Ins.riflemenEndPos.position;
bool isHaveMortar = IsHaveTypeEnemy(EnemyType.Riflemen);
while (isHaveMortar)
{
var item= Instantiate(gqBulletPre);
NetworkServer.Spawn(item);
item.transform.position=insPos.position;
int rangeIndexZ = Random.Range(-2, 2);
item.GetComponent().OnSpawn(endPos+new Vector3(rangeIndexZ,0,rangeIndexZ),20);
var itemMuzzle= Instantiate(gqMuzzleBulletPre);
NetworkServer.Spawn(itemMuzzle);
itemMuzzle.transform.position=insPos.position;
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
NetworkServer.Destroy(itemMuzzle.gameObject);
}, 1);
yield return new WaitForSeconds(AiInfos[(int)EnemyType.Riflemen].FiringRate);
isHaveMortar = IsHaveTypeEnemy(EnemyType.Riflemen);
}
}
[ClientRpc]
public void OpenEndBullet()
{
GameLocal.Ins.OpenEndBullet();
}
[ClientRpc]
public void DownEndBullet()
{
GameLocal.Ins.DownEndBullet();
}
public List NpcEnemyList = new List();
public void CreateNpc()
{
if (!isStart)
return;
for (int posId = 0; posId < 2; posId++) // npcPos[0] 和 npcPos[1]
{
List npcList = new List();
// === 生成 3 个 NPC ===
for (int i = 0; i < 3; i++)
{
int id = Random.Range(0, playerNpcPre.Length);
// 在 npcPos 附近生成,带随机偏移
Vector3 randomOffset = new Vector3(Random.Range(-1f, 1f), 0, Random.Range(-1f, 1f));
Vector3 npcPos = GameLocal.Ins.npcPos[posId].position + randomOffset;
var npc = Instantiate(playerNpcPre[id], npcPos, Quaternion.identity);
NetworkServer.Spawn(npc);
npc.GetComponent().OnSpawn(i, GameLocal.Ins.npcEndPos.gameObject, false);
npcList.Add(npc);
}
// === 敌人生成逻辑 ===
// NPC 的平均位置(大致在3个 NPC 中心点)
Vector3 centerPos = Vector3.zero;
foreach (var npc in npcList)
centerPos += npc.transform.position;
centerPos /= npcList.Count;
// 前进方向
Vector3 forward = GameLocal.Ins.npcPos[posId].forward;
// 敌人在前进方向的反方向(后面)
Vector3 backOffset = -forward * 3f; // 敌人与NPC中心点的间隔,数值可调
for (int j = 0; j < 2; j++)
{
// 敌人横向展开
Vector3 sideOffset = Vector3.Cross(Vector3.up, forward).normalized * (j == 0 ? -1.5f : 1.5f);
Vector3 enemyPos = centerPos + backOffset + sideOffset;
var enemy = Instantiate(EnemyPres[0], enemyPos, Quaternion.identity);
NetworkServer.Spawn(enemy);
enemy.GetComponent().OnSpawn(-j, 3, -1, GameLocal.Ins.npcPos[posId].position);
enemy.GetComponent().isOutLine = true;
NpcEnemyList.Add(enemy.GetComponent());
}
}
}
public void CreateEnemyEndBullet(bool isEvent)
{
PlayerAiList[0].PlaySound3DRPC("1.65",true);
OpenEndBullet();
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
foreach (var item in EnemyList.Values)
{
item.Die(null,transform);
}
foreach (var item in NpcEnemyList)
{
item.Die(null,transform);
}
}, 5);
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
PlayEndEvent(isEvent);
DownEndBullet();
}, 8);
}
public bool IsHaveTypeEnemy(EnemyType curType)
{
foreach (var enemy in EnemyList.Values)
{
if (enemy.type == curType)
return true;
}
return false;
}
public void EnemyShowOutline(EnemyType type)
{
foreach (var enemy in EnemyList.Values)
{
if (enemy.type == type)
{
enemy.isOutLine = true;
}
}
}
///
/// 删除敌方单位
///
[Server]
public void DeleteEnemy(int id,bool isNpcEnemy)
{
if (isNpcEnemy)
{
foreach (var item in NpcEnemyList)
{
if (item.id == id)
{
NpcEnemyList.Remove(item);
NetworkServer.Destroy(item.gameObject);
return;
}
}
return;
}
GameObject enemy = EnemyList[id].gameObject;
EnemyList.Remove(id);
curRoundEnemyCount--;
NetworkServer.Destroy(enemy);
ChangePlayerAiCountdownTime();
if (curRoundEnemyCount<=0)
{
// 如果是PK事件结束,重置PK事件标志
if (gameState == GameState.PKEvent)
{
isPkEvent = false;
gameState = GameState.Playing;
// 创建下一波敌人
CreateNextRound();
}
else if (gameState == GameState.EndEvent)
{
gameState = GameState.Victory;
GameOver();
}
else
{
CreateNextRound();
}
}
}
///
/// 痛击场上所有敌方单位
///
[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;
AiInfos.Clear();
RoundInfos.Clear();
TableReader infoReader = DB["AiInfo"].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["AiInfo"].GetReader();
while (infoReader.Read())
{
AiInfo info = new AiInfo(infoReader);
AiInfos.Add(info.ID,info);
}
infoReader = DB["RoundInfo"].GetReader();
while (infoReader.Read())
{
RoundInfo info = new RoundInfo(infoReader);
RoundInfos.Add(info.ID,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;
}
///
/// 获取最近的Ai
///
///
public GameObject GetPlayerAi(Transform curTransform)
{
if (PlayerAiList.Count==0 )
return null;
GameObject nearestPlayer = null;
float minDistance = float.MaxValue;
foreach (var player in PlayerAiList)
{
if (player.Value == null|| player.Key<=1|| player.Value.isGet) continue;
// 计算XZ平面距离(使用你的 ReflectVectorXOZ 方法)
float dis = Vector3.Distance(
player.Value.transform.position.ReflectVectorXOZ(),
curTransform.position.ReflectVectorXOZ()
);
if (dis < minDistance)
{
minDistance = dis;
player.Value.isGet = true;
nearestPlayer = player.Value.gameObject;
}
}
return nearestPlayer;
}
public GameObject GetPlayer(Transform curTransform)
{
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(),
curTransform.position.ReflectVectorXOZ()
);
if (dis < minDistance)
{
minDistance = dis;
nearestPlayer = player.gameObject;
}
}
return nearestPlayer;
}
///
/// 获取最近敌人
///
///
public GameObject GetEnemy(Transform playerAi)
{
GameObject nearestPlayer = null;
float minDis = 999;
foreach (var enemy in EnemyList.Values)
{
if (enemy == null) continue;
// 计算XZ平面距离(使用你的 ReflectVectorXOZ 方法)
float dis = Vector3.Distance(
enemy.transform.position.ReflectVectorXOZ(),
playerAi.position.ReflectVectorXOZ()
);
if (dis < minDis)
{
nearestPlayer = enemy.gameObject;
minDis = dis;
}
}
return nearestPlayer;
}
public void ChangePlayerAiCountdownTime()
{
foreach (var ai in PlayerAiList.Values)
{
ai.ChangeKillEnemyTime();
}
}
public Transform GetPlayerPos()
{
int rand = Random.Range(0, 100);
if (players.Count >= 2) // 双人模式
{
if (rand < 45) // 0-44
return players[0].transform; // 玩家A
else if (rand < 90) // 45-89
return players[1].transform; // 玩家B
else // 90-99
return PlayerAiList[0].transform; // 队友A
}
else // 单人模式
{
if (rand < 60) // 0-59
return players[0].transform; // 玩家
else if (rand < 80) // 60-79
return PlayerAiList[0].transform; // 队友A
else // 80-99
return PlayerAiList[1].transform; // 队友B
}
}
[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(0);
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);
}
public bool IsHaveEnemy()
{
return EnemyList.Count > 0;
}
#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);
}
#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
}