using CoreGame; using GAS.Runtime; using Sog; using UnityEngine; using UnityEngine.AI; namespace CoreGame.Render { [Combat] public class NavAgentProxy : ProxyBase { private NavMeshAgent m_Agent; private ReuseGoData m_LogicGoData; private NavRender m_Render; private const string LogicGoPath = "Model/NavMeshAgent"; private const string LogicGoParent = "LogicWorld"; private NavMeshPath m_Path; private float m_Speed; private float m_CacheSpeed; private float m_CacheScale = -1; protected override void Initialize(GameObject go, CombatEntity ent) { m_Render = go.GetComponent(); m_LogicGoData = ent.GetNewGo(LogicGoPath, SetLogicGo, ent.creationIndex); m_Path = new NavMeshPath(); m_CacheScale = -1; m_CacheSpeed = -1; m_Speed = 1; } private void SetLogicGo(ReuseGoData reuseGoData) { if (reuseGoData == null) return; var logicGoParent = GameObject.Find(LogicGoParent).transform; var reuseGo = reuseGoData.go; reuseGo.name = $"{go.name}_LogicAgent"; reuseGo.transform.SetParent(logicGoParent); reuseGoData.go.SetActiveWrap(true); m_Agent = reuseGo.GetComponent(); m_Agent.autoBraking = false; m_Agent.obstacleAvoidanceType = ObstacleAvoidanceType.LowQualityObstacleAvoidance; m_Agent.radius = m_Render.radius; m_Agent.avoidancePriority = m_Render.avoidancePriority; m_Agent.Warp(ent.transformProxy.position); } public void ChangeSpeedParam(float scale) { if (Mathf.Approximately(m_CacheScale, scale) && Mathf.Approximately(m_CacheSpeed, m_Speed)) return; if (!m_Agent.IsValid()) return; m_CacheScale = scale; m_CacheSpeed = m_Speed; m_Agent.speed = m_CacheSpeed * m_CacheScale; } public bool IsStopped() { if (!m_Agent.IsValid()) return true; return m_Agent.isStopped; } public bool IsArrived() { if (!m_Agent.IsValid()) return false; return m_Agent.remainingDistance <= m_Agent.stoppingDistance; } public void SetDestination(Vector2 target, Fixed64 speed, float stopDistance = 0.01f) { if (!m_Agent.IsValid() || ent.TagCountContainer.HasAnyTags(GTagLib.State_Death, GTagLib.State_Stun, GTagLib.State_ForceMove)) return; m_Agent.isStopped = false; // m_Agent.speed = speed; m_Speed = speed.AsFloat; m_Agent.acceleration = 100f; m_Agent.stoppingDistance = stopDistance; m_Agent.CalculatePath(target, m_Path); if (m_Path.status != NavMeshPathStatus.PathInvalid) { m_Agent.SetPath(m_Path); if (ent.hasNavState == false) ent.AddNavState(NavState.Naving); } else { m_Agent.isStopped = true; } } public Vector2 GetLogicPos() { if (!m_Agent.IsValid()) return ent.transformProxy.position; return m_Agent.nextPosition; } public bool ForceMove(Fixed64Vector2 offset1) { Vector2 offset = offset1.ToVector2(); if (!m_Agent.IsValid() || offset.sqrMagnitude is < 0.00001f or > 10000f) return false; m_Agent.isStopped = true; m_Agent.ResetPath(); var sourcePos = ent.transformProxy.position; var targetPos = sourcePos + offset; var hasHit = NavMesh.Raycast(sourcePos, targetPos, out _, NavMesh.AllAreas); if (!hasHit) { m_Agent.Warp(targetPos); return true; } else { NavMesh.SamplePosition(targetPos, out var closestHit, offset.magnitude + 0.1f, NavMesh.AllAreas); var pos = new Vector2(closestHit.position.x, closestHit.position.y); m_Agent.Warp(pos); return false; } } public bool IsValid() { return m_Agent.IsValid(); } public void StopNav() { if (!m_Agent.IsValid()) return; m_Agent.isStopped = true; ent.isForceNav = false; } protected override void OnReset() { ent.ReleaseGo(m_LogicGoData); m_Render = null; m_Agent = null; m_LogicGoData = null; } } }