## 自己实现了父子对象功能
-
通过封装GUI可以解决一些GUI的缺陷
-
可在编辑器实时查看GUI渲染结果
-
分辨率自适应 锚点系统
-
控制GUI渲染顺序
-
CustomGUIControl:GUI位置信息类
-
可根据屏幕或父控件的九个锚点 设置位置(实现分辨率自适应)
-
或将控件挂载成子控件 使用父控件作为锚点
-
修改层级时可保持原位置
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 锚点枚举 /// </summary> public enum E_Alignment_Type { Left_UP, Center_UP, Right_UP, Left_Center, Center_Center, Right_Center, Left_Down, Center_Dwon, Right_Down } [System.Serializable] public class CustomGUIPos { /// <summary> /// 父物体 /// </summary> [HideInInspector] public CustomGUIControl faterCustom; /// <summary> /// 临时存储父控件 只有父控件改变时调用 /// </summary> private CustomGUIControl oldFaterCustom; /// <summary> /// 父物体锚点设置 /// </summary> public E_Alignment_Type fater_Alignment_Type = E_Alignment_Type.Left_UP; /// <summary> /// 控件锚点设置 /// </summary> public E_Alignment_Type contol_Alignment_Type = E_Alignment_Type.Left_UP; /// <summary> /// 控件偏移位置 /// </summary> public Vector2 offsetPos; /// <summary> /// 是否在修改物体层级时 保持原位置 /// </summary> public bool keepOriginalPos = true; /// <summary> /// 是否根据锚点反转偏移 /// </summary> public bool isOffsetInversion = true; /// <summary> /// 控件宽高 /// </summary> public float width = 0; public float height = 0; /// <summary> /// 控件计算后的位置 /// </summary> private Rect rPos; public Rect Pos { get { //控件大小 Vector2 customSize = new Vector2(width, height); //控件锚点偏移 Vector2 contolPos = PointCulator(customSize, contol_Alignment_Type); //控件xy轴位移量 Vector2 offsetInversion = isOffsetInversion ? OffsetInversion(fater_Alignment_Type) : Vector2.one; //父控件锚点位置 Vector2 faterPos = PosCulator(faterCustom, fater_Alignment_Type); //只有在父控件改变时执行 重新设置偏移 if (faterCustom != oldFaterCustom && keepOriginalPos) { offsetPos = (rPos.position - faterPos + contolPos)* offsetInversion; oldFaterCustom = faterCustom; } //父控件锚点位置-控件锚点偏移+控件xy轴位移量(反转修正*控件位移) rPos = new Rect(faterPos - contolPos + offsetInversion * offsetPos, customSize); return rPos; } private set {} } /// <summary> /// 锚点位置计算 /// </summary> /// <param name="size">控件尺寸</param> /// <param name="alignment_Type">锚点类型</param> /// <returns></returns> private Vector2 PointCulator(Vector2 size , E_Alignment_Type alignment_Type) { float x; float y; switch (alignment_Type) { case E_Alignment_Type.Left_UP: x = 0; y = 0; break; case E_Alignment_Type.Center_UP: x = 0.5f; y = 0; break; case E_Alignment_Type.Right_UP: x = 1f; y = 0; break; case E_Alignment_Type.Left_Center: x = 0; y = 0.5f; break; case E_Alignment_Type.Center_Center: x = 0.5f; y = 0.5f; break; case E_Alignment_Type.Right_Center: x = 1; y = 0.5f; break; case E_Alignment_Type.Left_Down: x = 0; y = 1; break; case E_Alignment_Type.Center_Dwon: x = 0.5f; y = 1; break; case E_Alignment_Type.Right_Down: x = 1; y = 1; break; default: x = 0; y = 0; break; } return size*new Vector2(x,y); } /// <summary> /// xy反转偏移 /// </summary> /// <param name="alignment_Type">锚点类型</param> /// <returns></returns> private Vector2 OffsetInversion(E_Alignment_Type alignment_Type) { float posX = 1; float posY = 1; switch (alignment_Type) { case E_Alignment_Type.Left_UP: break; case E_Alignment_Type.Center_UP: break; case E_Alignment_Type.Right_UP: posX = -posX; break; case E_Alignment_Type.Left_Center: break; case E_Alignment_Type.Center_Center: break; case E_Alignment_Type.Right_Center: posX = -posX; break; case E_Alignment_Type.Left_Down: posY = -posY; break; case E_Alignment_Type.Center_Dwon: posY = -posY; break; case E_Alignment_Type.Right_Down: posX = -posX; posY = -posY; break; default: break; } return new Vector2(posX,posY); } /// <summary> /// 计算控件的位置 /// </summary> /// <param name="faterCustom">父对象GUI</param> /// <param name="alignment_Type">锚点类型</param> /// <returns></returns> private Vector2 PosCulator(CustomGUIControl faterCustom, E_Alignment_Type alignment_Type) { //如果没有父控件 使用屏幕分辨率计算锚点位置 if (faterCustom == null) return PointCulator(new Vector2(Screen.width, Screen.height), alignment_Type); //拿到父控件的rect Rect faterPos = faterCustom.guiPos.Pos; //父控件的位置+ 父控件的锚点位置 return faterPos.position + PointCulator(faterPos.size,alignment_Type); } }
CustomGUIControl:GUI控件基类
-
控件脚本需要继承CustomGUIControl
-
CustomGUIRoot调用DrawGUI渲染
using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class CustomGUIControl : MonoBehaviour { public CustomGUIPos guiPos; public GUIContent content; public bool useStyle; public GUIStyle style; private Transform faterTransform; public void DrawGUI() { //只有父对象发生变化才去GetComponent //取父对象的CustomGUIControl传入guiPos if (transform.parent != faterTransform) { faterTransform = transform.parent; guiPos.faterCustom = faterTransform.GetComponent<CustomGUIControl>(); } if (useStyle) UseStyleDraw(); else NoStyleDraw(); } /// <summary> /// 使用Style调用的方法 /// </summary> protected abstract void UseStyleDraw(); /// <summary> /// 不使用Style调用的方法 /// </summary> protected abstract void NoStyleDraw(); }
CustomGUIRoot:GUI渲染类
-
用来统一控制GUI的渲染 需要将GUI控件设置为子对象
-
通过ExecuteAlways特性在编辑器中渲染GUI
-
解决GUI无法设置渲染层级的问题
using System.Collections; using System.Collections.Generic; using UnityEngine; [ExecuteAlways] public class CustomGUIRoot : MonoBehaviour { public CustomGUIControl[] contorols; void Start() { contorols = GetComponentsInChildren<CustomGUIControl>(); } private void OnGUI() { //在编辑界面获取到所有的CustomGUIControl if (!Application.isPlaying) { contorols = GetComponentsInChildren<CustomGUIControl>(); } //渲染控件 if(contorols.Length>0) foreach (var item in contorols) item.DrawGUI(); } }