- WaypointProgressTracker.cs
- Utility /
- Standard Assets /
- Assets /
- project /
1 using System;
2 using UnityEngine;
3
4 namespace UnityStandardAssets.Utility
5 {
6 public class WaypointProgressTracker : MonoBehaviour
7 {
8 // This script can be used with any object that is supposed to follow a
9 // route marked out by waypoints.
10
11 // This script manages the amount to look ahead along the route,
12 // and keeps track of progress and laps.
13
14 [SerializeField] public WaypointCircuit circuit; // A reference to the waypoint-based route we should follow
15
16 [SerializeField] private float lookAheadForTargetOffset = 5;
17 // The offset ahead along the route that the we will aim for
18
19 [SerializeField] private float lookAheadForTargetFactor = .1f;
20 // A multiplier adding distance ahead along the route to aim for, based on current speed
21
22 [SerializeField] private float lookAheadForSpeedOffset = 10;
23 // The offset ahead only the route for speed adjustments (applied as the rotation of the waypoint target transform)
24
25 [SerializeField] private float lookAheadForSpeedFactor = .2f;
26 // A multiplier adding distance ahead along the route for speed adjustments
27
28 [SerializeField] private ProgressStyle progressStyle = ProgressStyle.SmoothAlongRoute;
29 // whether to update the position smoothly along the route (good for curved paths) or just when we reach each waypoint.
30
31 [SerializeField] private float pointToPointThreshold = 4;
32 // proximity to waypoint which must be reached to switch target to next waypoint : only used in PointToPoint mode.
33
34 public enum ProgressStyle
35 {
36 SmoothAlongRoute,
37 PointToPoint,
38 }
39
40 // these are public, readable by other objects - i.e. for an AI to know where to head!
41 public WaypointCircuit.RoutePoint targetPoint { get; private set; }
42 public WaypointCircuit.RoutePoint speedPoint { get; private set; }
43 public WaypointCircuit.RoutePoint progressPoint { get; private set; }
44
45 public Transform target;
46
47 private float progressDistance; // The progress round the route, used in smooth mode.
48 private int progressNum; // the current waypoint number, used in point-to-point mode.
49 private Vector3 lastPosition; // Used to calculate current speed (since we may not have a rigidbody component)
50 private float speed; // current speed of this object (calculated from delta since last frame)
51
52 // setup script properties
53 private void Start()
54 {
55 // we use a transform to represent the point to aim for, and the point which
56 // is considered for upcoming changes-of-speed. This allows this component
57 // to communicate this information to the AI without requiring further dependencies.
58
59 // You can manually create a transform and assign it to this component *and* the AI,
60 // then this component will update it, and the AI can read it.
61 if (target == null)
62 {
63 target = new GameObject(name + " Waypoint Target").transform;
64 }
65
66 Reset();
67 }
68
69
70 // reset the object to sensible values
71 public void Reset()
72 {
73 progressDistance = 0;
74 progressNum = 0;
75 if (progressStyle == ProgressStyle.PointToPoint)
76 {
77 target.position = circuit.Waypoints[progressNum].position;
78 target.rotation = circuit.Waypoints[progressNum].rotation;
79 }
80 }
81
82
83 private void Update()
84 {
85 if (progressStyle == ProgressStyle.SmoothAlongRoute)
86 {
87 // determine the position we should currently be aiming for
88 // (this is different to the current progress position, it is a a certain amount ahead along the route)
89 // we use lerp as a simple way of smoothing out the speed over time.
90 if (Time.deltaTime > 0)
91 {
92 speed = Mathf.Lerp(speed, (lastPosition - transform.position).magnitude/Time.deltaTime,
93 Time.deltaTime);
94 }
95 target.position =
96 circuit.GetRoutePoint(progressDistance + lookAheadForTargetOffset + lookAheadForTargetFactor*speed)
97 .position;
98 target.rotation =
99 Quaternion.LookRotation(
100 circuit.GetRoutePoint(progressDistance + lookAheadForSpeedOffset + lookAheadForSpeedFactor*speed)
101 .direction);
102
103
104 // get our current progress along the route
105 progressPoint = circuit.GetRoutePoint(progressDistance);
106 Vector3 progressDelta = progressPoint.position - transform.position;
107 if (Vector3.Dot(progressDelta, progressPoint.direction) < 0)
108 {
109 progressDistance += progressDelta.magnitude*0.5f;
110 }
111
112 lastPosition = transform.position;
113 }
114 else
115 {
116 // point to point mode. Just increase the waypoint if we're close enough:
117
118 Vector3 targetDelta = target.position - transform.position;
119 if (targetDelta.magnitude < pointToPointThreshold)
120 {
121 progressNum = (progressNum + 1)%circuit.Waypoints.Length;
122 }
123
124
125 target.position = circuit.Waypoints[progressNum].position;
126 target.rotation = circuit.Waypoints[progressNum].rotation;
127
128 // get our current progress along the route
129 progressPoint = circuit.GetRoutePoint(progressDistance);
130 Vector3 progressDelta = progressPoint.position - transform.position;
131 if (Vector3.Dot(progressDelta, progressPoint.direction) < 0)
132 {
133 progressDistance += progressDelta.magnitude;
134 }
135 lastPosition = transform.position;
136 }
137 }
138
139
140 private void OnDrawGizmos()
141 {
142 if (Application.isPlaying)
143 {
144 Gizmos.color = Color.green;
145 Gizmos.DrawLine(transform.position, target.position);
146 Gizmos.DrawWireSphere(circuit.GetRoutePosition(progressDistance), 1);
147 Gizmos.color = Color.yellow;
148 Gizmos.DrawLine(target.position, target.position + target.forward);
149 }
150 }
151 }
152 }
2 using UnityEngine;
3
4 namespace UnityStandardAssets.Utility
5 {
6 public class WaypointProgressTracker : MonoBehaviour
7 {
8 // This script can be used with any object that is supposed to follow a
9 // route marked out by waypoints.
10
11 // This script manages the amount to look ahead along the route,
12 // and keeps track of progress and laps.
13
14 [SerializeField] public WaypointCircuit circuit; // A reference to the waypoint-based route we should follow
15
16 [SerializeField] private float lookAheadForTargetOffset = 5;
17 // The offset ahead along the route that the we will aim for
18
19 [SerializeField] private float lookAheadForTargetFactor = .1f;
20 // A multiplier adding distance ahead along the route to aim for, based on current speed
21
22 [SerializeField] private float lookAheadForSpeedOffset = 10;
23 // The offset ahead only the route for speed adjustments (applied as the rotation of the waypoint target transform)
24
25 [SerializeField] private float lookAheadForSpeedFactor = .2f;
26 // A multiplier adding distance ahead along the route for speed adjustments
27
28 [SerializeField] private ProgressStyle progressStyle = ProgressStyle.SmoothAlongRoute;
29 // whether to update the position smoothly along the route (good for curved paths) or just when we reach each waypoint.
30
31 [SerializeField] private float pointToPointThreshold = 4;
32 // proximity to waypoint which must be reached to switch target to next waypoint : only used in PointToPoint mode.
33
34 public enum ProgressStyle
35 {
36 SmoothAlongRoute,
37 PointToPoint,
38 }
39
40 // these are public, readable by other objects - i.e. for an AI to know where to head!
41 public WaypointCircuit.RoutePoint targetPoint { get; private set; }
42 public WaypointCircuit.RoutePoint speedPoint { get; private set; }
43 public WaypointCircuit.RoutePoint progressPoint { get; private set; }
44
45 public Transform target;
46
47 private float progressDistance; // The progress round the route, used in smooth mode.
48 private int progressNum; // the current waypoint number, used in point-to-point mode.
49 private Vector3 lastPosition; // Used to calculate current speed (since we may not have a rigidbody component)
50 private float speed; // current speed of this object (calculated from delta since last frame)
51
52 // setup script properties
53 private void Start()
54 {
55 // we use a transform to represent the point to aim for, and the point which
56 // is considered for upcoming changes-of-speed. This allows this component
57 // to communicate this information to the AI without requiring further dependencies.
58
59 // You can manually create a transform and assign it to this component *and* the AI,
60 // then this component will update it, and the AI can read it.
61 if (target == null)
62 {
63 target = new GameObject(name + " Waypoint Target").transform;
64 }
65
66 Reset();
67 }
68
69
70 // reset the object to sensible values
71 public void Reset()
72 {
73 progressDistance = 0;
74 progressNum = 0;
75 if (progressStyle == ProgressStyle.PointToPoint)
76 {
77 target.position = circuit.Waypoints[progressNum].position;
78 target.rotation = circuit.Waypoints[progressNum].rotation;
79 }
80 }
81
82
83 private void Update()
84 {
85 if (progressStyle == ProgressStyle.SmoothAlongRoute)
86 {
87 // determine the position we should currently be aiming for
88 // (this is different to the current progress position, it is a a certain amount ahead along the route)
89 // we use lerp as a simple way of smoothing out the speed over time.
90 if (Time.deltaTime > 0)
91 {
92 speed = Mathf.Lerp(speed, (lastPosition - transform.position).magnitude/Time.deltaTime,
93 Time.deltaTime);
94 }
95 target.position =
96 circuit.GetRoutePoint(progressDistance + lookAheadForTargetOffset + lookAheadForTargetFactor*speed)
97 .position;
98 target.rotation =
99 Quaternion.LookRotation(
100 circuit.GetRoutePoint(progressDistance + lookAheadForSpeedOffset + lookAheadForSpeedFactor*speed)
101 .direction);
102
103
104 // get our current progress along the route
105 progressPoint = circuit.GetRoutePoint(progressDistance);
106 Vector3 progressDelta = progressPoint.position - transform.position;
107 if (Vector3.Dot(progressDelta, progressPoint.direction) < 0)
108 {
109 progressDistance += progressDelta.magnitude*0.5f;
110 }
111
112 lastPosition = transform.position;
113 }
114 else
115 {
116 // point to point mode. Just increase the waypoint if we're close enough:
117
118 Vector3 targetDelta = target.position - transform.position;
119 if (targetDelta.magnitude < pointToPointThreshold)
120 {
121 progressNum = (progressNum + 1)%circuit.Waypoints.Length;
122 }
123
124
125 target.position = circuit.Waypoints[progressNum].position;
126 target.rotation = circuit.Waypoints[progressNum].rotation;
127
128 // get our current progress along the route
129 progressPoint = circuit.GetRoutePoint(progressDistance);
130 Vector3 progressDelta = progressPoint.position - transform.position;
131 if (Vector3.Dot(progressDelta, progressPoint.direction) < 0)
132 {
133 progressDistance += progressDelta.magnitude;
134 }
135 lastPosition = transform.position;
136 }
137 }
138
139
140 private void OnDrawGizmos()
141 {
142 if (Application.isPlaying)
143 {
144 Gizmos.color = Color.green;
145 Gizmos.DrawLine(transform.position, target.position);
146 Gizmos.DrawWireSphere(circuit.GetRoutePosition(progressDistance), 1);
147 Gizmos.color = Color.yellow;
148 Gizmos.DrawLine(target.position, target.position + target.forward);
149 }
150 }
151 }
152 }