1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| using System.Collections.Generic; using UnityEngine;
public class ArcMove : MonoBehaviour { public float TurnTriggerDistance = 5f; public float MoveSpeed = 20f;
private float _angularSpeed = 0f; private float _remainingTurnTime = 0f; private int _currentNodeIndex = 0;
private List<Vector3> _route = new() { new Vector3(10,0,-10), new Vector3(-10,0,-10), new Vector3(10,0, 0), new Vector3(10,0,10), new Vector3(-10,0,10), };
private void Start() => ResetState();
void Update() { var curPos = transform.position; if (_remainingTurnTime <= 0 && _currentNodeIndex == _route.Count - 2) { var curPoint = _route[_currentNodeIndex]; var arrivePoint = _route[_currentNodeIndex + 1]; if (Vector3.Dot(arrivePoint - curPoint, arrivePoint - curPos) < 0) ResetState(); } if (_remainingTurnTime > 0) { _remainingTurnTime -= Time.deltaTime; if (_remainingTurnTime <= 0) _angularSpeed = 0; } else { var haveNextPoint = _currentNodeIndex + 1 < _route.Count; var haveNextNextPoint = _currentNodeIndex + 2 < _route.Count; var handled = false; if (haveNextNextPoint) { var curPoint = _route[_currentNodeIndex]; var nextPoint = _route[_currentNodeIndex + 1]; var nextNextPoint = _route[_currentNodeIndex + 2]; var inVector = nextPoint - curPoint; var outVector = nextNextPoint - nextPoint; var clampTurnTriggerDistance = Mathf.Min(TurnTriggerDistance, Mathf.Min(inVector.magnitude, outVector.magnitude) / 2); var nowRemainDist = (curPos - nextPoint).magnitude; if (nowRemainDist <= clampTurnTriggerDistance) { ++_currentNodeIndex; handled = true; var angle = Vector3.SignedAngle(inVector.normalized, outVector.normalized, Vector3.up); var absoluteAngle = Mathf.Abs(angle); if (absoluteAngle < 1f) return; var inCircleRadius = nowRemainDist / Mathf.Tan(absoluteAngle * Mathf.Deg2Rad / 2); var arcLength = 2 * Mathf.PI * inCircleRadius * absoluteAngle / 360; _remainingTurnTime = arcLength / MoveSpeed; _angularSpeed = angle / _remainingTurnTime; } } if (haveNextPoint && !handled) { var curDir = transform.rotation * Vector3.forward; var targetDir = _route[_currentNodeIndex + 1] - curPos; var diffAngle = Vector3.SignedAngle(curDir.normalized, targetDir.normalized, Vector3.up); _angularSpeed = diffAngle * MoveSpeed; } }
transform.rotation *= Quaternion.Euler(0, _angularSpeed * Time.deltaTime, 0); transform.position = transform.position + MoveSpeed * Time.deltaTime * transform.forward; }
private void ResetState() { _currentNodeIndex = 0; transform.SetPositionAndRotation(_route[_currentNodeIndex], Quaternion.LookRotation(_route[1] - _route[0])); } }
|