using System; using Games.Events; using Module.Log; using System.Collections.Generic; using GCGame.Table; using UnityEngine; using UnityEngine.Events; namespace Games.LogicObj { // 近世界层UI,该层UI可以认为是每一帧都需要重新拼合 public class WorldUIRoot : MonoBehaviour { // 暂时不构造从UiManager向下初始化的结构,不析构的管理器直接用Instance自己管理 public static WorldUIRoot Instance { get; private set; } //public const float maxScale = 1f; //public const float minScale = 0.2f; //// 像素宽度到世界宽度转化数值 //public float PixelToWorld { get; private set; } private List<WorldUIItem> _uiItemList; private UiItemPool<WorldUIItem, WorldUiLoadData, WorldUiLoadTask> _uiItemPool; // Destroy之后不回收任何物品 private bool _isDestroyed; private Canvas _canvas; #region Head UI public static bool ShowHeadUi { get { return PlayerPreferenceData.SystemNameBoard; } } private RectTransform _headUiRoot; private RectTransform _damageUiRoot; public void ShowOrHideHeadRoot(bool IsShow) { if (_headUiRoot) _headUiRoot.gameObject.SetActive(IsShow); } public void ResetShowHeadUi() { for (var i = 0; i < _uiItemList.Count; i++) { var headUi = _uiItemList[i] as Obj_HeadUI; if (headUi) headUi.ResetShow(); } } /// <summary> /// 请求一个HeadUi物体 /// </summary> public void LoadHeadUi(ObjParent objParent) { var loadData = new WorldUiLoadData(objParent, _headUiRoot, OnHeadUiLoadTaskComplete); _uiItemPool.PullItem(loadData, objParent.HeadUiPath); } public void StopLoadHeadUi(ObjParent objParent) { // 无视这个警告 - 常规指针检测方式 #pragma warning disable 252,253 _uiItemPool.RemoveLoadTask(a => a.data == objParent); #pragma warning restore 252,253 } private void OnHeadUiLoadTaskComplete(WorldUIItem worldUiItem, WorldUiLoadData loadData) { if (worldUiItem == null) return; // Obj在加载中被析构的稀有情况 if (loadData.data == null) _uiItemPool.PushItem(worldUiItem.uiPathData, worldUiItem); else { var error = false; try { ((ObjParent)loadData.data).BindHeadUi(worldUiItem); } catch (Exception e) { LogModule.ErrorLog(e.ToString()); error = true; } if (error) worldUiItem.BackToPool(); else _uiItemList.Add(worldUiItem); } } #endregion #region Damage Board /// <summary> /// 显示伤害信息 /// </summary> /// <param name="nType">伤害类型</param> /// <param name="strValue">字符串</param> /// <param name="pos">世界位置</param> /// <param name="isProfessionSkill">是否职业技能</param> public void ShowDamageBoard(int nType, string strValue, Vector3 pos, bool isProfessionSkill = true) { if (!PlayerPreferenceData.SystemDamageBoardEnable) return; var data = DamageBoardManager.damageBoardManager.TryAddDamageBoard(nType); if (data != null) { bool hightLayer = ( (nType == (int)Games.GlobeDefine.GameDefine_Globe.DAMAGEBOARD_TYPE.PLAYER_EXP_UP) || (nType == (int)Games.GlobeDefine.GameDefine_Globe.DAMAGEBOARD_TYPE.YINPIAO_UP) || (nType == (int)Games.GlobeDefine.GameDefine_Globe.DAMAGEBOARD_TYPE.YINLING_UP) || (nType == (int)Games.GlobeDefine.GameDefine_Globe.DAMAGEBOARD_TYPE.YUANBAO_UP) || (nType == (int)Games.GlobeDefine.GameDefine_Globe.DAMAGEBOARD_TYPE.LINGYU_UP) ); RectTransform _damageExpUiRoot = (UIManager.Instance() != null ? UIManager.Instance().DamageHightRoot : null); RectTransform root = (hightLayer && _damageExpUiRoot != null ? _damageExpUiRoot : _damageUiRoot); var taskStarter = new WorldUiLoadData(new DamageBoardData(data, strValue, pos, isProfessionSkill), root, OnDamageBoardLoadTaskComplete); _uiItemPool.PullItem(taskStarter, DamageBoard.PathData); } } private void OnDamageBoardLoadTaskComplete(WorldUIItem damageUiItem, WorldUiLoadData loadData) { var data = (DamageBoardData) loadData.data; var damageBoard = (DamageBoard) damageUiItem; damageBoard.ActiveDamageBoard(data.data, data.strValue, data.worldPos, data.isProfessionSkill); _uiItemList.Add(damageBoard); } // 注:这个指令应该同所有角色析构是同一帧,因此可以析构HeadUi public void ClearDamageBoard() { if (!_isDestroyed) { for (var i = 0; i < _uiItemList.Count; i++) { var uiItem = _uiItemList[i]; if (uiItem.itemType == WorldUiItemType.DamageBoard) Recovery(uiItem.uiPathData, uiItem); } DamageBoardManager.damageBoardManager.ClearNumber(); } } #endregion #region AnchoredText public void ShowCountdownOnCharacter(int objId, int countdown) { var textData = new AnchoredTextData(objId, Time.unscaledTime + (float)countdown); var taskStarter = new WorldUiLoadData(textData, _damageUiRoot, OnCountDownLoadTaskComplete); _uiItemPool.PullItem(taskStarter, AnchoredText.PathData); } private void OnCountDownLoadTaskComplete(WorldUIItem damageUiItem, WorldUiLoadData loadData) { var data = (AnchoredTextData) loadData.data; var anchoredText = (AnchoredText) damageUiItem; anchoredText.SetInitData(data); _uiItemList.Add(anchoredText); } #endregion private void Awake() { Instance = this; _canvas = GetComponent<Canvas>(); _uiItemList = new List<WorldUIItem>(); _uiItemPool = new UiItemPool<WorldUIItem, WorldUiLoadData, WorldUiLoadTask>((RectTransform)transform.Find("PoolRoot")); _headUiRoot = (RectTransform)transform.Find("NameBoardRoot"); _damageUiRoot = (RectTransform) transform.Find("DamageBoardRoot"); } private void Start() { EventDispatcher.Instance.Add(Events.EventId.PostMainCameraMove, PostMainCameraMove); EventDispatcher.Instance.Add(Events.EventId.UiCameraCopy, OnUiCameraCopy); // 等TableManager一帧 // PixelToWorld = 1f; float.Parse(TableManager.GetSystemParamByID(6, 0).StringValue); } private void OnDestroy() { if (Instance == this) Instance = null; _isDestroyed = true; EventDispatcher.Instance.Remove(Events.EventId.PostMainCameraMove, PostMainCameraMove); EventDispatcher.Instance.Remove(Events.EventId.UiCameraCopy, OnUiCameraCopy); } private int _hideCamera; private void OnUiCameraCopy(object args) { var start = (bool)args; _hideCamera = _hideCamera.ReplaceFlag(0.ToFlag(), start); ResetHideCamera(); } //private void OnSceneMovie(object args) //{ // var start = (bool)args; // _hideCamera = _hideCamera.ReplaceFlag(1.ToFlag(), start); // ResetHideCamera(); //} private void ResetHideCamera() { _canvas.enabled = _hideCamera <= 0; } private void PostMainCameraMove(object args) { // 注:可能有设置位置时,要求被回收的情况 for (var i = _uiItemList.Count - 1; i >= 0; i--) { // 加固,防止固化流程被其他模块破坏 try { var activeItem = _uiItemList[i]; if (activeItem.CheckPositionValid() && activeItem.CheckDuration()) { // 屏蔽缩放功能直到修复 //if (activeItem.scaleByWorldPos) // uiPos = GetUiPositionAndScale(activeItem.worldPosition, activeItem.pixelWidth, out scale); //else //{ var uiPos = UIManager.Instance().WorldToUiPoint(activeItem.worldPosition); const float scale = 1f; //} activeItem.SetPositionAndScale(uiPos, scale); } else { // 伤害面板回收需要清除使用计数 if (activeItem.itemType == WorldUiItemType.DamageBoard && DamageBoardManager.damageBoardManager != null) { var damageBoard = (DamageBoard) activeItem; DamageBoardManager.damageBoardManager.RemoveDamageBoard(damageBoard.data.DamageBoardTypeID); } activeItem.BackToPool(); } } catch (System.Exception e) { LogModule.ErrorLog(_uiItemList[i] == null ? "World Ui Root 中发现为空的物体!" : string.Format("{0}发生故障!", _uiItemList[i].transform.GetHierarchyName())); LogModule.ErrorLog(e.ToString()); } } } /// <summary> /// 世界坐标转到UI坐标体系下的位置和缩放 /// </summary> /// <param name="worldPos">世界坐标位置</param> /// <param name="pixelWidth">组件预期像素宽度</param> /// <param name="scale">Ui空间的缩放数值</param> //public Vector3 GetUiPositionAndScale(Vector3 worldPos, float pixelWidth, out float scale) //{ // var sceneCamera = UIManager.Instance().GetWorldCamera(); // var worldWidth = pixelWidth * PixelToWorld; // // 默认世界摄像机是投影摄像机 // // 实际是摄像机的forward,叉乘之后才是right // var right = worldPos - sceneCamera.transform.position; // right = Vector3.Cross(Vector3.up, right); // if (right == Vector3.zero) // right = sceneCamera.transform.right; // right = right.normalized; // var pos0 = worldPos - right * 0.5f * worldWidth; // var pos1 = worldPos + right * 0.5f * worldWidth; // // 像素位置 // pos0 = UIManager.Instance().WorldToUiPoint(pos0); // pos1 = UIManager.Instance().WorldToUiPoint(pos1); // scale = Mathf.Clamp((pos1.x - pos0.x) / pixelWidth, minScale, maxScale); // return (pos0 + pos1) * 0.5f; //} public void SetShow(bool isShow) { _canvas.enabled = isShow; } public void Recovery(UIPathData pathData, WorldUIItem item) { if (!_isDestroyed) { _uiItemList.Remove(item); _uiItemPool.PushItem(pathData, item); } } public class WorldUiLoadData : BaseLoadData<WorldUIItem, WorldUiLoadData> { public object data; public WorldUiLoadData(object pData, Transform root, UnityAction<WorldUIItem, WorldUiLoadData> callback) : base(root, callback) { data = pData; } } public class WorldUiLoadTask : BaseLoadTask<WorldUIItem, WorldUiLoadData, WorldUiLoadTask> { } public class DamageBoardData { public Tab_DamageBoardType data; public string strValue; public Vector3 worldPos; public bool isProfessionSkill; public DamageBoardData(Tab_DamageBoardType data, string strValue, Vector3 worldPos, bool isProfessionSkill) { this.data = data; this.strValue = strValue; this.worldPos = worldPos; this.isProfessionSkill = isProfessionSkill; } } public class AnchoredTextData { public int objId; public float endTime; public AnchoredTextData(int objId, float endTime) { this.objId = objId; this.endTime = endTime; } } public enum WorldUiItemType { HeadInfo, // 头顶面板 DamageBoard, // 伤害面板 AnchorText, // 倒计时面板 } } }