123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- using System;
- using UnityEngine;
- using UnityEngine.Events;
- using Logger = ARLocation.Utils.Logger;
- namespace ARLocation
- {
- [AddComponentMenu("AR+GPS/Hotspot")]
- [HelpURL("https://http://docs.unity-ar-gps-location.com/guide/#hotspot")]
- [DisallowMultipleComponent]
- public class Hotspot : MonoBehaviour
- {
- [Serializable]
- public class OnHotspotActivatedUnityEvent : UnityEvent<GameObject> { }
- [Serializable]
- public class OnHotspotActivatedWithIdUnityEvent : UnityEvent<GameObject, int> { }
- [Serializable]
- public class OnHotspotLeaveUnityEvent : UnityEvent<GameObject> { }
- [Serializable]
- public class OnHotspotLeaveWithIdUnityEvent : UnityEvent<GameObject, int> { }
- [Serializable]
- public enum PositionModes
- {
- HotspotCenter,
- CameraPosition
- };
- [Serializable]
- public class HotspotSettingsData
- {
- [Tooltip("The prefab/GameObject that will be instantiated by the Hotspot.")]
- public GameObject Prefab;
- [Tooltip("The positioning mode. 'HotspotCenter' means the object will be instantiated at the Hotpot's center geo-location. 'CameraPosition' means it will be positioned at the front of the camera.")]
- public PositionModes PositionMode;
- [Tooltip("The distance from the center that the user must be located to activate the Hotspot.")]
- public float ActivationRadius = 4.0f;
- [Tooltip("If true, align the instantiated object to face the camera (horizontally).")]
- public bool AlignToCamera = true;
- [Tooltip("If 'PositionMode' is set to 'CameraPosition', how far from the camera the instantiated object should be placed.")]
- public float DistanceFromCamera = 3.0f;
- [Tooltip("If true, use raw GPS data, instead of the filtered GPS data.")]
- public bool UseRawLocation = true;
- [Tooltip("If true, deactivate the hotspot when leaving the radius after entering it. After deactivattion, the hotspot will be available for activation againg when re-entering the radius.")]
- public bool DeactivateOnLeave = false;
- [Tooltip("An optional integer ID which is passed to the \"On Hotspot Activated With Id\" and \"On Hotspot Leave With Id\" events.")]
- [HideInInspector] public int Id = 0;
- }
- [Serializable]
- public class StateData
- {
- public bool Activated;
- public GameObject Instance;
- public Location Location;
- public bool EmittedLeaveHotspotEvent;
- }
- public PlaceAtLocation.LocationSettingsData LocationSettings = new PlaceAtLocation.LocationSettingsData();
- public HotspotSettingsData HotspotSettings = new HotspotSettingsData();
- [Space(4.0f)]
- [Header("Debug")]
- [Tooltip("When debug mode is enabled, this component will print relevant messages to the console. Filter by 'Hotspot' in the log output to see the messages.")]
- public bool DebugMode;
- [Space(4.0f)]
- [Header("Events")]
- [Tooltip("If true, monitor distance to emit the 'OnLeaveHotspot' event. If you don't need it, keep this disabled for better performance.")]
- public bool UseOnLeaveHotspotEvent;
- [Tooltip("Event for the Hotspot is activated.")]
- public OnHotspotActivatedUnityEvent OnHotspotActivated = new OnHotspotActivatedUnityEvent();
- [Tooltip("This event will be emited only once, when the user leaves the hotspot area after it is activated.")]
- public OnHotspotLeaveUnityEvent OnHotspotLeave = new OnHotspotLeaveUnityEvent();
- [Tooltip("This event will be emited only once, when the user leaves the hotspot area after it is activated.")]
- [HideInInspector] public OnHotspotLeaveWithIdUnityEvent OnHotspotLeaveWithId = new OnHotspotLeaveWithIdUnityEvent();
- [Tooltip("Event for the Hotspot is activated.")]
- [HideInInspector] public OnHotspotActivatedWithIdUnityEvent OnHotspotActivatedWithId = new OnHotspotActivatedWithIdUnityEvent();
- private readonly StateData state = new StateData();
- private Transform root;
- private Camera arCamera;
- private double currentDistance;
- // ReSharper disable once UnusedMember.Global
- public GameObject Instance => state.Instance;
- // ReSharper disable once MemberCanBePrivate.Global
- public Location Location
- {
- // ReSharper disable once UnusedMember.Global
- get => state.Location;
- set => state.Location = value;
- }
- /// <summary>
- ///
- /// Returns the Hotspot's current position, both before and after
- /// activation. Before activation it will return a Horizontal position,
- /// i.e., without altiture (that is, with y = 0).
- ///
- /// </summary>
- public Vector3 Position
- {
- get
- {
- if (state.Activated)
- {
- return state.Instance.transform.position;
- }
- else
- {
- var arLocMngr = ARLocationManager.Instance;
- var arLocPrvdr = ARLocationProvider.Instance;
- var pos = Location.GetGameObjectPositionForLocation(
- arLocMngr.gameObject.transform,
- arLocMngr.Camera.transform.position,
- arLocPrvdr.CurrentLocation.ToLocation(),
- state.Location,
- true
- );
- pos.y = 0;
- return pos;
- }
- }
- }
- /// <summary>
- /// Returns the current user distance to the Hotspot center.
- /// </summary>
- public float CurrentDistance => (float)currentDistance;
- void Start()
- {
- var arLocationProvider = ARLocationProvider.Instance;
- if (HotspotSettings.UseRawLocation)
- {
- arLocationProvider.Provider.LocationUpdatedRaw += Provider_LocationUpdated;
- }
- else
- {
- arLocationProvider.Provider.LocationUpdated += Provider_LocationUpdated;
- }
- root = ARLocationManager.Instance.gameObject.transform;
- if (state.Location == null)
- {
- state.Location = LocationSettings.GetLocation();
- }
- arCamera = ARLocationManager.Instance.MainCamera;
- if (arLocationProvider.IsEnabled)
- {
- Provider_LocationUpdated(arLocationProvider.CurrentLocation, arLocationProvider.LastLocation);
- }
- }
- public void OnDisable()
- {
- var arLocationProvider = ARLocationProvider.Instance;
- if (!arLocationProvider) return;
- if (HotspotSettings.UseRawLocation)
- {
- arLocationProvider.Provider.LocationUpdatedRaw -= Provider_LocationUpdated;
- }
- else
- {
- arLocationProvider.Provider.LocationUpdated -= Provider_LocationUpdated;
- }
- }
- public void Restart()
- {
- Destroy(state.Instance);
- state.Instance = null;
- state.Activated = false;
- state.EmittedLeaveHotspotEvent = false;
- }
- private void Provider_LocationUpdated(LocationReading currentLocation, LocationReading lastLocation)
- {
- if (state.Activated) return;
- Logger.LogFromMethod("Hotspot", "LocationUpdatedRaw", $"({gameObject.name}): New device location {currentLocation}", DebugMode);
- currentDistance = Location.HorizontalDistance(currentLocation.ToLocation(), state.Location);
- var delta = Location.HorizontalVectorFromTo(currentLocation.ToLocation(), state.Location);
- if (currentDistance <= HotspotSettings.ActivationRadius)
- {
- ActivateHotspot(new Vector3((float)delta.x, 0, (float)delta.y));
- }
- else
- {
- Logger.LogFromMethod("Hotspot", "LocationUpdatedRaw", $"({gameObject.name}): No activation - distance = {currentDistance}", DebugMode);
- }
- }
- private void ActivateHotspot(Vector3 delta)
- {
- Logger.LogFromMethod("Hotspot", "ActivateHotspot", $"({gameObject.name}): Activating hotspot...", DebugMode);
- if (HotspotSettings.Prefab == null) return;
- state.Instance = Instantiate(HotspotSettings.Prefab, HotspotSettings.AlignToCamera ? gameObject.transform : root);
- switch (HotspotSettings.PositionMode)
- {
- case PositionModes.HotspotCenter:
- state.Instance.transform.position = arCamera.transform.position + delta;
- break;
- case PositionModes.CameraPosition:
- var transform1 = arCamera.transform;
- var forward = transform1.forward;
- forward.y = 0;
- state.Instance.transform.position = transform1.position + forward * HotspotSettings.DistanceFromCamera;
- break;
- }
- if (HotspotSettings.AlignToCamera)
- {
- state.Instance.transform.LookAt(arCamera.transform);
- }
- state.Instance.AddComponent<GroundHeight>();
- state.Instance.name = name + " (Hotspot)";
- state.Activated = true;
- Logger.LogFromMethod("Hotspot", "ActivateHotspot", $"({name}): Hotspot activated", DebugMode);
- OnHotspotActivated?.Invoke(state.Instance);
- OnHotspotActivatedWithId?.Invoke(state.Instance, HotspotSettings.Id);
- }
- public static Hotspot AddHotspotComponent(GameObject go, Location location, HotspotSettingsData settings)
- {
- var hotspot = go.AddComponent<Hotspot>();
- hotspot.Location = location.Clone();
- hotspot.HotspotSettings = settings;
- return hotspot;
- }
- public static Hotspot AddHotspotComponent(GameObject go, Location location, HotspotSettingsData settings, int id = 0)
- {
- settings.Id = id;
- return AddHotspotComponent(go, location, settings);
- }
- public static GameObject CreateHotspotGameObject(Location location, HotspotSettingsData settings,
- string name = "GPS Hotspot")
- {
- var go = new GameObject(name);
- AddHotspotComponent(go, location, settings);
- return go;
- }
- public static GameObject CreateHotspotGameObject(Location location, HotspotSettingsData settings,
- string name = "GPS Hotspot", int id = 0)
- {
- settings.Id = id;
- return CreateHotspotGameObject(location, settings, name);
- }
- void Update()
- {
- if (UseOnLeaveHotspotEvent && state.Activated && !state.EmittedLeaveHotspotEvent)
- {
- var distance = Vector3.Distance(arCamera.transform.position, state.Instance.transform.position);
- if (distance >= HotspotSettings.ActivationRadius)
- {
- OnHotspotLeave?.Invoke(state.Instance);
- OnHotspotLeaveWithId?.Invoke(state.Instance, HotspotSettings.Id);
- state.EmittedLeaveHotspotEvent = true;
- if (HotspotSettings.DeactivateOnLeave)
- {
- Restart();
- }
- }
- }
- }
- }
- }
|