using SC.XR.Unity; using System; using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; public class SafetyAreaManager : SingletonMono { //是否已从配置文件中读取安全区域 private static bool hasReadFromFile = false; public Action OnBeginSetSafeArea; public Action OnFinishSetSafeArea; public Action OnEnterSafetyArea; public Action OnExitSafetyArea; public Action OnDisableSafetyArea; public Action OnDoubleTapShowSafetyArea; private Dictionary areaStepDic; private GameObject safetyAreaGameObject; private SafetyAreaMono safetyAreaMono; private ISafetyAreaStep currentStep; [HideInInspector] public StationaryAreaMono stationaryAreaMono; private GameObject stationaryAreaObject; [HideInInspector] public PlayAreaMono playAreaMono; private GameObject playAreaObject; [HideInInspector] public bool isDisableSafetyArea = false; [HideInInspector] public bool isSettingSafetyArea = false; [HideInInspector] public bool onlySettingGroundHeight = false; [HideInInspector] public bool doubleTapShowSeeThrough = true; private bool showAreaWhenBowHead = true; private float originAlphaParam = 0.4f; private int originSafetyAreaColorIndex = 0; private SafetyAreaInfo currentSafetyAreaInfo = null; private bool alreayExitSafetyArea = false; public bool DoubleClickShowSeeThrough { get { return doubleTapShowSeeThrough; } set { doubleTapShowSeeThrough = value; OnDoubleTapShowSafetyArea?.Invoke(doubleTapShowSeeThrough); } } public bool IsDisableSafetyArea { get { return isDisableSafetyArea; } set { isDisableSafetyArea = value; OnDisableSafetyArea?.Invoke(isDisableSafetyArea); } } public bool ShowAreaWhenBowHead { get { if (!hasReadFromFile) { LoadSafetyArea(); } return showAreaWhenBowHead; } set { showAreaWhenBowHead = value; SaveSafetyArea(); } } public int OriginSafetyAreaColorIndex { get { if (!hasReadFromFile) { LoadSafetyArea(); } return originSafetyAreaColorIndex; } set { originSafetyAreaColorIndex = value; SaveSafetyArea(); } } public float OriginAlphaParam { get { if (!hasReadFromFile) { LoadSafetyArea(); } return originAlphaParam; } set { originAlphaParam = value; SaveSafetyArea(); } } //public Color SafetyAreaColor //{ // get // { // return safetyAreaColor[originSafetyAreaColorIndex]; // } //} public float AlphaParam { get { return Mathf.Lerp(0f, 1f, originAlphaParam); } } //private GameObject savedSafetyArea; private void Awake() { DontDestroyOnLoad(this.gameObject); } private IEnumerator Start() { SafetyAreaLanguageManager.Instance.Init(); //yield return new WaitUntil(() => GSXRManager.Instance.Initialized); yield return null; if (!hasReadFromFile) { LoadSafetyArea(); } API_GSXR_Slam.GSXR_Add_SlamPauseCallback(OnLoading); } private void OnDestroy() { API_GSXR_Slam.GSXR_Remove_SlamPauseCallback(OnLoading); } private void Init(object data) { InitSafetyAreaMono(); InitStep(safetyAreaMono); safetyAreaMono.Init(data); } private void Release() { OnFinishSetSafeArea?.Invoke(); if (safetyAreaMono != null) { safetyAreaMono.Release(); GameObject.Destroy(safetyAreaGameObject); safetyAreaMono = null; areaStepDic = null; } } private void InitStep(SafetyAreaMono safetyAreaMono) { if (areaStepDic == null) { areaStepDic = new Dictionary(); areaStepDic.Add(SafetyAreaStepEnum.GroundHeight, new GroundHeightStep(safetyAreaMono)); areaStepDic.Add(SafetyAreaStepEnum.PlayArea, new PlayAreaStep(safetyAreaMono)); areaStepDic.Add(SafetyAreaStepEnum.StationaryArea, new StationaryAreaStep(safetyAreaMono)); //areaStepDic.Add(SafetyAreaStepEnum.ConfirmPlayArea, new ConfirmPlayAreaStep()); } } private void InitSafetyAreaMono() { if (safetyAreaMono == null) { GameObject safetyAreaMonoResource = Resources.Load("SafetyAreaMono"); safetyAreaGameObject = GameObject.Instantiate(safetyAreaMonoResource); safetyAreaMono = safetyAreaGameObject.GetComponent(); } //safetyAreaMono.Init(); } //创建原地区域 public void CreateStationarySafetyArea() { if (stationaryAreaMono == null) { stationaryAreaObject = new GameObject(PlayAreaConstant.STATIONARY_NAME); stationaryAreaObject.layer = 9;//1 << LayerMask.NameToLayer("SafetyArea"); float groundHeight = 0f;//GetStep(SafetyAreaStepEnum.GroundHeight).GetPlaneHeight(); Mesh cylinderMesh = SafetyAreaVertexHelper.GenerateCylinderMesh(new Vector3(0, groundHeight, 0), groundHeight + PlayAreaConstant.SAFETY_AREA_HEIGHT, groundHeight, PlayAreaConstant.STATIONARY_AREA_RADIUS); stationaryAreaMono = stationaryAreaObject.AddComponent(); stationaryAreaMono.Init(); stationaryAreaMono.SetMesh(cylinderMesh, PlayAreaConstant.STATIONARY_AREA_RADIUS); } } //销毁原地区域 public void DestroyStationaryArea() { if (stationaryAreaObject != null) { GameObject.Destroy(stationaryAreaObject); } stationaryAreaObject = null; stationaryAreaMono = null; } //创建安全网格 public void CreatePlayArea(Mesh mesh, Color[] colors, float perimeter, Vector3 worldPosition) { if (playAreaObject != null) { GameObject.Destroy(playAreaObject); } playAreaObject = new GameObject(PlayAreaConstant.PLAY_AREA_NAME); playAreaObject.layer = LayerMask.NameToLayer("SafetyArea"); playAreaObject.transform.position = new Vector3(worldPosition.x, 0f, worldPosition.z); playAreaMono = playAreaObject.AddComponent(); playAreaMono.Init(); playAreaMono.SetMesh(mesh, colors, perimeter); } public void DestroyPlayArea() { if (playAreaObject != null) { Debug.LogError("Destroy playAreaObject"); GameObject.Destroy(playAreaObject); } playAreaObject = null; playAreaMono = null; } public void StartSetSafetyArea(object data = null) { if (safetyAreaMono != null) { Debug.LogError("last set safety area process not complete"); return; } //if (savedSafetyArea != null) //{ // savedSafetyArea.SetActive(false); //} Init(data); isSettingSafetyArea = true; OnBeginSetSafeArea?.Invoke(); DestroyExistSafetyArea(); SafetyAreaCommandBuffer.Instance.AddLoading(); API_GSXR_Slam.GSXR_ResaveMap("forTest"); API_GSXR_Slam.GSXR_StartSeeThrough(); API_GSXR_Slam.GSXR_Add_SlamPauseCallback(OnSlamPause); } public void StartSetSafetyAreaHeight() { if (!CheckSafetyAreaExist()) { StartSetSafetyArea(); return; } onlySettingGroundHeight = true; Init(null); OnBeginSetSafeArea?.Invoke(); API_GSXR_Slam.GSXR_StartSeeThrough(); API_GSXR_Slam.GSXR_Add_SlamPauseCallback(OnSlamPause); } //判断安全区域是否存在 public bool CheckSafetyAreaExist() { if (!hasReadFromFile) { LoadSafetyArea(); } GameObject playArea = GameObject.Find(PlayAreaConstant.PLAY_AREA_NAME); if (playArea != null) { return true; } GameObject stationaryArea = GameObject.Find(PlayAreaConstant.STATIONARY_NAME); if (stationaryArea != null) { return true; } return false; } public SafetyAreaTypeEnum GetSafetyAreaType() { if (!CheckSafetyAreaExist()) return SafetyAreaTypeEnum.None; GameObject playArea = GameObject.Find(PlayAreaConstant.PLAY_AREA_NAME); if (playArea != null) { return SafetyAreaTypeEnum.PlayArea; } GameObject stationaryArea = GameObject.Find(PlayAreaConstant.STATIONARY_NAME); if (stationaryArea != null) { return SafetyAreaTypeEnum.Stationary; } return SafetyAreaTypeEnum.None; } //重新设置安全区域高度 //public void ResetSafetyAreaHeight() //{ // GameObject playArea = GameObject.Find(PlayAreaConstant.PLAY_AREA_NAME); // if (playArea != null) // { // playArea.GetComponent().ResetPlaneHeight(GetStep(SafetyAreaStepEnum.GroundHeight).GetPlaneHeight()); // } // GameObject stationaryArea = GameObject.Find(PlayAreaConstant.STATIONARY_NAME); // if (stationaryArea != null) // { // stationaryArea.GetComponent().ResetPlaneHeight(GetStep(SafetyAreaStepEnum.GroundHeight).GetPlaneHeight()); // } //} public void DestroyExistSafetyArea() { GameObject playArea = GameObject.Find(PlayAreaConstant.PLAY_AREA_NAME); if (playArea != null) { playArea.GetComponent().Release(); GameObject.Destroy(playArea); } GameObject stationaryArea = GameObject.Find(PlayAreaConstant.STATIONARY_NAME); if (stationaryArea != null) { stationaryArea.GetComponent().Release(); GameObject.Destroy(stationaryArea); } } public void ExitSafeAreaStep() { if (currentStep != null) { currentStep.OnExitStep(); } currentStep = null; Release(); API_GSXR_Slam.GSXR_Remove_SlamPauseCallback(OnSlamPause); API_GSXR_Slam.GSXR_StopSeeThrough(); API_GSXR_Slam.GSXR_SaveMap(); isSettingSafetyArea = false; onlySettingGroundHeight = false; stationaryAreaMono = null; stationaryAreaObject = null; playAreaMono = null; playAreaObject = null; SaveSafetyArea(true); } private void LoadSafetyArea() { hasReadFromFile = true; if (!File.Exists(PlayAreaConstant.SAVE_FILE_NAME)) { currentSafetyAreaInfo = new SafetyAreaInfo(); return; } string fileStr = File.ReadAllText(PlayAreaConstant.SAVE_FILE_NAME); currentSafetyAreaInfo = JsonUtility.FromJson(fileStr); showAreaWhenBowHead = currentSafetyAreaInfo.showAreaWhenBowHead; originAlphaParam = currentSafetyAreaInfo.originAlphaParam; originSafetyAreaColorIndex = currentSafetyAreaInfo.originSafetyAreaColorIndex; if (string.IsNullOrEmpty(currentSafetyAreaInfo.safetyAreaName)) { return; } Mesh edgeMesh = new Mesh(); edgeMesh.vertices = currentSafetyAreaInfo.vertices.ToArray(); edgeMesh.uv = currentSafetyAreaInfo.uv.ToArray(); edgeMesh.triangles = currentSafetyAreaInfo.triangles.ToArray(); GameObject safetyArea = new GameObject(currentSafetyAreaInfo.safetyAreaName); safetyArea.transform.position = currentSafetyAreaInfo.position; MeshRenderer meshRenderer = safetyArea.AddComponent(); MeshFilter meshFilter = safetyArea.AddComponent(); meshFilter.mesh = edgeMesh; meshRenderer.sharedMaterial = Resources.Load("Material/SafetyEdgeMat_Normal"); SafetyAreaBase safetyAreaBase = null; if (currentSafetyAreaInfo.safetyAreaName == PlayAreaConstant.PLAY_AREA_NAME) { safetyAreaBase = safetyArea.AddComponent(); safetyArea.GetComponent().Init(); safetyArea.GetComponent().SetColor(currentSafetyAreaInfo.colors.ToArray()); } else { safetyAreaBase = safetyArea.AddComponent(); safetyArea.GetComponent().Init(); safetyArea.GetComponent().SetRadius(currentSafetyAreaInfo.radius); } //safetyAreaBase.SetOriginHeight(currentSafetyAreaInfo.originHeight); safetyAreaBase.SetPerimeter(currentSafetyAreaInfo.perimeter); } private void SaveSafetyArea(bool overrideVertexData = false) { if (overrideVertexData) { if (CheckSafetyAreaExist()) { GameObject playArea = GameObject.Find(PlayAreaConstant.PLAY_AREA_NAME); if (playArea != null) { currentSafetyAreaInfo.safetyAreaName = PlayAreaConstant.PLAY_AREA_NAME; currentSafetyAreaInfo.position = playArea.transform.position; currentSafetyAreaInfo.vertices = new List(playArea.GetComponent().mesh.vertices); currentSafetyAreaInfo.triangles = new List(playArea.GetComponent().mesh.triangles); currentSafetyAreaInfo.uv = new List(playArea.GetComponent().mesh.uv); //currentSafetyAreaInfo.originHeight = playArea.GetComponent().GetOriginHeight(); currentSafetyAreaInfo.perimeter = playArea.GetComponent().GetPerimter(); currentSafetyAreaInfo.colors = new List(playArea.GetComponent().GetColor()); } GameObject stationaryArea = GameObject.Find(PlayAreaConstant.STATIONARY_NAME); if (stationaryArea != null) { currentSafetyAreaInfo.safetyAreaName = PlayAreaConstant.STATIONARY_NAME; currentSafetyAreaInfo.position = stationaryArea.transform.position; currentSafetyAreaInfo.vertices = new List(stationaryArea.GetComponent().mesh.vertices); currentSafetyAreaInfo.triangles = new List(stationaryArea.GetComponent().mesh.triangles); currentSafetyAreaInfo.uv = new List(stationaryArea.GetComponent().mesh.uv); //currentSafetyAreaInfo.originHeight = stationaryArea.GetComponent().GetOriginHeight(); currentSafetyAreaInfo.perimeter = stationaryArea.GetComponent().GetPerimter(); currentSafetyAreaInfo.radius = stationaryArea.GetComponent().GetRadius(); } } else { currentSafetyAreaInfo.safetyAreaName = string.Empty; currentSafetyAreaInfo.position = Vector3.zero; currentSafetyAreaInfo.vertices = null; currentSafetyAreaInfo.triangles = null; currentSafetyAreaInfo.uv = null; currentSafetyAreaInfo.originHeight = 0f; } } currentSafetyAreaInfo.showAreaWhenBowHead = ShowAreaWhenBowHead; currentSafetyAreaInfo.originAlphaParam = OriginAlphaParam; currentSafetyAreaInfo.originSafetyAreaColorIndex = OriginSafetyAreaColorIndex; if (!File.Exists(PlayAreaConstant.SAVE_FILE_NAME)) { if (!Directory.Exists(Path.GetDirectoryName(PlayAreaConstant.SAVE_FILE_NAME))) { Directory.CreateDirectory(Path.GetDirectoryName(PlayAreaConstant.SAVE_FILE_NAME)); } File.Create(PlayAreaConstant.SAVE_FILE_NAME).Dispose(); } File.WriteAllText(PlayAreaConstant.SAVE_FILE_NAME, JsonUtility.ToJson(currentSafetyAreaInfo)); } public void DestroySafetyArea() { if (CheckSafetyAreaExist()) { DestroyExistSafetyArea(); } SaveSafetyArea(); } public T GetStep(SafetyAreaStepEnum safetyAreaStepEnum) where T : class, ISafetyAreaStep { if (!areaStepDic.ContainsKey(safetyAreaStepEnum)) { return default(T); } return areaStepDic[safetyAreaStepEnum] as T; } public void ChangeStep(SafetyAreaStepEnum safetyAreaStep, object data = null) { if (currentStep != null) { currentStep.OnExitStep(); } ISafetyAreaStep nextStep = areaStepDic[safetyAreaStep]; nextStep.OnEnterStep(data); currentStep = nextStep; } public SafetyAreaStepEnum GetCurrentStepEnum() { if (currentStep == null) return SafetyAreaStepEnum.Null; return currentStep.GetStepEnum(); } public void UserCancelStep() { if (currentStep != null) { currentStep.OnUserCancel(); } } public void DelayExitSafeAreaStep(float delayTime, Action onExitComplete) { StartCoroutine(ExitSafeAreaStepCoroutine(delayTime, onExitComplete)); } public void DelayChangeStep(SafetyAreaStepEnum safetyAreaStep, float delayTime) { StartCoroutine(ChangeStepCoroutine(safetyAreaStep, delayTime)); } public void ExitSafetyAreaInvoke() { if (!alreayExitSafetyArea) { alreayExitSafetyArea = true; OnExitSafetyArea?.Invoke(); } } public void EnterSafetyAreaInvoke() { if (alreayExitSafetyArea) { alreayExitSafetyArea = false; OnEnterSafetyArea?.Invoke(); } } private IEnumerator ChangeStepCoroutine(SafetyAreaStepEnum safetyAreaStep, float delayTime) { yield return new WaitForSeconds(delayTime); ChangeStep(safetyAreaStep); } private IEnumerator ExitSafeAreaStepCoroutine(float delayTime, Action onExitComplete) { yield return new WaitForSeconds(delayTime); onExitComplete?.Invoke(); ExitSafeAreaStep(); } public void DelayShow(float delayTime, Action delayMethod) { StartCoroutine(DelayShowCoroutine(delayTime, delayMethod)); } private IEnumerator DelayShowCoroutine(float delayTime, Action delayMethod) { yield return new WaitForSeconds(delayTime); delayMethod?.Invoke(); } private void OnSlamPause(bool isPause) { if (!isPause) { API_GSXR_Slam.GSXR_StartSeeThrough(); } } private void OnLoading(bool isPause) { if (!isPause) { SafetyAreaCommandBuffer.Instance.AddLoading(); } } }