IEnumerator <float> MoveAlongPath(BaseUnit unit, ABPath path, float speed) { if (path.error || path.vectorPath.Count == 0) { throw new ArgumentException("Cannot follow an empty path"); } PreMoveUnit = unit; Callback_OnMoveStart?.Invoke(unit); // Very simple movement, just interpolate using a catmull rom spline float distanceAlongSegment = 0; for (int i = 0; i < path.vectorPath.Count - 1; i++) { var p0 = path.vectorPath[Mathf.Max(i - 1, 0)]; // Start of current segment var p1 = path.vectorPath[i]; // End of current segment var p2 = path.vectorPath[i + 1]; var p3 = path.vectorPath[Mathf.Min(i + 2, path.vectorPath.Count - 1)]; var segmentLength = Vector3.Distance(p1, p2); while (distanceAlongSegment < segmentLength) { var interpolatedPoint = MathUtil.CatmullRom(p0, p1, p2, p3, distanceAlongSegment / segmentLength); var targetRot = Quaternion.LookRotation((p2 - p1).SetY(0), Vector3.up); unit.Rot = Quaternion.Slerp(unit.Rot, targetRot, Time.deltaTime * 10); unit.transform.position = interpolatedPoint; Callback_OnMovingAlone?.Invoke(unit, p0, p1, p2, p3); yield return(Timing.WaitForOneFrame); distanceAlongSegment += Time.deltaTime * speed; } distanceAlongSegment -= segmentLength; } Vector3 target = path.vectorPath[path.vectorPath.Count - 1]; unit.Pos = target; Callback_OnMoveEnd?.Invoke(unit); }
protected override IEnumerator <float> OnFollowPathCoroutine() { IsMovingFlag = false; //是否为第一段移动 bool isFirstMoved = false; //当前已经走过的路段 float distanceAlongSegment = 0; //当前路段长度 var segmentLength = 0.0f; //节点的大小 float nodeSize = AStarMgr.Ins.data.gridGraph.nodeSize; //最大可以移动的距离 float maxMoveDistance = nodeSize * MaxMovePoint; //已经移动的距离 float movedDistance = 0; var moveStep = Time.smoothDeltaTime * RealMoveSpeed; IsForceBreak = false; IsFinalPosMove = false; for (int i = 0; i < ABPath.vectorPath.Count - 1; i++) { CurIndex = i; var p1 = ABPath.vectorPath[i]; var p2 = ABPath.vectorPath[i + 1]; segmentLength = Vector3.Distance(p1, p2); if (CurMovePoint <= segmentLength) { p2 = (Vector3)AStarMgr.GetSafeNode(p2).position;; } while (IsHaveMoveSegment() && !IsForceBreak) { if (CurMovePoint < nodeSize && MathUtil.Approximately(SelfBaseUnit.Pos, p2)) { IsForceBreak = true; } else { LerpMove(p1, p2, 1, true, false); } yield return(Timing.WaitForOneFrame); if (!isFirstMoved) { isFirstMoved = true; Callback_OnFirstMovingAlone?.Invoke(); } } distanceAlongSegment -= segmentLength; OnMoveStep(movedDistance, maxMoveDistance, nodeSize, segmentLength); CurIndex++; if (!IsCanMove || IsForceBreak) { break; } } //计算最后的安全落点 yield return(Timing.WaitUntilDone(FinalPosMove())); if (CurMovePoint < 1) { CurMovePoint = 0; } IsMovingFlag = true; Callback_OnMoveDestination?.Invoke(); StopPath(); //最后位置点的矫正 IEnumerator <float> FinalPosMove() { IsFinalPosMove = true; Vector3 startPos = SelfBaseUnit.Pos; var finalPos = GetFinalPos(startPos); if (MathUtil.Approximately(startPos, finalPos)) { yield break; } //将单位移动到最终的目标节点 distanceAlongSegment = 0; segmentLength = Vector3.Distance(startPos, finalPos); while (IsHaveMoveSegment()) { LerpMove(startPos, finalPos, 1, segmentLength > nodeSize, true); yield return(Timing.WaitForOneFrame); } SelfBaseUnit.Pos = finalPos; //如果目标无效,进入递归 if (!MathUtil.Approximately(finalPos, GetFinalPos(SelfBaseUnit.Pos))) { yield return(Timing.WaitUntilDone(FinalPosMove())); } IsForceBreak = false; IsFinalPosMove = false; } bool LerpMove(Vector3 p1, Vector3 p2, float speedMul = 1.0f, bool isRot = true, bool isFinalCorrect = false) { float aiSpeedMul = 1; if (BaseGlobal.FOWMgr != null && BaseGlobal.FOWMgr.IsInFog(p2) && SelfBaseUnit != null && SelfBaseUnit.IsAI() && SelfBaseUnit.FOWMgr != null && !SelfBaseUnit.FOWMgr.IsVisible && !SelfBaseUnit.FOWMgr.IsPreVisible) { aiSpeedMul = 10; } if (!isFinalCorrect && IsForceBreak) { return(false); } var tempMoveStep = moveStep * speedMul * aiSpeedMul; var interpolatedPoint = Vector3.Lerp(p1, p2, distanceAlongSegment / segmentLength); var targetRot = Quaternion.LookRotation((p2 - p1).SetY(0), Vector3.up); if (isRot) { SelfBaseUnit.Rot = Quaternion.Slerp(SelfBaseUnit.Rot, targetRot, tempMoveStep); } bool isValid = OnPreLerpMoveAlone(interpolatedPoint, tempMoveStep, movedDistance, maxMoveDistance, nodeSize, segmentLength, isFinalCorrect); if (!isValid) { return(false); } SelfBaseUnit.Pos = interpolatedPoint; movedDistance += tempMoveStep; distanceAlongSegment += tempMoveStep; OnLerpMoveAlone(tempMoveStep, movedDistance, maxMoveDistance, nodeSize, segmentLength, isFinalCorrect); Callback_OnMovingAlone?.Invoke(); return(true); } //是否有移动的路段 bool IsHaveMoveSegment() { return(distanceAlongSegment < segmentLength); } }