namespace Mapbox.Examples { using Mapbox.Unity.Location; using UnityEngine; public class RotateWithLocationProvider : MonoBehaviour { /// /// Location property used for rotation: false=Heading (default), true=Orientation /// [SerializeField] [Tooltip("Per default 'UserHeading' (direction the device is moving) is used for rotation. Check to use 'DeviceOrientation' (where the device is facing)")] bool _useDeviceOrientation; /// /// /// [SerializeField] [Tooltip("Only evaluated when 'Use Device Orientation' is checked. Subtracts UserHeading from DeviceOrientation. Useful if map is rotated by UserHeading and DeviceOrientation should be displayed relative to the heading.")] bool _subtractUserHeading; /// /// The rate at which the transform's rotation tries catch up to the provided heading. /// [SerializeField] [Tooltip("The rate at which the transform's rotation tries catch up to the provided heading. ")] float _rotationFollowFactor = 1; /// /// Set this to true if you'd like to adjust the rotation of a RectTransform (in a UI canvas) with the heading. /// [SerializeField] bool _rotateZ; /// /// Set this to true if you'd like to adjust the sign of the rotation angle. /// eg angle passed in 63.5, angle that should be used for rotation: -63.5. /// This might be needed when rotating the map and not objects on the map. /// [SerializeField] [Tooltip("Set this to true if you'd like to adjust the sign of the rotation angle. eg angle passed in 63.5, angle that should be used for rotation: -63.5.")] bool _useNegativeAngle; /// /// Use a mock , /// rather than a . /// [SerializeField] bool _useTransformLocationProvider; Quaternion _targetRotation; /// /// The location provider. /// This is public so you change which concrete to use at runtime. /// ILocationProvider _locationProvider; public ILocationProvider LocationProvider { private get { if (_locationProvider == null) { _locationProvider = _useTransformLocationProvider ? LocationProviderFactory.Instance.TransformLocationProvider : LocationProviderFactory.Instance.DefaultLocationProvider; } return _locationProvider; } set { if (_locationProvider != null) { _locationProvider.OnLocationUpdated -= LocationProvider_OnLocationUpdated; } _locationProvider = value; _locationProvider.OnLocationUpdated += LocationProvider_OnLocationUpdated; } } Vector3 _targetPosition; void Start() { LocationProvider.OnLocationUpdated += LocationProvider_OnLocationUpdated; } void OnDestroy() { if (LocationProvider != null) { LocationProvider.OnLocationUpdated -= LocationProvider_OnLocationUpdated; } } void LocationProvider_OnLocationUpdated(Location location) { float rotationAngle = _useDeviceOrientation ? location.DeviceOrientation : location.UserHeading; if (_useNegativeAngle) { rotationAngle *= -1f; } // 'Orientation' changes all the time, pass through immediately if (_useDeviceOrientation) { if (_subtractUserHeading) { if (rotationAngle > location.UserHeading) { rotationAngle = 360 - (rotationAngle - location.UserHeading); } else { rotationAngle = location.UserHeading - rotationAngle + 360; } if (rotationAngle < 0) { rotationAngle += 360; } if (rotationAngle >= 360) { rotationAngle -= 360; } } _targetRotation = Quaternion.Euler(getNewEulerAngles(rotationAngle)); } else { // if rotating by 'Heading' only do it if heading has a new value if (location.IsUserHeadingUpdated) { _targetRotation = Quaternion.Euler(getNewEulerAngles(rotationAngle)); } } } private Vector3 getNewEulerAngles(float newAngle) { var localRotation = transform.localRotation; var currentEuler = localRotation.eulerAngles; var euler = Mapbox.Unity.Constants.Math.Vector3Zero; if (_rotateZ) { euler.z = -newAngle; euler.x = currentEuler.x; euler.y = currentEuler.y; } else { euler.y = -newAngle; euler.x = currentEuler.x; euler.z = currentEuler.z; } return euler; } void Update() { transform.localRotation = Quaternion.Lerp(transform.localRotation, _targetRotation, Time.deltaTime * _rotationFollowFactor); } } }