summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/LocalAvoidance/RVOExampleAgent.cs
diff options
context:
space:
mode:
authorchai <215380520@qq.com>2024-05-23 10:08:29 +0800
committerchai <215380520@qq.com>2024-05-23 10:08:29 +0800
commit8722a9920c1f6119bf6e769cba270e63097f8e25 (patch)
tree2eaf9865de7fb1404546de4a4296553d8f68cc3b /Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/LocalAvoidance/RVOExampleAgent.cs
parent3ba4020b69e5971bb0df7ee08b31d10ea4d01937 (diff)
+ astar project
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/LocalAvoidance/RVOExampleAgent.cs')
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/LocalAvoidance/RVOExampleAgent.cs186
1 files changed, 186 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/LocalAvoidance/RVOExampleAgent.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/LocalAvoidance/RVOExampleAgent.cs
new file mode 100644
index 0000000..d1f5de7
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/LocalAvoidance/RVOExampleAgent.cs
@@ -0,0 +1,186 @@
+using UnityEngine;
+using System.Collections.Generic;
+using Pathfinding.RVO;
+
+namespace Pathfinding.Examples {
+ /// <summary>
+ /// Example movement script for using RVO.
+ ///
+ /// Primarily intended for the example scenes.
+ /// You can use the AIPath or RichAI movement scripts in your own projects.
+ ///
+ /// See: <see cref="Pathfinding.AIPath"/>
+ /// See: <see cref="Pathfinding.RichAI"/>
+ /// See: <see cref="Pathfinding.RVO.RVOController"/>
+ /// </summary>
+ [RequireComponent(typeof(RVOController))]
+ [RequireComponent(typeof(Seeker))]
+ [HelpURL("https://arongranberg.com/astar/documentation/stable/rvoexampleagent.html")]
+ public class RVOExampleAgent : MonoBehaviour {
+ public float repathRate = 1;
+
+ private float nextRepath = 0;
+
+ private Vector3 target;
+ private bool canSearchAgain = true;
+
+ private RVOController controller;
+ public float maxSpeed = 10;
+
+ Path path = null;
+
+ List<Vector3> vectorPath;
+ int wp;
+
+ public float moveNextDist = 1;
+ public float slowdownDistance = 1;
+ public LayerMask groundMask;
+
+ Seeker seeker;
+
+ MeshRenderer[] rends;
+
+ public void Awake () {
+ seeker = GetComponent<Seeker>();
+ controller = GetComponent<RVOController>();
+ }
+
+ /// <summary>Set the point to move to</summary>
+ public void SetTarget (Vector3 target) {
+ this.target = target;
+ RecalculatePath();
+ }
+
+ /// <summary>Animate the change of color</summary>
+ public void SetColor (Color color) {
+ if (rends == null) rends = GetComponentsInChildren<MeshRenderer>();
+ foreach (var rend in rends) {
+ StartCoroutine(AnimateColor(rend, rend.material.GetColor("_Color"), color));
+ }
+ }
+
+ System.Collections.IEnumerator AnimateColor (MeshRenderer rend, Color startColor, Color endColor) {
+ float t = 0;
+
+ do {
+ t = Mathf.Min(1.0f, t + Time.deltaTime);
+ rend.material.SetColor("_Color", Color.Lerp(startColor, endColor, t));
+ yield return null;
+ } while (t < 1);
+ }
+
+ public void RecalculatePath () {
+ canSearchAgain = false;
+ nextRepath = Time.time+repathRate*(Random.value+0.5f);
+ seeker.StartPath(transform.position, target, OnPathComplete);
+ }
+
+ public void OnPathComplete (Path _p) {
+ ABPath p = _p as ABPath;
+
+ canSearchAgain = true;
+
+ if (path != null) path.Release(this);
+ path = p;
+ p.Claim(this);
+
+ if (p.error) {
+ wp = 0;
+ vectorPath = null;
+ return;
+ }
+
+
+ Vector3 p1 = p.originalStartPoint;
+ Vector3 p2 = transform.position;
+ p1.y = p2.y;
+ float d = (p2-p1).magnitude;
+ wp = 0;
+
+ vectorPath = p.vectorPath;
+ Vector3 waypoint;
+
+ if (moveNextDist > 0) {
+ for (float t = 0; t <= d; t += moveNextDist*0.6f) {
+ wp--;
+ Vector3 pos = p1 + (p2-p1)*t;
+
+ do {
+ wp++;
+ waypoint = vectorPath[wp];
+ } while (controller.To2D(pos - waypoint).sqrMagnitude < moveNextDist*moveNextDist && wp != vectorPath.Count-1);
+ }
+ }
+ }
+
+ public void Update () {
+ if (Time.time >= nextRepath && canSearchAgain) {
+ RecalculatePath();
+ }
+
+ Vector3 pos = transform.position;
+
+ if (vectorPath != null && vectorPath.Count > 1) {
+ while ((controller.To2D(pos - vectorPath[wp]).sqrMagnitude < moveNextDist*moveNextDist && wp != vectorPath.Count-1) || wp == 0) {
+ wp++;
+ }
+
+ // Current path segment goes from vectorPath[wp-1] to vectorPath[wp]
+ // We want to find the point on that segment that is 'moveNextDist' from our current position.
+ // This can be visualized as finding the intersection of a circle with radius 'moveNextDist'
+ // centered at our current position with that segment.
+ var p1 = vectorPath[wp-1];
+ var p2 = vectorPath[wp];
+
+ // Calculate the intersection with the circle. This involves some math.
+ var t = VectorMath.LineCircleIntersectionFactor(controller.To2D(transform.position), controller.To2D(p1), controller.To2D(p2), moveNextDist);
+ // Clamp to a point on the segment
+ t = Mathf.Clamp01(t);
+ Vector3 waypoint = Vector3.Lerp(p1, p2, t);
+
+ // Calculate distance to the end of the path
+ float remainingDistance = controller.To2D(waypoint - pos).magnitude + controller.To2D(waypoint - p2).magnitude;
+ for (int i = wp; i < vectorPath.Count - 1; i++) remainingDistance += controller.To2D(vectorPath[i+1] - vectorPath[i]).magnitude;
+
+ // Set the target to a point in the direction of the current waypoint at a distance
+ // equal to the remaining distance along the path. Since the rvo agent assumes that
+ // it should stop when it reaches the target point, this will produce good avoidance
+ // behavior near the end of the path. When not close to the end point it will act just
+ // as being commanded to move in a particular direction, not toward a particular point
+ var rvoTarget = (waypoint - pos).normalized * remainingDistance + pos;
+ // When within [slowdownDistance] units from the target, use a progressively lower speed
+ var desiredSpeed = Mathf.Clamp01(remainingDistance / slowdownDistance) * maxSpeed;
+ Debug.DrawLine(transform.position, waypoint, Color.red);
+ controller.SetTarget(rvoTarget, desiredSpeed, maxSpeed, vectorPath[vectorPath.Count-1]);
+ } else {
+ // Stand still
+ controller.SetTarget(pos, maxSpeed, maxSpeed, pos);
+ }
+
+ // Get a processed movement delta from the rvo controller and move the character.
+ // This is based on information from earlier frames.
+ var movementDelta = controller.CalculateMovementDelta(Time.deltaTime);
+ pos += movementDelta;
+
+ // Rotate the character if the velocity is not extremely small
+ if (Time.deltaTime > 0 && movementDelta.magnitude / Time.deltaTime > 0.01f) {
+ var rot = transform.rotation;
+ var targetRot = Quaternion.LookRotation(movementDelta, controller.To3D(Vector2.zero, 1));
+ const float RotationSpeed = 5;
+ if (controller.movementPlaneMode == MovementPlane.XY) {
+ targetRot = targetRot * Quaternion.Euler(-90, 180, 0);
+ }
+ transform.rotation = Quaternion.Slerp(rot, targetRot, Time.deltaTime * RotationSpeed);
+ }
+
+ if (controller.movementPlaneMode == MovementPlane.XZ) {
+ RaycastHit hit;
+ if (Physics.Raycast(pos + Vector3.up, Vector3.down, out hit, 2, groundMask)) {
+ pos.y = hit.point.y;
+ }
+ }
+
+ transform.position = pos;
+ }
+ }
+}