AR + GPS Location  3.0.0
All Classes Namespaces Functions Variables Properties Events Pages
MoveAlongPath.cs
1 using System;
2 using UnityEngine;
3 using UnityEngine.Serialization;
4 // ReSharper disable UnusedMember.Global
5 
6 namespace ARLocation
7 {
8  using Utils;
9 
14  [AddComponentMenu("AR+GPS/Move Along Path")]
15  [HelpURL("https://http://docs.unity-ar-gps-location.com/guide/#movealongpath")]
16  [DisallowMultipleComponent]
17  public class MoveAlongPath : MonoBehaviour
18  {
19  [Serializable]
20  public class PathSettingsData
21  {
25  [Tooltip("The LocationPath describing the path to be traversed.")]
27 
31  [Tooltip("The number of points-per-segment used to calculate the spline.")]
32  public int SplineSampleCount = 250;
33 
37  [FormerlySerializedAs("lineRenderer")] [Tooltip("If present, renders the spline in the scene using the given line renderer.")]
39  }
40 
41  [Serializable]
42  public class PlaybackSettingsData
43  {
47  [Tooltip("The speed along the path.")]
48  public float Speed = 1.0f;
49 
53  [Tooltip("The up direction to be used for orientation along the path.")]
54  public Vector3 Up = Vector3.up;
55 
59  [Tooltip("If true, play the path traversal in a loop.")]
60  public bool Loop = true;
61 
65  [Tooltip("If true, start playing automatically.")]
66  public bool AutoPlay = true;
67 
68  [FormerlySerializedAs("offset")] [Tooltip("The parameters offset; marks the initial position of the object along the curve.")]
69  public float Offset;
70  }
71 
72  [Serializable]
73  public class PlacementSettingsData
74  {
75  [Tooltip("The altitude mode. The altitude modes of the individual path locations are ignored, and this will be used instead.")]
76  public AltitudeMode AltitudeMode = AltitudeMode.DeviceRelative;
77 
78  [Tooltip(
79  "The maximum number of times this object will be affected by GPS location updates. Zero means no limits are imposed.")]
80  public uint MaxNumberOfLocationUpdates = 4;
81  }
82 
83  [Serializable]
84  public class StateData
85  {
86  public uint UpdateCount;
87  public Vector3[] Points;
88  public int PointCount;
89  public bool Playing;
90  public Spline Spline;
91  public Vector3 Translation;
92  public float Speed;
93  }
94 
95  public PathSettingsData PathSettings = new PathSettingsData();
96  public PlaybackSettingsData PlaybackSettings = new PlaybackSettingsData();
97  public PlacementSettingsData PlacementSettings = new PlacementSettingsData();
98 
99  public float Speed
100  {
101  get => state.Speed;
102  set => state.Speed = value;
103  }
104 
105  [Space(4.0f)]
106 
107  [Header("Debug")]
108  [Tooltip("When debug mode is enabled, this component will print relevant messages to the console. Filter by 'MoveAlongPath' in the log output to see the messages.")]
109  public bool DebugMode;
110 
111  [Space(4.0f)]
112 
113  private StateData state = new StateData();
114  private ARLocationProvider locationProvider;
115  private float u;
116  private GameObject arLocationRoot;
117  private Transform mainCameraTransform;
118  private bool useLineRenderer;
119  private bool hasInitialized;
120  private GroundHeight groundHeight;
121 
122  private bool HeightRelativeToDevice => PlacementSettings.AltitudeMode == AltitudeMode.DeviceRelative;
123  private bool HeightGroundRelative => PlacementSettings.AltitudeMode == AltitudeMode.GroundRelative;
124 
129  public void SetLocationPath(LocationPath path)
130  {
131  PathSettings.LocationPath = path;
132 
133  state.PointCount = PathSettings.LocationPath.Locations.Length;
134  state.Points = new Vector3[state.PointCount];
135 
136 
137  BuildSpline(locationProvider.CurrentLocation.ToLocation());
138  }
139 
140 
141  void Start()
142  {
143  if (PathSettings.LocationPath == null)
144  {
145  throw new NullReferenceException("[AR+GPS][MoveAlongPath]: Null Path! Please set the 'LocationPath' property!");
146  }
147 
148  locationProvider = ARLocationProvider.Instance;
149  locationProvider.OnLocationUpdatedEvent(LocationUpdated);
150 
151  mainCameraTransform = ARLocationManager.Instance.MainCamera.transform;
152  arLocationRoot = ARLocationManager.Instance.gameObject; // Misc.FindAndLogError("ARLocationRoot", "[ARLocationMoveAlongPath]: ARLocationRoot GameObject not found.");
153 
154  Initialize();
155  hasInitialized = true;
156  }
157 
158  private void Initialize()
159  {
160  state.PointCount = PathSettings.LocationPath.Locations.Length;
161  state.Points = new Vector3[state.PointCount];
162  state.Speed = PlaybackSettings.Speed;
163 
164  useLineRenderer = PathSettings.LineRenderer != null;
165 
166  transform.SetParent(arLocationRoot.transform);
167 
168  state.Playing = PlaybackSettings.AutoPlay;
169 
170  u += PlaybackSettings.Offset;
171 
172  groundHeight = GetComponent<GroundHeight>();
173  if (PlacementSettings.AltitudeMode == AltitudeMode.GroundRelative)
174  {
175  if (!groundHeight)
176  {
177  groundHeight = gameObject.AddComponent<GroundHeight>();
178  groundHeight.Settings.DisableUpdate = true;
179  }
180  }
181  else
182  {
183  if (groundHeight)
184  {
185  Destroy(groundHeight);
186  groundHeight = null;
187  }
188  }
189 
190  if (!hasInitialized)
191  {
192  locationProvider.OnProviderRestartEvent(ProviderRestarted);
193  }
194 
195  if (locationProvider.IsEnabled)
196  {
197  LocationUpdated(locationProvider.CurrentLocation, locationProvider.LastLocation);
198  }
199  }
200 
201  private void ProviderRestarted()
202  {
203  state.UpdateCount = 0;
204  }
205 
206  public void Restart()
207  {
208  state = new StateData();
209  Initialize();
210  }
211 
212 
216  public void Play()
217  {
218  state.Playing = true;
219  }
220 
226  public void GoTo(float t)
227  {
228  u = Mathf.Clamp(t, 0, 1);
229  }
230 
234  public void Pause()
235  {
236  state.Playing = false;
237  }
238 
242  public void Stop()
243  {
244  state.Playing = false;
245  u = 0;
246  }
247 
248  private void BuildSpline(Location location)
249  {
250  for (var i = 0; i < state.PointCount; i++)
251  {
252  var loc = PathSettings.LocationPath.Locations[i];
253 
254  state.Points[i] = Location.GetGameObjectPositionForLocation(arLocationRoot.transform,
255  mainCameraTransform, location, loc, HeightRelativeToDevice || HeightGroundRelative);
256 
257  Logger.LogFromMethod("MoveAlongPath", "BuildSpline", $"({gameObject.name}): Points[{i}] = {state.Points[i]}, geo-location = {loc}", DebugMode);
258  }
259 
260  state.Spline = Misc.BuildSpline(PathSettings.LocationPath.SplineType, state.Points, PathSettings.SplineSampleCount, PathSettings.LocationPath.Alpha);
261  }
262 
263  private void LocationUpdated(LocationReading location, LocationReading _)
264  {
265  Logger.LogFromMethod("MoveAlongPath", "LocationUpdated", $"({gameObject.name}): New device location {location}", DebugMode);
266 
267  if (PlacementSettings.MaxNumberOfLocationUpdates > 0 && state.UpdateCount > PlacementSettings.MaxNumberOfLocationUpdates)
268  {
269  Logger.LogFromMethod("MoveAlongPath", "LocationUpdated", $"({gameObject.name}): Max number of updates reached! returning", DebugMode);
270  return;
271  }
272 
273  BuildSpline(location.ToLocation());
274  state.Translation = new Vector3(0, 0, 0);
275 
276  state.UpdateCount++;
277  }
278 
279  private void Update()
280  {
281  if (!state.Playing)
282  {
283  return;
284  }
285 
286  // If there is no location provider, or spline, do nothing
287  if (state.Spline == null || !locationProvider.IsEnabled)
288  {
289  return;
290  }
291 
292  // Get spline point at current parameter
293  var s = state.Spline.Length * u;
294 
295  var data = state.Spline.GetPointAndTangentAtArcLength(s);
296  var tan = arLocationRoot.transform.InverseTransformVector(data.tangent);
297 
298  transform.position = data.point;
299 
300  var groundY = 0.0f;
301  if (groundHeight)
302  {
303  var position = transform.position;
304  groundY = groundHeight.CurrentGroundY;
305  position = MathUtils.SetY(position, position.y + groundY);
306  transform.position = position;
307  }
308 
309  // Set orientation
310  transform.localRotation = Quaternion.LookRotation(tan, PlaybackSettings.Up);
311 
312  // Check if we reached the end of the spline
313  u = u + (state.Speed * Time.deltaTime) / state.Spline.Length;
314  if (u >= 1 && !PlaybackSettings.Loop)
315  {
316  u = 0;
317  state.Playing = false;
318  }
319  else
320  {
321  u = u % 1.0f;
322  }
323 
324  // If there is a line renderer, render the path
325  if (useLineRenderer)
326  {
327  PathSettings.LineRenderer.useWorldSpace = true;
328  var t = arLocationRoot.transform;
329  state.Spline.DrawCurveWithLineRenderer(PathSettings.LineRenderer,
330  p => MathUtils.SetY(p, p.y + groundY)); //t.TransformVector(p - state.Translation));
331  }
332  }
333 
334  private void OnDestroy()
335  {
336  locationProvider.OnLocationUpdatedDelegate -= LocationUpdated;
337  locationProvider.OnRestartDelegate -= ProviderRestarted;
338  }
339  }
340 }
ARLocation.MoveAlongPath.Stop
void Stop()
Stops the movement along the path.
Definition: MoveAlongPath.cs:242
ARLocation.MoveAlongPath.PlacementSettingsData
Definition: MoveAlongPath.cs:74
ARLocation.ARLocationProvider.IsEnabled
bool IsEnabled
If true, the location provider has received the first location data.
Definition: ARLocationProvider.cs:68
ARLocation.MoveAlongPath.PathSettingsData.LineRenderer
LineRenderer LineRenderer
If present, renders the spline in the scene using the given line renderer.
Definition: MoveAlongPath.cs:38
ARLocation.MoveAlongPath.PathSettingsData
Definition: MoveAlongPath.cs:21
ARLocation.LocationPath
Data used to construct a spline passing trough a set of geographical locations.
Definition: LocationPath.cs:12
ARLocation.MoveAlongPath.PlaybackSettingsData.Speed
float Speed
The speed along the path.
Definition: MoveAlongPath.cs:48
ARLocation.ARLocationProvider
Definition: ARLocationProvider.cs:17
ARLocation.MoveAlongPath
This component, when attached to a GameObject, makes it traverse a path that interpolates a given set...
Definition: MoveAlongPath.cs:18
ARLocation.MoveAlongPath.SetLocationPath
void SetLocationPath(LocationPath path)
Change the LocationPath the GameObject will traverse.
Definition: MoveAlongPath.cs:129
ARLocation.MoveAlongPath.PlaybackSettingsData.Loop
bool Loop
If true, play the path traversal in a loop.
Definition: MoveAlongPath.cs:60
ARLocation.Location
Represents a geographical location.
Definition: Location.cs:19
ARLocation.MoveAlongPath.Play
void Play()
Starts playing or resumes the playback.
Definition: MoveAlongPath.cs:216
ARLocation.Utils.Singleton.Instance
static T Instance
Access singleton instance through this propriety.
Definition: Singleton.cs:18
ARLocation.LocationPath.Alpha
float Alpha
The path's alpha/tension factor.
Definition: LocationPath.cs:26
ARLocation.ARLocationProvider.OnLocationUpdatedEvent
void OnLocationUpdatedEvent(LocationUpdatedDelegate locationUpdatedDelegate, bool useRawIfEnabled=false)
Register a delegate to location updates.
Definition: ARLocationProvider.cs:276
ARLocation.MoveAlongPath.Pause
void Pause()
Pauses the movement along the path.
Definition: MoveAlongPath.cs:234
ARLocation.MoveAlongPath.PathSettingsData.SplineSampleCount
int SplineSampleCount
The number of points-per-segment used to calculate the spline.
Definition: MoveAlongPath.cs:32
ARLocation.MoveAlongPath.PlaybackSettingsData.Up
Vector3 Up
The up direction to be used for orientation along the path.
Definition: MoveAlongPath.cs:54
ARLocation.MoveAlongPath.PlaybackSettingsData
Definition: MoveAlongPath.cs:43
ARLocation.MoveAlongPath.StateData
Definition: MoveAlongPath.cs:85
ARLocation.ARLocationProvider.CurrentLocation
LocationReading CurrentLocation
The latest location data.
Definition: ARLocationProvider.cs:88
ARLocation.Location.GetGameObjectPositionForLocation
static Vector3 GetGameObjectPositionForLocation(Transform arLocationRoot, Vector3 userPosition, Location userLocation, Location objectLocation, bool heightIsRelative)
Gets the game object world-position for location.
Definition: Location.cs:276
ARLocation.Spline
Definition: Spline.cs:13
ARLocation.LocationPath.Locations
Location[] Locations
The geographical locations that the path will interpolate.
Definition: LocationPath.cs:17
ARLocation
Definition: ARLocationConfigInspector.cs:7
ARLocation.MoveAlongPath.PathSettingsData.LocationPath
LocationPath LocationPath
The LocationPath describing the path to be traversed.
Definition: MoveAlongPath.cs:26
ARLocation.MoveAlongPath.GoTo
void GoTo(float t)
Moves the object to the spline point corresponding to the given parameter.
Definition: MoveAlongPath.cs:226
ARLocation.ARLocationProvider.LastLocation
LocationReading LastLocation
The previous location data.
Definition: ARLocationProvider.cs:93
ARLocation.MoveAlongPath.PlaybackSettingsData.AutoPlay
bool AutoPlay
If true, start playing automatically.
Definition: MoveAlongPath.cs:66
ARLocation.GroundHeight
This component will change the Y component of the GameObject's position, so that it is set to the lev...
Definition: GroundHeight.cs:24