3 using UnityEngine.Serialization;
14 [AddComponentMenu(
"AR+GPS/Move Along Path")]
15 [HelpURL(
"https://http://docs.unity-ar-gps-location.com/guide/#movealongpath")]
16 [DisallowMultipleComponent]
25 [Tooltip(
"The LocationPath describing the path to be traversed.")]
31 [Tooltip(
"The number of points-per-segment used to calculate the spline.")]
37 [FormerlySerializedAs(
"lineRenderer")] [Tooltip(
"If present, renders the spline in the scene using the given line renderer.")]
47 [Tooltip(
"The speed along the path.")]
53 [Tooltip(
"The up direction to be used for orientation along the path.")]
54 public Vector3
Up = Vector3.up;
59 [Tooltip(
"If true, play the path traversal in a loop.")]
65 [Tooltip(
"If true, start playing automatically.")]
68 [FormerlySerializedAs(
"offset")] [Tooltip(
"The parameters offset; marks the initial position of the object along the curve.")]
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;
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;
86 public uint UpdateCount;
87 public Vector3[] Points;
88 public int PointCount;
91 public Vector3 Translation;
102 set => state.Speed = value;
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;
113 private StateData state =
new StateData();
116 private GameObject arLocationRoot;
117 private Transform mainCameraTransform;
118 private bool useLineRenderer;
119 private bool hasInitialized;
122 private bool HeightRelativeToDevice => PlacementSettings.AltitudeMode == AltitudeMode.DeviceRelative;
123 private bool HeightGroundRelative => PlacementSettings.AltitudeMode == AltitudeMode.GroundRelative;
134 state.Points =
new Vector3[state.PointCount];
145 throw new NullReferenceException(
"[AR+GPS][MoveAlongPath]: Null Path! Please set the 'LocationPath' property!");
148 locationProvider = ARLocationProvider.
Instance;
151 mainCameraTransform = ARLocationManager.Instance.MainCamera.transform;
152 arLocationRoot = ARLocationManager.Instance.gameObject;
155 hasInitialized =
true;
158 private void Initialize()
161 state.Points =
new Vector3[state.PointCount];
162 state.Speed = PlaybackSettings.
Speed;
166 transform.SetParent(arLocationRoot.transform);
168 state.Playing = PlaybackSettings.
AutoPlay;
170 u += PlaybackSettings.Offset;
172 groundHeight = GetComponent<GroundHeight>();
173 if (PlacementSettings.AltitudeMode == AltitudeMode.GroundRelative)
177 groundHeight = gameObject.AddComponent<GroundHeight>();
178 groundHeight.Settings.DisableUpdate =
true;
185 Destroy(groundHeight);
192 locationProvider.OnProviderRestartEvent(ProviderRestarted);
201 private void ProviderRestarted()
203 state.UpdateCount = 0;
206 public void Restart()
208 state =
new StateData();
218 state.Playing =
true;
228 u = Mathf.Clamp(t, 0, 1);
236 state.Playing =
false;
244 state.Playing =
false;
248 private void BuildSpline(
Location location)
250 for (var i = 0; i < state.PointCount; i++)
255 mainCameraTransform, location, loc, HeightRelativeToDevice || HeightGroundRelative);
257 Logger.LogFromMethod(
"MoveAlongPath",
"BuildSpline", $
"({gameObject.name}): Points[{i}] = {state.Points[i]}, geo-location = {loc}", DebugMode);
263 private void LocationUpdated(LocationReading location, LocationReading _)
265 Logger.LogFromMethod(
"MoveAlongPath",
"LocationUpdated", $
"({gameObject.name}): New device location {location}", DebugMode);
267 if (PlacementSettings.MaxNumberOfLocationUpdates > 0 && state.UpdateCount > PlacementSettings.MaxNumberOfLocationUpdates)
269 Logger.LogFromMethod(
"MoveAlongPath",
"LocationUpdated", $
"({gameObject.name}): Max number of updates reached! returning", DebugMode);
273 BuildSpline(location.ToLocation());
274 state.Translation =
new Vector3(0, 0, 0);
279 private void Update()
287 if (state.Spline ==
null || !locationProvider.
IsEnabled)
293 var s = state.Spline.Length * u;
295 var data = state.Spline.GetPointAndTangentAtArcLength(s);
296 var tan = arLocationRoot.transform.InverseTransformVector(data.tangent);
298 transform.position = data.point;
303 var position = transform.position;
304 groundY = groundHeight.CurrentGroundY;
305 position = MathUtils.SetY(position, position.y + groundY);
306 transform.position = position;
310 transform.localRotation = Quaternion.LookRotation(tan, PlaybackSettings.
Up);
313 u = u + (state.Speed * Time.deltaTime) / state.Spline.Length;
314 if (u >= 1 && !PlaybackSettings.
Loop)
317 state.Playing =
false;
328 var t = arLocationRoot.transform;
329 state.Spline.DrawCurveWithLineRenderer(PathSettings.
LineRenderer,
330 p => MathUtils.SetY(p, p.y + groundY));
334 private void OnDestroy()
336 locationProvider.OnLocationUpdatedDelegate -= LocationUpdated;
337 locationProvider.OnRestartDelegate -= ProviderRestarted;