123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465 |
- /*===============================================================================
- Copyright (C) 2022 Immersal - Part of Hexagon. All Rights Reserved.
- This file is part of the Immersal SDK.
- The Immersal SDK cannot be copied, distributed, or made available to
- third-parties for commercial purposes without written permission of Immersal Ltd.
- Contact sdk@immersal.com for licensing requests.
- ===============================================================================*/
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.Events;
- using UnityEngine.UI;
- using UnityEngine.AI;
- using Immersal.AR;
- using TMPro;
- namespace Immersal.Samples.Navigation
- {
- [System.Serializable]
- public class NavigationEvent : UnityEvent<Transform>
- {
- }
- public class NavigationManager : MonoBehaviour
- {
- // Navigation Visualization references
- [Header("Visualization")]
- [SerializeField]
- private GameObject m_navigationPathPrefab = null;
- /*
- [SerializeField]
- private GameObject m_navigationArrowPrefab = null;
- */
- // UI Object references
- [Header("UI Objects")]
- [SerializeField]
- private GameObject m_TargetsList = null;
- [SerializeField]
- private Sprite m_ShowListIcon = null;
- [SerializeField]
- private Sprite m_SelectTargetIcon = null;
- [SerializeField]
- private Image m_TargetsListIcon = null;
- [SerializeField]
- private TextMeshProUGUI m_TargetsListText = null;
- [SerializeField]
- private GameObject m_StopNavigationButton = null;
- // Navigation Settings
- private enum NavigationMode { NavMesh, Graph};
- [Header("Settings")]
- [SerializeField]
- private NavigationMode m_navigationMode = NavigationMode.NavMesh;
- public bool inEditMode = false;
- /*
- [SerializeField]
- private bool m_showArrow = true;
- */
- [SerializeField]
- private float m_ArrivedDistanceThreshold = 1.0f;
- [SerializeField]
- private float m_pathWidth = 0.3f;
- [SerializeField]
- private float m_heightOffset = 0.5f;
- // Navigation State Events
- [Header("Events")]
- [SerializeField]
- private NavigationEvent onTargetFound = new NavigationEvent();
- [SerializeField]
- private NavigationEvent onTargetNotFound = new NavigationEvent();
- private ARSpace m_arSpace = null;
- private bool m_managerInitialized = false;
- private bool m_navigationActive = false;
- private Transform m_targetTransform = null;
- private IsNavigationTarget m_NavigationTarget = null;
- private Transform m_playerTransform = null;
- private GameObject m_navigationPathObject = null;
- private NavigationPath m_navigationPath = null;
- [SerializeField]
- private NavigationGraphManager m_NavigationGraphManager = null;
- private enum NavigationState { NotNavigating, Navigating};
- private NavigationState m_navigationState = NavigationState.NotNavigating;
- private static NavigationManager instance = null;
- public static NavigationManager Instance
- {
- get
- {
- #if UNITY_EDITOR
- if (instance == null && !Application.isPlaying)
- {
- instance = FindObjectOfType<NavigationManager>();
- }
- #endif
- if (instance == null)
- {
- Debug.LogError("No NavigationManager instance found. Ensure one exists in the scene.");
- }
- return instance;
- }
- }
- public bool navigationActive
- {
- get { return m_navigationActive; }
- }
- void Awake()
- {
- if (instance == null)
- {
- instance = this;
- }
- if (instance != this)
- {
- Debug.LogError("NavigationManager: There must be only one NavigationManager in a scene.");
- UnityEngine.Object.DestroyImmediate(this);
- return;
- }
- }
- private void Start()
- {
- InitializeNavigationManager();
- if (m_managerInitialized)
- {
- m_TargetsListIcon.sprite = m_ShowListIcon;
- m_TargetsListText.text = "Show Navigation Targets";
- }
- }
- private void Update()
- {
- if(m_managerInitialized && m_navigationState == NavigationState.Navigating)
- {
- TryToFindPath(m_NavigationTarget);
- }
- }
- public void InitializeNavigation(NavigationTargetListButton button)
- {
- if (!m_managerInitialized)
- {
- Debug.LogWarning("NavigationManager: Navigation Manager not properly initialized.");
- return;
- }
- m_targetTransform = button.targetObject.transform;
- m_NavigationTarget = button.targetObject.GetComponent<IsNavigationTarget>();
- TryToFindPath(m_NavigationTarget);
- }
- public void TryToFindPath(IsNavigationTarget navigationTarget)
- {
- List<Vector3> corners;
- // Convert to Unity's world space coordinates to use NavMesh
- Vector3 startPosition = m_playerTransform.position;
- Vector3 targetPosition = navigationTarget.position;
- Vector3 delta = targetPosition - startPosition;
- float distanceToTarget = new Vector3(delta.x, delta.y, delta.z).magnitude;
- if (distanceToTarget < m_ArrivedDistanceThreshold)
- {
- m_navigationActive = false;
- m_navigationState = NavigationState.NotNavigating;
- UpdateNavigationUI(m_navigationState);
- DisplayArrivedNotification();
- return;
- }
- switch (m_navigationMode)
- {
- case NavigationMode.NavMesh:
- startPosition = ARSpaceToUnity(m_arSpace.transform, m_arSpace.initialOffset, startPosition);
- targetPosition = ARSpaceToUnity(m_arSpace.transform, m_arSpace.initialOffset, targetPosition);
- corners = FindPathNavMesh(startPosition, targetPosition);
- if (corners.Count >= 2)
- {
- m_navigationActive = true;
- m_navigationState = NavigationState.Navigating;
- UpdateNavigationUI(m_navigationState);
- m_navigationPath.GeneratePath(corners, m_arSpace.transform.up);
- m_navigationPath.pathWidth = m_pathWidth;
- }
- else
- {
- Mapping.NotificationManager.Instance.GenerateNotification("Path to target not found.");
- UpdateNavigationUI(m_navigationState);
- }
- break;
- case NavigationMode.Graph:
- corners = m_NavigationGraphManager.FindPath(startPosition, targetPosition);
- if (corners.Count >= 2)
- {
- m_navigationActive = true;
- m_navigationState = NavigationState.Navigating;
- UpdateNavigationUI(m_navigationState);
- m_navigationPath.GeneratePath(corners, m_arSpace.transform.up);
- m_navigationPath.pathWidth = m_pathWidth;
- }
- else
- {
- Mapping.NotificationManager.Instance.GenerateNotification("Path to target not found.");
- UpdateNavigationUI(m_navigationState);
- }
- break;
- }
- }
- private List<Vector3> FindPathNavMesh(Vector3 startPosition, Vector3 targetPosition)
- {
- NavMeshPath path = new NavMeshPath();
- List<Vector3> collapsedCorners = new List<Vector3>();
- if (NavMesh.CalculatePath(startPosition, targetPosition, NavMesh.AllAreas, path))
- {
- List<Vector3> corners = new List<Vector3>(path.corners);
- for (int i = 0; i < corners.Count; i++)
- {
- corners[i] = corners[i] + new Vector3(0f, m_heightOffset, 0f);
- corners[i] = UnityToARSpace(m_arSpace.transform, m_arSpace.initialOffset, corners[i]);
- }
- for (int i = 0; i < corners.Count - 1; i++)
- {
- Vector3 currentPoint = corners[i];
- Vector3 nextPoint = corners[i + 1];
- float threshold = 0.75f;
- if (Vector3.Distance(currentPoint, nextPoint) > threshold)
- {
- collapsedCorners.Add(currentPoint);
- }
- }
- collapsedCorners.Add(corners[corners.Count - 1]);
- }
- return collapsedCorners;
- }
- public void ToggleTargetsList()
- {
- if (!m_managerInitialized)
- {
- Debug.LogWarning("NavigationManager: Navigation Manager not properly initialized.");
- return;
- }
- if (m_TargetsList.activeInHierarchy)
- {
- m_TargetsList.SetActive(false);
- if (m_ShowListIcon != null && m_TargetsListIcon != null)
- {
- m_TargetsListIcon.sprite = m_ShowListIcon;
- }
- if (m_TargetsListText != null)
- {
- m_TargetsListText.text = "Show Navigation Targets";
- }
- }
- else
- {
- m_TargetsList.SetActive(true);
- m_TargetsList.GetComponent<NavigationTargetListControl>().GenerateButtons();
- if (m_SelectTargetIcon != null && m_TargetsListIcon != null)
- {
- m_TargetsListIcon.sprite = m_SelectTargetIcon;
- }
- if (m_TargetsListText != null)
- {
- m_TargetsListText.text = "Select Navigation Target";
- }
- }
- }
- public void ToggleEditMode()
- {
- inEditMode = !inEditMode;
- }
- public void DisplayPathNotFoundNotification()
- {
- #if !(UNITY_STANDALONE || PLATFORM_LUMIN)
- Handheld.Vibrate();
- #endif
- Mapping.NotificationManager.Instance.GenerateNotification("Path to target could not be found.");
- onTargetNotFound.Invoke(m_targetTransform);
- }
- public void DisplayArrivedNotification()
- {
- #if !(UNITY_STANDALONE || PLATFORM_LUMIN)
- Handheld.Vibrate();
- #endif
- Mapping.NotificationManager.Instance.GenerateNotification("You have arrived!");
- onTargetFound.Invoke(m_targetTransform);
- }
- public void StopNavigation()
- {
- m_navigationActive = false;
- m_navigationState = NavigationState.NotNavigating;
- UpdateNavigationUI(m_navigationState);
- Mapping.NotificationManager.Instance.GenerateNotification("Navigation stopped.");
- }
- private void UpdateNavigationUI(NavigationState navigationState)
- {
- switch(navigationState)
- {
- case NavigationState.NotNavigating:
- m_StopNavigationButton.SetActive(false);
- m_navigationPathObject.SetActive(false);
- break;
- case NavigationState.Navigating:
- m_StopNavigationButton.SetActive(true);
- m_navigationPathObject.SetActive(true);
- break;
- }
- }
- private void InitializeNavigationManager()
- {
- if (m_arSpace == null)
- {
- m_arSpace = FindObjectOfType<ARSpace>();
- if (m_arSpace == null)
- {
- Debug.LogWarning("NavigationManager: No AR Space found in scene, ensure one exists.");
- return;
- }
- }
- m_NavigationGraphManager = GetComponent<NavigationGraphManager>();
- if (m_NavigationGraphManager == null)
- {
- Debug.LogWarning("NavigationManager: Missing Navigation Graph Manager component.");
- return;
- }
- m_playerTransform = Camera.main.transform;
- if (m_playerTransform == null)
- {
- Debug.LogWarning("NavigationManager: Could not find the main camera. Do you have the MainCamera tag applied?");
- return;
- }
- if (m_navigationPathPrefab == null)
- {
- Debug.LogWarning("NavigationManager: Missing navigation path object reference.");
- return;
- }
- if(m_navigationPathPrefab != null)
- {
- if (m_navigationPathObject == null)
- {
- m_navigationPathObject = Instantiate(m_navigationPathPrefab);
- m_navigationPathObject.SetActive(false);
- m_navigationPath = m_navigationPathObject.GetComponent<NavigationPath>();
- }
- if(m_navigationPath == null)
- {
- Debug.LogWarning("NavigationManager: NavigationPath component in Navigation path is missing.");
- return;
- }
- }
- if (m_TargetsList == null)
- {
- Debug.LogWarning("NavigationManager: Navigation Targets List reference is missing.");
- return;
- }
- if (m_ShowListIcon == null)
- {
- Debug.LogWarning("NavigationManager: \"Show List\" icon is missing.");
- return;
- }
- if (m_SelectTargetIcon == null)
- {
- Debug.LogWarning("NavigationManager: \"Select Target\" icon is missing.");
- return;
- }
- if (m_TargetsListIcon == null)
- {
- Debug.LogWarning("NavigationManager: \"Targets List\" icon reference is missing.");
- return;
- }
- if (m_TargetsListText == null)
- {
- Debug.LogWarning("NavigationManager: \"Targets List\" text reference is missing.");
- return;
- }
- if (m_StopNavigationButton == null)
- {
- Debug.LogWarning("NavigationManager: Stop Navigation Button reference is missing.");
- return;
- }
- m_managerInitialized = true;
- }
- private Vector3 ARSpaceToUnity(Transform arspace, Matrix4x4 arspaceoffset, Vector3 pos)
- {
- Matrix4x4 m = arspace.worldToLocalMatrix;
- pos = m.MultiplyPoint(pos);
- pos = arspaceoffset.MultiplyPoint(pos);
- return pos;
- }
- private Vector3 ARSpaceToUnity(Transform arspace, Vector3 pos)
- {
- pos = ARSpaceToUnity(arspace, Matrix4x4.identity, pos);
- return pos;
- }
- private Vector3 UnityToARSpace(Transform arspace, Matrix4x4 arspaceOffset, Vector3 pos)
- {
- pos = arspaceOffset.inverse.MultiplyPoint(pos);
- Matrix4x4 m = arspace.localToWorldMatrix;
- pos = m.MultiplyPoint(pos);
- return pos;
- }
- private Vector3 UnityToARSpace(Transform arspace, Vector3 pos)
- {
- pos = UnityToARSpace(arspace, Matrix4x4.identity, pos);
- return pos;
- }
- }
- }
|