using AX.InputSystem; using AX.MessageSystem; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.AI; [RequireComponent(typeof(NavMeshAgent))] public class AgentController : MonoBehaviour { private NavMeshAgent agent; private NavMeshPath NavMeshPath; private NavMeshQueryFilter filter; private Vector3 pointhit; private GameObject hitObj; public List corners = new List(); private Vector3 lastPosition; public bool pathFindEnable; public bool FixedArmFlag; private float speed; private float angularSpeed; public List TargetPoint = new List(); private void Awake() { pathFindEnable = true; agent = GetComponent(); speed = agent.speed; angularSpeed = agent.angularSpeed; MessageDispatcher.AddListener("ReplayEvent", ReplayAgent); MessageDispatcher.AddListener("ReplayEvent", ReplayCautionAreaTip); MessageDispatcher.AddListener("ReplayStatusChanged", ReplayStatusChanged); } void OnEnable() { MessageDispatcher.AddListener("PATH_FINDING_COMMAND", PathFinding); } void OnDisable() { MessageDispatcher.RemoveListener("PATH_FINDING_COMMAND", PathFinding); } void OnDestroy() { MessageDispatcher.RemoveListener("PATH_FINDING_COMMAND", PathFinding); MessageDispatcher.RemoveListener("ReplayEvent", ReplayAgent); MessageDispatcher.RemoveListener("ReplayEvent", ReplayCautionAreaTip); MessageDispatcher.RemoveListener("ReplayStatusChanged", ReplayStatusChanged); } private void ReplayStatusChanged(IMessage obj) { //if (!agent.isOnNavMesh) // return; var Status = (ReplayStatus)obj.Data; switch (Status) { case ReplayStatus.normal: if (agent.isOnNavMesh && agent.isStopped) { agent.isStopped = false; } break; case ReplayStatus.pause: if (agent.isOnNavMesh && !agent.isStopped) { agent.isStopped = true; } break; case ReplayStatus.over: break; default: break; } } public void Stop() { corners.Clear(); StopAllCoroutines(); agent.SetDestination(this.transform.position); } void Start() { NavMeshPath = new NavMeshPath(); filter = new NavMeshQueryFilter { agentTypeID = agent.agentTypeID, areaMask = agent.areaMask }; if (GetComponent()) { NavMesh.CalculatePath(transform.position, transform.position, filter, NavMeshPath); Vector3[] b = NavMeshPath.corners; if (b.Length < 1) { agent.enabled = false; } else { agent.enabled = true; } } } //check for mouse input void Update() { } IEnumerator ReplayEventWaitPosition(Vector3 pos) { yield return new WaitForEndOfFrame(); agent.SetDestination(pos); } private void ReplayAgent(IMessage obj) { var eventData = (EventData)obj.Data; if (eventData.eventType == RecordEventType.Agent) { var data = JsonUtility.FromJson(eventData.json); if (data.GameId == GetComponent().GameObjID) { //MessageDispatcher.AddListener("ReplayStatusChanged", ReplayStatusChanged); ReplayManager_ChangeReplaySpeed(GlobalVariable.ReplaySpeed); ReplayManager.ChangeReplaySpeed += ReplayManager_ChangeReplaySpeed; if (agent && agent.isOnNavMesh) { agent.SetDestination(data.TargetPoint); } //else //{ // StartCoroutine(ReplayEventWaitPosition(data.TargetPoint)); // } } } } private void ReplayManager_ChangeReplaySpeed(int obj) { if (agent) { agent.speed = speed * GlobalVariable.ReplaySpeed; agent.angularSpeed = angularSpeed * GlobalVariable.ReplaySpeed; } } private void PathFinding(IMessage obj) { if (SelectedObjs.selectedCharacters.Contains(gameObject) || SelectedObjs.selectedObj == gameObject) { if (pathFindEnable && !FixedArmFlag) { var data = (PathFindingCmdArgs)obj.Data; pointhit = data.hitPoint; StopAllCoroutines(); corners.Clear(); bool flag = setPathCorners(transform.position, pointhit, corners); if (flag) { // pointerObj.transform.position = pointhit; hitObj = EntitiesManager.Instance.GetEntityByID(data.gameObjID); //setFloorMessage(hitObj.transform); removeNoMainCorners(corners); StartCoroutine(GoToDestination()); var objinfo = GetComponent(); //if (objinfo.gameObjType != CloneObjType.fireman && objinfo.gameObjType != CloneObjType.ObligationFireman) //{ // MessageDispatcher.SendMessage(GetComponent().GameObjID, "SetpathIndex"); //} if (tag == "Player") { //先判断:是否进入警戒区 // checkEnterCautionArea(pointhit); FireManMessage mess = GetComponent(); //GetComponent().setLine(); if (mess.workType == FireManSkills.LayLifeSavingFlarePath || mess.workType == FireManSkills.LayWaterHose || mess.workType == FireManSkills.SprayFoam || mess.workType == FireManSkills.SprayWater || mess.workType == FireManSkills.Decontamination) { GetComponent().setPath(corners.ToArray()); } } } else ResourceLoadWindow.Instance.LoadTextHintWindow("不能抵达", 1f); } else { ResourceLoadWindow.Instance.LoadTextHintWindow("不能移动", 1f); } } } public static event Func checkCautionAreaEntering; private void checkEnterCautionArea(Vector3 pointhit) { IntData data = new IntData(0); if(checkCautionAreaEntering != null) data = checkCautionAreaEntering(pointhit, data); if (data.value > 0) { string warning = ""; //即将进入警戒区,判断是否按要求装备 Bag bag = GetComponent(); bool detectEquiped = false; //是否携带侦测类仪器 bool breathEquiped = false; //是否装备空呼 bool clothEquiped = false; //是否装备防化服 bool phoneEquiped = false; //是否装备对讲机 foreach(Equip equip in bag.EquipList) { if (equip.Name == "有毒气体探测仪") { detectEquiped = true; } if (equip.Name == "正压式空气呼吸器") { breathEquiped = true; } if (equip.Name.Contains("防化服")) { clothEquiped = true; } if (equip.Name.Contains("通信")) { phoneEquiped = true; } } if(detectEquiped && breathEquiped && clothEquiped && phoneEquiped) { //如果按要求装备,就不提示 return; } else { warning += "即将进入警戒区,但未按要求装备:\n"; if (!detectEquiped) warning += "有毒气体探测仪"; if (!breathEquiped) warning += " 空气呼吸器"; if (!clothEquiped) warning += " 防化服"; if (!phoneEquiped) warning += " 通信设备"; ResourceLoadWindow.Instance.LoadTipWindow(warning, () => { }, null); AddCautionAreaTipEvent(warning); } } } private void AddCautionAreaTipEvent(string warning) { if (ReplaySetting.PlayStatus == PlayStatus.isEditor && RecordManager.Instance.recordStatus == RecordStatus.normal) { var eventData = new EventData(); eventData.time = RecordManager.Instance.RecordTimer; eventData.cloneObjType = GetComponent().gameObjType; eventData.eventType = RecordEventType.CautionAreaTip; CautionAreaTipData data = new CautionAreaTipData(); data.gameObjID = GetComponent().gameObjID; data.warning = warning; eventData.json = JsonUtility.ToJson(data); RecordManager.Instance.jsonData.eventDataList.Add(eventData); } } private void ReplayCautionAreaTip(IMessage obj) { var eventData = (EventData)obj.Data; if (eventData.eventType == RecordEventType.CautionAreaTip) { CautionAreaTipData data = JsonUtility.FromJson(eventData.json); if (data.gameObjID == GetComponent().gameObjID) { ResourceLoadWindow.Instance.LoadTextHintWindow(data.warning, Mathf.Clamp(2/ GlobalVariable.ReplaySpeed,1,2)); } } } bool ArriveFlag(Vector3 transformpos, Vector3 pointhit) { // StopAllCoroutines(); // corners.Clear(); return setPathCorners(transformpos, pointhit, corners); } public void AutoPathFinding(List TargetPoint) { if (pathFindEnable && !FixedArmFlag) StartCoroutine(PathFinding(TargetPoint)); } IEnumerator PathFinding(List TargetPoint) { this.TargetPoint = TargetPoint; StopAllCoroutines(); corners.Clear(); int a = 0; while (a < TargetPoint.Count) { if (a == 0) ArriveFlag(transform.position, TargetPoint[a]); else ArriveFlag(TargetPoint[a - 1], TargetPoint[a]); //if (ArriveFlag(transform.position, TargetPoint[a])) // StartCoroutine(GoToDestination()); //// ArriveFlag(transform.position, TargetPoint[a]); a++; } if (a == TargetPoint.Count) { removeNoMainCorners(corners); StartCoroutine(GoToDestination()); yield return true; } } public static List LiSan(Vector3 center, int count, Vector3 size) { List list = new List(); int num = 1; while (list.Count < count) { var tagent = new Vector3(center.x, center.y, center.z + size.z * num); if (InNavMesh(center, tagent)) list.Add(tagent); else { if (Vector3.Distance(center, tagent) >= (count + 3) * size.z) break; } num++; } num = 1; while (list.Count < count) { var tagent = new Vector3(center.x, center.y, center.z - size.z * num); if (InNavMesh(center, tagent)) list.Add(tagent); else { if (Vector3.Distance(center, tagent) >= (count + 3) * size.z) break; } num++; } num = 1; while (list.Count < count) { var tagent = new Vector3(center.x + size.x * num, center.y, center.z); if (InNavMesh(center, tagent)) list.Add(tagent); else { if (Vector3.Distance(center, tagent) >= (count + 3) * size.x) break; } num++; } num = 1; while (list.Count < count) { var tagent = new Vector3(center.x - size.x * num, center.y, center.z); if (InNavMesh(center, tagent)) list.Add(tagent); else { if (Vector3.Distance(center, tagent) >= (count + 3) * size.x) break; } num++; } return list; } public static bool InNavMesh(Vector3 center, Vector3 tagent) { NavMeshHit hit; NavMeshQueryFilter filter = new NavMeshQueryFilter(); filter.agentTypeID = 0; filter.areaMask = 1; NavMesh.Raycast(center, tagent, out hit, filter); return hit.mask == filter.areaMask; } EventData eventData; //loops over path positions, sets the //current target destination of this agent IEnumerator GoToDestination() { int i = 1; while (i < corners.Count) { NavMeshPath NavMeshPath = new NavMeshPath(); NavMesh.CalculatePath(transform.position, corners[i], filter, NavMeshPath); if (RecordEvent.IsRecord()) { /* eventData = RecordEvent.CreateLinearEventData(CloneObjType.None, RecordEventType.LinearData);*///GetComponent().gameObjType AgentRecordData AgentRecordData = new AgentRecordData { TargetPoint = corners[i], GameId = GetComponent().GameObjID }; //RecordEvent.AddLinearEventData(eventData, GetComponent().GameObjID, JsonUtility.ToJson(AgentRecordData)); eventData = RecordEvent.AddEventData(CloneObjType.None, RecordEventType.Agent, JsonUtility.ToJson(AgentRecordData)); } agent.SetDestination(corners[i]); while (agent.pathPending) yield return null; //wait until we reached this position float remain = Vector3.Distance(transform.position, corners[i]); while (remain == Mathf.Infinity || remain - agent.stoppingDistance > float.Epsilon) { remain = Vector3.Distance(transform.position, corners[i]); if (RecordEvent.IsRecord())//正在寻路开记录节点 if (eventData == null) { AgentRecordData AgentRecordData = new AgentRecordData { TargetPoint = corners[i], GameId = GetComponent().GameObjID }; eventData = RecordEvent.AddEventData(CloneObjType.None, RecordEventType.Agent, JsonUtility.ToJson(AgentRecordData)); } //if (RecordEvent.IsRecordPause())//记录暂定 停止寻路 //{ // agent.isStopped = true; //} //else //{ // if (RecordEvent.IsRecord() && agent.isStopped) // { // agent.isStopped = false; // eventData = null; // } //} yield return null; } if (eventData != null) { eventData = null; } var objinfo = GetComponent(); if (objinfo.gameObjType == CloneObjType.FireMan) { setFloorMessage(); } else if (objinfo.GetComponent()) { setFloorMessage(false); } i++; } if (i == corners.Count) { corners.Clear(); yield return true; } } private void setFloorMessage(bool isFireman = true) { //璁剧疆瀵昏矾瀵硅薄妤煎眰灞炴€? Vector3 adPos2 = transform.position; Ray ray = new Ray(adPos2 + Vector3.up, Vector3.down); RaycastHit hit = new RaycastHit(); if (isFireman) { if (Physics.Raycast(ray, out hit, 1000, LayerMask.GetMask("ManRode", "CarRode"))) { if (hit.transform.gameObject.GetComponent()) { CloneGameObjInfo msg = GetComponent(); CloneGameObjInfo hitinfo = hit.transform.gameObject.GetComponent(); msg.buildNum = hitinfo.buildNum; msg.floorNum = hitinfo.floorNum; msg.interlayerNum = hitinfo.interlayerNum; //msg.inOutType = hitinfo.inOutType; if (!SelectedObjs.selectedCharacters.Contains(gameObject)) { msg.UpdateFloorEnabled(GlobalVariable.CurrentFloor); } return; } } } else { if (Physics.Raycast(ray, out hit, LayerMask.NameToLayer("CarRoad"))) { if (hit.transform.gameObject.GetComponent()) { CloneGameObjInfo msg = GetComponent(); CloneGameObjInfo hitinfo = hit.transform.gameObject.GetComponent(); msg.buildNum = hitinfo.buildNum; msg.floorNum = hitinfo.floorNum; msg.interlayerNum = hitinfo.interlayerNum; return; } } } } bool setPathCorners(Vector3 sourcePosition, Vector3 targetPosition, List corners) { NavMeshPath NavMeshPath = new NavMeshPath(); NavMesh.CalculatePath(sourcePosition, targetPosition, filter, NavMeshPath); Vector3[] b = NavMeshPath.corners; if (b.Length == 1) { //Debug.Log("断裂"); return false; } if (NavMeshPath.status == NavMeshPathStatus.PathComplete) { //Debug.Log("PathComplete"); foreach (Vector3 corner in b) { if (!corners.Contains(corner)) { corners.Add(corner); } } return true; } else if (NavMeshPath.status == NavMeshPathStatus.PathPartial) { if (Vector3.Distance(b[b.Length - 1], lastPosition) == 0) { //Debug.Log("(" + sourcePosition.x + "," + sourcePosition.y + "," + sourcePosition.z + ")、(" + lastPosition.x + "," + lastPosition.y + "," + lastPosition.z + ")"); //Debug.Log("进入死循环"); return false; } foreach (Vector3 corner in b) { if (!corners.Contains(corner)) { corners.Add(corner); } } lastPosition = sourcePosition; return setPathCorners(b[b.Length - 1], targetPosition, corners); } else if (NavMeshPath.status == NavMeshPathStatus.PathInvalid) { return false; } else { return false; } } void removeNoMainCorners(List corners) { for (int i = 0; i < corners.Count - 1; i++) { for (int k = corners.Count - 2; k > i; k--) { float distance = Vector3.Distance(corners[i], corners[k]);//计算两点的距离 if (distance < 5) { for (int j = k; j > i; j--) { corners.RemoveAt(j); } break; } } } } }