using System.Collections; using System.Collections.Generic; using UnityEngine; using TableConfig; using UnityEngine.UI; using System; using DG.Tweening; namespace Snxxz.UI { public class UI3DTreasureSelectStage : MonoBehaviour { [SerializeField] Transform m_CenterStage; [SerializeField] Transform m_TreasureRoot; [SerializeField] Camera m_Camera; [SerializeField] Camera m_RenderCamera; [SerializeField] Transform m_CameraControl; [SerializeField] GameObject[] m_TreasureSkys; [SerializeField] GameObject[] m_TreasureTitles; [SerializeField] GameObject[] m_TreasureFogs; public Camera showCamera { get { return m_Camera; } } public Camera renderCamera { get { return m_RenderCamera; } } public Transform center { get { return m_CenterStage; } } public Transform treasureRoot { get { return m_TreasureRoot; } } [SerializeField] float m_Radius = 10.0f; public float radius { get { return m_Radius; } } [SerializeField] float m_IntervalAngle = 20.0f; public float intervalAngle { get { return m_IntervalAngle; } } public int forward { get { return intervalAngle > 0 ? -1 : 1; } } [SerializeField, Header("最大允许偏移")] float m_Offset = 30f; [SerializeField, Header("法宝一页个数")] int m_PageCount = 5; public int pageCount { get { return m_PageCount; } } #if UNITY_EDITOR [SerializeField, Header("法宝个数")] int m_TreasureCount = 5; public int treasureCount { get { return m_TreasureCount; } } public Vector3 normal { get { var _x = 0; var _y = Mathf.Sin(Mathf.Deg2Rad * 90); var _z = Mathf.Cos(Mathf.Deg2Rad * 90); return new Vector3(_x, _y, _z); } } [NonSerialized] public float angle = 360; #endif [SerializeField, Header("移动时长")] float m_Duration = 1.0f; public float duration { get { return m_Duration; } } [SerializeField, Header("Left")] int m_StartIndex = 3; public int startIndex { get { return m_StartIndex; } } [SerializeField, Header("灵敏系数")] float m_Sensitive = 0.1f; public float sensitive { get { return m_Sensitive <= 0 ? 1 : m_Sensitive; } } [SerializeField, Header("平静速度")] float m_SmoothVeiocity = 5.0f; public float smoothVeiocity { get { return m_SmoothVeiocity; } } [SerializeField, Header("是否处于滑动的角度范围")] float m_JudgeDrag = 0.1f; [SerializeField, Header("起始位置")] Vector3 m_StartPosition = Vector3.zero; //[SerializeField, Header("结束位置")] Vector3 m_EndPosition = Vector3.zero; [SerializeField, Header("法宝拉近时间")] float m_TweenDuration = 1.0f; [SerializeField, Header("法宝左移时间")] float m_TweenLeftDuration = 0.35f; [SerializeField] Treasure3DConfig.TreasureParam m_ChallengeSfxParam; public Treasure3DConfig.TreasureParam challengeSfxParam { get { return m_ChallengeSfxParam; } } [SerializeField] Treasure3DConfig.TreasureParam m_PotentialParam; public Treasure3DConfig.TreasureParam potentialParam { get { return m_PotentialParam; } } [SerializeField] Treasure3DConfig.TreasureParam m_AchievementParam; public Treasure3DConfig.TreasureParam achievementParam { get { return m_AchievementParam; } } [SerializeField] Treasure3DConfig.TreasureParam m_StageUpParam; public Treasure3DConfig.TreasureParam stageUpParam { get { return m_StageUpParam; } } TreasureModel m_Model; TreasureModel model { get { return m_Model ?? (m_Model = ModelCenter.Instance.GetModel()); } } static UI3DTreasureSelectStage m_Instance = null; public static UI3DTreasureSelectStage Instance { get { if (m_Instance == null) { var gameObject = Instantiate(UILoader.LoadPrefab("UI3DTreasureSelectStage")); m_Instance = gameObject.GetComponent(); m_Instance.transform.position = new Vector3(0, 3000, 4000); m_Instance.name = "UI3DTreasureSelectStage"; m_Instance.gameObject.SetActive(true); m_Instance.showCamera.enabled = false; m_Instance.renderCamera.enabled = false; DontDestroyOnLoad(gameObject); } return m_Instance; } } public TreasureCategory currentCategory { get; private set; } public bool IsCloser { get; private set; } public bool IsOpen { get; private set; } public bool CloserComplete { get; private set; } public int jumpTreasure { get; private set; } public bool UnlockShowing { get; set; } public bool Preloading { get; private set; } public GameObject currentTreasureTitle { get { if((int)currentCategory-1< m_TreasureTitles.Length) { return m_TreasureTitles[(int)currentCategory - 1]; } return null; } } public GameObject currentTreasureBackGround { get { if ((int)currentCategory - 1 < m_TreasureSkys.Length) { return m_TreasureSkys[(int)currentCategory - 1]; } return null; } } public GameObject currentTreasureFog { get { if ((int)currentCategory - 1 < m_TreasureFogs.Length) { return m_TreasureFogs[(int)currentCategory - 1]; } return null; } } public int selectTreasure { get { if (m_Treasures.ContainsKey(currentCategory) && presentSelectIndex < m_Treasures[currentCategory].Count) { return m_Treasures[currentCategory][presentSelectIndex].treasureId; } return 0; } } [NonSerialized] public int presentSelectIndex = 0; public event Action OnCameraBackComplete; public event Action OnCameraStartEvent; public event Action OnCameraCloserComplete; public event Action OnCameraBackEvent; public event Action OnUnlockComplete; private Dictionary> m_Treasures = new Dictionary>(); private Dictionary m_PreloadDict = new Dictionary(); private void InitTreasure() { Load(TreasureCategory.Human); Load(TreasureCategory.Demon); Load(TreasureCategory.Fairy); } void Load(TreasureCategory _type) { if (m_Treasures.ContainsKey(_type)) { return; } var list = new List(); m_Treasures.Add(_type, list); var _list = model.GetTreasureCategory(_type); if (_list != null) { for (int i = 0; i < _list.Count; i++) { var _component = new TreasureComponent() { treasureId = _list[i], root = (new GameObject("TreasureComponent")).transform, treasureRoot = (new GameObject("TreasureRoot")).transform, }; _component.SetLayer(LayerUtility.UILayer); _component.root.position = GetPosition(i + startIndex); _component.treasureRoot.position = GetPosition(i + startIndex); _component.root.SetParent(center); _component.treasureRoot.SetParent(treasureRoot); _component.root.LookAt(showCamera.transform); _component.treasureRoot.LookAt(showCamera.transform); TreasureInteractProcessor _interactProcessor = _component.root.AddMissingComponent(); _interactProcessor.treasureId = _list[i]; _component.interactProcessor = _interactProcessor; _component.paramConfig = ScriptableObjectLoader.LoadSoTreasure3DConfig(_list[i]); var _treasureConfig = Config.Instance.Get(_list[i]); _component.category = (TreasureCategory)_treasureConfig.Category; list.Add(_component); } } } public void Open(bool _closer = false, TreasureCategory _type = TreasureCategory.Human) { InitTreasure(); CameraController.Instance.CameraObject.gameObject.SetActive(false); m_Camera.enabled = true; WindowCenter.Instance.uiRoot.baseCanvas.gameObject.SetActive(false); SelectTreasureCategory(_type, _closer); IsOpen = true; jumpTreasure = 0; if (_closer) { var _config = ScriptableObjectLoader.LoadSoTreasure3DConfig(selectTreasure); m_CameraControl.localPosition = _config.cameraTweenParam.position; IsCloser = true; CloserComplete = true; OpenRenderCamera(); HideTreasuresExcept(presentSelectIndex); m_Treasures[currentCategory][presentSelectIndex].SetActive(true); m_Treasures[currentCategory][presentSelectIndex].CloserState(); m_Treasures[currentCategory][presentSelectIndex].SetLayer(LayerUtility.DefaultLayer); SetCloserState(); } else { var _list = m_Treasures[currentCategory]; for (int i = 0; i < _list.Count; i++) { _list[i].SetLayer(LayerUtility.UILayer); } } model.treasureStateChangeEvent += TreasureStateChangeEvent; } IEnumerator Co_PreLoad(TreasureCategory _category, Action callback) { var _list = m_Treasures[currentCategory]; for (int i = 0; i < _list.Count; i++) { _list[i].SetActive(true); _list[i].SetActive(false); yield return null; } if (callback != null) { callback(); callback = null; } } public void Close() { HideAllTreasure(); CloseRenderCamera(); var movecomponent = m_CameraControl.GetComponent(); if (movecomponent != null) { DestroyImmediate(movecomponent); } m_CameraControl.localPosition = m_StartPosition; IsCloser = false; CloserComplete = false; UnlockShowing = false; IsOpen = false; jumping = false; Preloading = false; jumpTreasure = 0; CameraController.Instance.CameraObject.gameObject.SetActive(true); m_Camera.enabled = false; WindowCenter.Instance.uiRoot.baseCanvas.gameObject.SetActive(true); model.treasureStateChangeEvent -= TreasureStateChangeEvent; model.SetTreasureUnlockShow(currentCategory, 0); if (currentTreasureTitle != null) { currentTreasureTitle.SetActive(false); } if (currentTreasureBackGround != null) { currentTreasureBackGround.SetActive(false); } if (currentTreasureFog != null) { currentTreasureFog.SetActive(false); } } private void TreasureStateChangeEvent(int _id) { var _list = m_Treasures[currentCategory]; var _component = _list.Find((x) => { return x.treasureId == _id; }); if (_component != null && _component.display) { _component.UpdateTreasureState(); _component.SetLayer(CloserComplete ? LayerUtility.DefaultLayer : LayerUtility.UILayer); } } public void SelectTreasureCategory(TreasureCategory _type, bool _closer = false) { presentSelectIndex = 0; UnlockShowing = false; currentCategory = _type; model.currentCategory = currentCategory; min_angle = startIndex * Mathf.Abs(intervalAngle); max_angle = (m_Treasures[currentCategory].Count + startIndex) * Mathf.Abs(intervalAngle); var _index = -1; if (!_closer) { _index = CheckOpenSelectTreasure(); } if (_index == -1) { var _treasureCount = m_Treasures[_type].Count; _index = _treasureCount < pageCount / 2 ? 0 : pageCount / 2; } HideAllTreasure(); InitScene(); if (!m_PreloadDict.ContainsKey(currentCategory) && !_closer) { Preloading = true; center.localEulerAngles = Vector3.zero; current_angle = 0; before_angle = 0; before_drag_angle = current_angle; StartCoroutine(Co_PreLoad(currentCategory, () => { if (!m_PreloadDict.ContainsKey(currentCategory)) { m_PreloadDict.Add(currentCategory, true); } GoTreasureFromHeader(_index); Preloading = false; })); } else { if (!m_PreloadDict.ContainsKey(currentCategory)) { m_PreloadDict.Add(currentCategory, true); } GoTreasureFromHeader(_index); } } private void InitScene() { for (int i = 0; i < m_TreasureSkys.Length; i++) { m_TreasureSkys[i].SetActive((int)currentCategory - 1 == i); } for (int i = 0; i < m_TreasureTitles.Length; i++) { m_TreasureTitles[i].SetActive((int)currentCategory - 1 == i); } for (int i = 0; i < m_TreasureFogs.Length; i++) { m_TreasureFogs[i].SetActive((int)currentCategory - 1 == i); } } private int CheckOpenSelectTreasure() { var _treasure = 0; int _index = -1; if (model.GetTreasureUnlockShow(currentCategory) != 0) { _treasure = model.GetTreasureUnlockShow(currentCategory); model.treasureGotoId = _treasure; UnlockShowing = true; } else if (model.treasureGotoId == 0) { List compares = new List(); var _list = model.GetTreasureCategory(currentCategory); compares.AddRange(_list); compares.Sort(Compare); _treasure = compares[0]; } else { _treasure = model.treasureGotoId; model.treasureGotoId = 0; } if (_treasure != 0) { _index = m_Treasures[currentCategory].FindIndex((x) => { return x.treasureId == _treasure; }); } return _index; } int Compare(int x, int y) { Treasure treasure_x; Treasure treasure_y; if (!model.TryGetTreasure(x, out treasure_x) || !model.TryGetTreasure(y, out treasure_y)) { return x.CompareTo(y); } bool collect_x = treasure_x.state == TreasureState.Collecting; bool collect_y = treasure_y.state == TreasureState.Collecting; if (collect_x != collect_y) { return -collect_x.CompareTo(collect_y); } if ((treasure_x is HumanTreasure) && (treasure_y is HumanTreasure)) { var humanTreasure_x = treasure_x as HumanTreasure; var humanTreasure_y = treasure_y as HumanTreasure; bool castSoul_x = humanTreasure_x.castSoulRedpoint.state == RedPointState.Simple; bool castSoul_y = humanTreasure_y.castSoulRedpoint.state == RedPointState.Simple; if (castSoul_x != castSoul_y) { return -castSoul_x.CompareTo(castSoul_y); } bool achieve_x = humanTreasure_x.achievementRedpoint.state == RedPointState.Simple; bool achieve_y = humanTreasure_y.achievementRedpoint.state == RedPointState.Simple; if (achieve_x != achieve_y) { return -achieve_x.CompareTo(achieve_y); } bool skillUp_x = humanTreasure_x.skillLevelUpRedpoint.state == RedPointState.Simple; bool skillUp_y = humanTreasure_y.skillLevelUpRedpoint.state == RedPointState.Simple; if (skillUp_x != skillUp_y) { return -skillUp_x.CompareTo(skillUp_y); } } bool lock_x = treasure_x.state == TreasureState.Locked; bool lock_y = treasure_y.state == TreasureState.Locked; if (lock_x != lock_y) { return -lock_x.CompareTo(lock_y); } bool up = true; bool collected_x = treasure_x.state == TreasureState.Collected; bool collected_y = treasure_y.state == TreasureState.Collected; if (collected_x && collected_y) { up = false; } return x.CompareTo(y) * (up ? 1 : -1); } public Vector3 GetPosition(int _index) { var _y = center.position.y; var _z = center.position.z + radius * Mathf.Cos(Mathf.Deg2Rad * (intervalAngle * _index)); var _x = center.position.x + radius * Mathf.Sin(Mathf.Deg2Rad * (intervalAngle * _index)); return new Vector3(_x, _y, _z); } #region 选择法宝 public void GoTreasureFromHeader(int _index) { center.localEulerAngles = Vector3.zero; current_angle = 0; before_angle = 0; before_drag_angle = current_angle; Goto(_index, true); } public void Goto(int _index, bool _force = false) { var _list = m_Treasures[currentCategory]; jumpTreasure = _list[_index].treasureId; if (!_force && _index == presentSelectIndex) { jumpTreasure = 0; return; } if (_index < _list.Count) { jumping = true; float _angle = (_index + 3) * Mathf.Abs(intervalAngle) * forward; target_angle = _angle; dragStarted = false; veiocity = 0; } } public void GotoImmediatly(int _index) { List _list; if (m_Treasures.TryGetValue(currentCategory, out _list)) { if (_index >= _list.Count) { return; } float _angle = (_index + 3) * Mathf.Abs(intervalAngle) * forward; target_angle = _angle; center.Rotate(center.up, _angle - current_angle); current_angle = _angle; before_angle = current_angle; if (IsCloser) { _list[presentSelectIndex].OutCloserState(); _list[presentSelectIndex].SetLayer(LayerUtility.UILayer); _list[presentSelectIndex].SetActive(false); _list[_index].SetActive(true); _list[_index].UpdateParam(); _list[_index].CloserState(); _list[_index].SetLayer(LayerUtility.DefaultLayer); var _config = ScriptableObjectLoader.LoadSoTreasure3DConfig(_list[_index].treasureId); m_CameraControl.localPosition = _config.cameraTweenParam.position; } presentSelectIndex = _index; } } public void OnPointDownTreasure(int _treasureId) { if (IsCloser || UnlockShowing || jumping || draging || BossShowModel.Instance.BossShowing) { return; } Treasure treasure; if (model.TryGetTreasure(102, out treasure) && treasure.state == TreasureState.Locked) { return; } var _list = m_Treasures[currentCategory]; var _index = _list.FindIndex((x) => { return x.treasureId == _treasureId; }); if (_index != -1) { model.openFromTreasureList = true; Goto(_index); StartCloser(); } } private void OnJumpComplete() { if (UnlockShowing) { var _component = m_Treasures[currentCategory][presentSelectIndex]; _component.PlayUnlockShow(); } jumpTreasure = 0; } #endregion #region 滑动 bool draging = false; bool dragStarted = false; bool jumping = false; float veiocity = 0; float min_angle = 0; float max_angle = 0; float target_angle = 0; float drag_angle = 0; float before_drag_angle = 0; float current_angle = 0; float before_angle = 0; public void BegineDrag() { if (IsCloser || UnlockShowing) { return; } jumping = false; dragStarted = true; drag_angle = 0; veiocity = 0; before_drag_angle = current_angle; } public void Drag(float _delta) { if (IsCloser || jumping || !dragStarted) { return; } drag_angle += _delta * sensitive; var _angle = before_drag_angle + drag_angle; _angle = Mathf.Clamp(_angle * forward, min_angle - Mathf.Abs(intervalAngle), max_angle + Mathf.Abs(intervalAngle)) * forward; target_angle = _angle; } public void DragEnd() { dragStarted = false; } #endregion private void LateUpdate() { if (!IsOpen || Preloading) { return; } if (m_Treasures.ContainsKey(currentCategory)) { current_angle = Mathf.SmoothDamp(current_angle, target_angle, ref veiocity, duration); var _deltaAngle = current_angle - before_angle; if (Mathf.Abs(_deltaAngle) > m_Offset) { _deltaAngle = _deltaAngle > 0 ? m_Offset : -m_Offset; current_angle = _deltaAngle + before_angle; } before_angle = current_angle; center.Rotate(center.up, _deltaAngle); if (!CloserComplete) { CheckDisplay(); } if (!jumping) { CheckElastic(); } draging = Mathf.Abs(target_angle - current_angle) > m_JudgeDrag; if (!draging && jumping) { jumping = false; OnJumpComplete(); jumpTreasure = 0; } } } #region 滑动 private void CheckDisplay() { var _list = m_Treasures[currentCategory]; for (int i = 0; i < _list.Count; i++) { _list[i].root.LookAt(center); #if UNITY_EDITOR if (_list[i].display) { _list[i].UpdateParam(); } #endif float _angle = Vector3.Angle(_list[i].root.position - center.position, GetPosition(0) - center.position); if (Mathf.Abs(_angle) <= Mathf.Abs(intervalAngle) - 10 && (_list[i].display || IsCloser)) { presentSelectIndex = i; } if (IsCloser) { continue; } if (Mathf.Abs(i - presentSelectIndex) > startIndex) { if (_list[i].display) { OutOfView(i, true); } } else if (!_list[i].display) { OutOfView(i, false); } } } private void CheckElastic() { if (target_angle * forward > max_angle) { float _angle = (m_Treasures[currentCategory].Count - 1 + startIndex) * Mathf.Abs(intervalAngle); target_angle = _angle * forward; } else if (target_angle * forward < min_angle) { float _angle = startIndex * Mathf.Abs(intervalAngle); target_angle = _angle * forward; } else if (Mathf.Abs(veiocity) < smoothVeiocity) { float _angle = (presentSelectIndex + startIndex) * Mathf.Abs(intervalAngle); target_angle = _angle * forward; } } #endregion #region 显示或隐藏法宝 private void OutOfView(int _index, bool _out) { var _list = m_Treasures[currentCategory]; if (_out && _list[_index].display) { _list[_index].SetActive(false); } else if (!_out && !_list[_index].display) { _list[_index].SetActive(true); } } private void ResetTreasureCategory() { foreach (var _key in m_Treasures.Keys) { var _list = m_Treasures[_key]; for (int i = 0; i < _list.Count; i++) { if (_key != currentCategory) { _list[i].SetActive(false); } else { bool _display = Mathf.Abs(i - presentSelectIndex) < startIndex; _list[i].SetActive(_display); } } } } private void HideTreasuresExcept(int _index) { var _list = m_Treasures[currentCategory]; for (int i = 0; i < _list.Count; i++) { if (i != _index && _list[i].display) { _list[i].SetActive(false); } } } private void HideAllTreasure() { foreach (var _key in m_Treasures.Keys) { var _list = m_Treasures[_key]; for (int i = 0; i < _list.Count; i++) { _list[i].OutCloserState(); _list[i].SetActive(false); _list[i].SetLayer(LayerUtility.UILayer); } } } private void ShowNearTreasure(int _index) { var _list = m_Treasures[currentCategory]; for (int i = 0; i < _list.Count; i++) { if (Mathf.Abs(i - _index) <= startIndex && !_list[i].display) { _list[i].SetActive(true); } } } #endregion #region 摄像机移动事件 public void StartCloser() { IsCloser = true; CloserComplete = false; if (OnCameraStartEvent != null) { OnCameraStartEvent(); } var _index = m_Treasures[currentCategory].FindIndex((x) => { return x.treasureId == jumpTreasure; }); _index = _index != -1 ? _index : presentSelectIndex; HideTreasuresExcept(_index); m_Treasures[currentCategory][_index].CloserState(); var _config = ScriptableObjectLoader.LoadSoTreasure3DConfig(m_Treasures[currentCategory][_index].treasureId); SmoothMove.MoveTo(m_CameraControl.gameObject, _config.cameraTweenParam.position, m_TweenDuration, true, OnCloserComplete); SetCloserState(); } private void SetCloserState() { if (currentTreasureTitle != null) { currentTreasureTitle.SetActive(false); } } private void OnCloserComplete() { if (!IsOpen) { return; } CloserComplete = true; OpenRenderCamera(); m_Treasures[currentCategory][presentSelectIndex].SetLayer(LayerUtility.DefaultLayer); if (OnCameraCloserComplete != null) { OnCameraCloserComplete(); } } public void StartBack() { CloserComplete = false; SmoothMove.MoveTo(m_CameraControl.gameObject, m_StartPosition, m_TweenDuration, true, CameraBackComplete); ShowNearTreasure(presentSelectIndex); CloseRenderCamera(); m_Treasures[currentCategory][presentSelectIndex].OutCloserState(); m_Treasures[currentCategory][presentSelectIndex].SetLayer(LayerUtility.UILayer); if (currentTreasureTitle != null) { currentTreasureTitle.SetActive(true); } if (OnCameraBackEvent != null) { OnCameraBackEvent(); } } private void CameraBackComplete() { if (!IsOpen) { return; } IsCloser = false; if (OnCameraBackComplete != null) { OnCameraBackComplete(); } var _list = m_Treasures[currentCategory]; for (int i = 0; i < _list.Count; i++) { _list[i].SetLayer(LayerUtility.UILayer); } } #endregion #region 法宝专用摄像机 public void OpenRenderCamera() { renderCamera.enabled = true; } public void CloseRenderCamera() { renderCamera.enabled = false; } public void Tween(Action callback) { SetStartState(); StartCoroutine(Co_RenderCameraTween(callback, m_TweenLeftDuration)); var config = ScriptableObjectLoader.LoadSoTreasure3DConfig(selectTreasure); var _tweener = renderCamera.transform.DOLocalMove(config.renderCameraParam.position, m_TweenLeftDuration); _tweener.SetEase(Ease.Linear); } IEnumerator Co_RenderCameraTween(Action callback, float _duration) { var _timer = 0f; while (_timer < _duration && IsOpen && IsCloser) { var _target = 0.62f * _timer / _duration; renderCamera.rect = new Rect(-_target, 0, 1, 1); yield return null; _timer += Time.deltaTime; } SetEndState(); if (callback != null) { callback(); callback = null; } } public void SetStartState() { renderCamera.rect = new Rect(0, 0, 1, 1); renderCamera.transform.localPosition = Vector3.zero; } public void SetEndState() { renderCamera.rect = new Rect(-0.62f, 0, 1, 1); var config = ScriptableObjectLoader.LoadSoTreasure3DConfig(selectTreasure); renderCamera.transform.localPosition = config.renderCameraParam.position; } #endregion #region 解锁动画播放完成 public void CompleteUnlock() { if (OnUnlockComplete != null) { OnUnlockComplete(); } } #endregion } }