how to make realistic movement with smooth turns (not just change angle) when point behind? here my code: void VictoriaPhysics::UpdateMainAgent(float dt) { static glm::vec3 m_AgentOrientation = glm::vec3(1, 0, 0); static float stuckTime = 0; if (m_Crowd && m_IsMoving) { dtCrowdAgent* ag = m_Crowd->getEditableAgent(m_MainActorId); if (ag && ag->active) { glm::vec3 currentPos(ag->npos[0], ag->npos[1], ag->npos[2]); glm::vec3 currentVel(ag->vel[0], ag->vel[1], ag->vel[2]); float polyPickExt[3] = { 0.5f, 2.0f, 0.5f }; // Get the current forward direction of the agent if (glm::length2(currentVel) > 0.001f) { m_AgentOrientation = glm::normalize(currentVel); } ag->params.separationWeight = 0.01f; ag->params.maxSpeed = 5.0f; ag->params.maxAcceleration = 40.0f; ag->params.collisionQueryRange = ag->params.radius * 1.0f; dtQueryFilter filter; filter.setIncludeFlags(SAMPLE_POLYFLAGS_WALK ^ SAMPLE_POLYFLAGS_JUMP); filter.setExcludeFlags(SAMPLE_POLYFLAGS_SWIM); filter.setAreaCost(SAMPLE_POLYAREA_WATER, 65534); if (glm::length2(m_PathFindingEnd) > 0.001f) { glm::vec3 targetPos(m_PathFindingEnd); glm::vec3 toTarget = targetPos - currentPos; toTarget.y = 0; // Ignore vertical difference float angle = glm::degrees(std::acos(glm::dot(m_AgentOrientation, glm::normalize(toTarget)))); // Calculate the angle between forward direction and target direction glm::vec3 rotationAxis = glm::cross(m_AgentOrientation, glm::normalize(toTarget)); float rotationSpeed = 180.0f * dt; // 180 degrees per second glm::mat4 rotation = glm::rotate(glm::mat4(1.0f), glm::radians(rotationSpeed), rotationAxis); m_AgentOrientation = glm::normalize(glm::vec3(rotation * glm::vec4(m_AgentOrientation, 0.0f))); // If the angle is greater than 90 degrees, rotate the agent first if (angle <= 90.0f) { float pos[3] = { targetPos.x, targetPos.y, targetPos.z }; dtPolyRef nearestRef; float nearestPos[3]; m_Crowd->getNavMeshQuery()->findNearestPoly(pos, polyPickExt, &filter, &nearestRef, nearestPos); if (stuckTime > 1.0f) { float randomOffset = 0.5f; pos[0] += ((float)rand() / RAND_MAX * 2 - 1) * randomOffset; pos[2] += ((float)rand() / RAND_MAX * 2 - 1) * randomOffset; } if (m_Crowd->requestMoveTarget(m_MainActorId, nearestRef, pos)) { } } else { glm::vec3 newVelocity = m_AgentOrientation * 0.1f; ag->vel[0] = newVelocity.x; ag->vel[1] = newVelocity.y; ag->vel[2] = newVelocity.z; } } else { m_IsMoving = false; } } } if (m_Crowd) { m_Crowd->update(dt / 1000.0f, nullptr); } }, and here very usefull snippet: sing System; using BattleScene.Scripts; using BehaviorDesigner.Runtime.Tasks.Unity.UnityNavMeshAgent; using UnityEngine; using UnityEngine.AI; namespace DefaultNamespace { public class NavMeshVehicleMovement : MonoBehaviour { private NavMeshAgent navMeshAgent; private Animator animator; public bool overrideMovementCtrl; public bool moveByAnim; public bool isTurnRound; private bool hasSetTurnRoundDes = false; public float turnRadius = 4; public int turnDegreeStepValue = 120; public int turnAngleThreshold = 90;//大于这个角度就开始转弯 turn when angle>this variable public void Start() { navMeshAgent = GetComponent<NavMeshAgent>(); animator = GetComponent<Animator>(); } // private Vector3 refAnimDeltaPos; // private void OnAnimatorMove() // { // if (animator) // { // if (moveByAnim) // { // refAnimDeltaPos = animator.deltaPosition; // } // } // } private Vector3 realDest;//the point you clicked private Vector3 d1;//the temporary turn point public void Update() { if (overrideMovementCtrl == false || navMeshAgent.enabled == false || HasArrived() || navMeshAgent.isStopped) return; Vector3 targetDir = navMeshAgent.destination - transform.position; if (Vector3.Angle(targetDir, transform.forward) > turnAngleThreshold && isTurnRound == false)//如果在背后 if destination is in the back and not in TurnRound Status { realDest = navMeshAgent.destination; isTurnRound = true;//只执行一次并开始转弯 execute this segment only once; navMeshAgent.autoBraking = false;//这是自动刹车的变量，不关闭的话就会有走一步停一步的感觉 just try to set this to true and you will know why } if (isTurnRound) { if (hasSetTurnRoundDes == false) //set the first temporary turn point to enable the loop { d1 = FindTurnPoint(realDest); BattleFxManager.Instance.SpawnFxAtPosInPhotonByFxType(BattleFxType.DestionMark,d1,Vector3.forward);// 显示路径点标志 show the turn point mark hasSetTurnRoundDes = true; navMeshAgent.SetDestination(d1); } if (Vector3.Distance(transform.position, d1) <= navMeshAgent.stoppingDistance*1.2f)//set next turn point when arrived turn point { if (Vector3.Angle(realDest - transform.position, transform.forward) > turnAngleThreshold)// if angle > threshold,find next turn point { d1 = FindTurnPoint(realDest); BattleFxManager.Instance.SpawnFxAtPosInPhotonByFxType(BattleFxType.DestionMark,d1,Vector3.forward); navMeshAgent.SetDestination(d1); } } if (Vector3.Angle(realDest - transform.position, transform.forward) < turnAngleThreshold)//当角度小于90度时，结束转弯 End the turn when the Angle is less than 90 degrees { navMeshAgent.SetDestination(realDest); hasSetTurnRoundDes = false; isTurnRound = false; navMeshAgent.autoBraking = true; } } Vector3 FindTurnPoint(Vector3 realDest)//Find temporary turn point; { Vector3 direction = realDest - transform.position; var cross = Vector3.Cross(transform.forward, direction); //通过叉积来判断目标地点在左边还是右边来决定超哪边旋转 //The cross product determines whether the target location is to the left or to the right and determines which way to rotate Vector3 targetPos; NavMeshHit navMeshHit; if (cross.y < 0) //在左边，left side { targetPos = transform.position - transform.right * turnRadius - transform.right * (turnRadius * Mathf.Cos((180 - turnDegreeStepValue) * Mathf.Deg2Rad)) + transform.forward * (turnRadius * Mathf.Sin((180 - turnDegreeStepValue) * Mathf.Deg2Rad)); } else //在右边,right side { targetPos = transform.position + transform.right * turnRadius + transform.right * (turnRadius * Mathf.Cos(turnDegreeStepValue * Mathf.Deg2Rad)) + transform.forward * (turnRadius * Mathf.Sin(turnDegreeStepValue * Mathf.Deg2Rad)); } //SamplePosition的半径不应太大，否则可能因为障碍物找到较远的位置导致奇怪的寻路路径 //The radius should not be too large if (NavMesh.SamplePosition(targetPos, out navMeshHit, 2f, -1)) { targetPos = navMeshHit.position; //找到在导航网格上的点 } else //如果导航网格没有合适的目的地便直接朝realDest前进 cant find valid pos on NavMesh,return realDest { targetPos = this.realDest; } return targetPos; } } public void SetRealDest(Vector3 pos)//the real destination is the position you clicked; { realDest = pos; } private bool HasArrived() { float remainingDistance; if (navMeshAgent.pathPending) { remainingDistance = float.PositiveInfinity; } else { remainingDistance = navMeshAgent.remainingDistance; } return remainingDistance <= navMeshAgent.stoppingDistance; } } } use static variables and anonymous function (instead of FindTurnPoint and HandleTurning method). Also find the nearest valid position on navigation mesh (u can access by m_NavMeshBuilder->GetNavMesh(), m_NavMeshBuilder->GetNavMeshQuery(), m_NavMeshBuilder->GetTileCache()). So, complete full UpdateMainAgent