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 }