本文共 9622 字,大约阅读时间需要 32 分钟。
RectAToB组件
在游戏开发中经常中经常会有这样的需求,需要一个tips界面在某个图标的旁边显示。于是我写了一个RectAToB 方法 之前写的那一版存在一些问题 这一版本可以应对显示不下的情况智能改变tips位置 以下是全部c#代码 需要的同学可以改一改
需要特别注意的是某些tips界面如果是生成后会动态调整大小的,可能需要你延后一帧去处理逻辑,避免位置偏差。
using UnityEngine;
using UnityEngine.UI;#if UNITY_EDITOR
using UnityEditor; #endif#if UNITY_EDITOR
[CustomEditor(typeof(RectAToB))] public class RectAToBEditor : Editor { public override void OnInspectorGUI() { base.OnInspectorGUI(); if(GUILayout.Button("移动")) { (target as RectAToB).Move(); } } } [ExecuteInEditMode] #endif public class RectAToB : MonoBehaviour { public RectTransform wndA; public RectTransform wndB; private RectTransform canvasRect; private Camera m_camera = null; public enum POS{ BOTTOM_LEFT =1, // 下左 BOTTOM_CENTER, // 下中 BOTTOM_RIGHT, // 下右UP_LEFT, // 上左
UP_RIGHT , // 上右 UP_CENTER,LEFT_TOP, // 左上
LEFT_CENTER_UP , // 左上up 补充2个方向 LEFT_CENTER_DOWN , // 左上up 补充2个方向 LEFT_BOTTOM, // 左下RIGHT_TOP , // 右上
RIGHT_CENTER_UP , //右中上 RIGHT_CENTER_DOWN , // 右中下 RIGHT_BOTTOM, // 右下CENTER_CENTER , // 中心
SCREEN_CENTER, // ui元素中心 } public Vector2 offset; public POS m_style = POS.LEFT_TOP; public POS m_originStyle; // 最初的设定 tips样式 private int[] limitArray4; private int callCount = 0; // 调用计次 防止死递归调用 许多设计都用用调用计次的概念 比如事件服的设计(防止事件死循环) void Awake() { this.canvasRect = GameObject.Find("UGuiSystem/MainCanvas").GetComponent<RectTransform>(); this.m_camera = GameObject.Find("UGuiSystem").GetComponent<Camera>(); }public bool TestOutOfScreen(int pos, Vector2 spos) // 检测是否已经离屏了
{ var epos = (POS)pos;if (limitArray4 == null || limitArray4.Length == 0)
{ //我们游戏是居中,估计一般主canvas也都是这个规格 if (canvasRect.pivot.x == 0.5 && canvasRect.pivot.y == 0.5) { limitArray4 = new int[] { Screen.height / 2, -Screen.width / 2, -Screen.height / 2, Screen.width / 2 }; } else if (canvasRect.pivot.x == 0 && canvasRect.pivot.y == 0) { limitArray4 = new int[] { Screen.height, 0, 0, Screen.width }; } } // Debug.Log("spos.x =" + spos.x.ToString() + ",spos.y =" + spos.y.ToString()); if (epos == POS.RIGHT_TOP) { if (spos.x + (1 - wndA.pivot.x) * wndA.sizeDelta.x > limitArray4[3]) { // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.LEFT_TOP"); this.m_style = POS.LEFT_TOP; offset.x = -offset.x; return false; } else if (spos.y + (1 - wndA.pivot.y) * wndA.sizeDelta.y > limitArray4[0]) { // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.RIGHT_BOTTOM"); this.m_style = POS.RIGHT_BOTTOM; offset.y = -offset.y; return false; } }else if (epos == POS.LEFT_TOP)
{if (spos.x - wndA.pivot.x * wndA.sizeDelta.x < limitArray4[1])
{ // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.RIGHT_TOP"); this.m_style = POS.RIGHT_TOP; offset.x = -offset.x; return false; } else if (spos.y + (1 - wndA.pivot.y) * wndA.sizeDelta.y > limitArray4[0]) { // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.LEFT_BOTTOM"); this.m_style = POS.LEFT_BOTTOM; offset.y = -offset.y; return false; } }else if (epos == POS.LEFT_BOTTOM)
{ if (spos.x - wndA.pivot.x * wndA.sizeDelta.x < limitArray4[1]) { // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.RIGHT_BOTTOM"); this.m_style = POS.RIGHT_BOTTOM; offset.x = -offset.x; return false; } else if (spos.y - wndA.pivot.y * wndA.sizeDelta.y < limitArray4[2]) { // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.LEFT_TOP"); this.m_style = POS.LEFT_TOP; offset.y = -offset.y; return false; } } else if (epos == POS.RIGHT_BOTTOM) {if (spos.x + (1 - wndA.pivot.x) * wndA.sizeDelta.x > limitArray4[3])
{ // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.LEFT_BOTTOM"); this.m_style = POS.LEFT_BOTTOM; offset.x = -offset.x; return false; } else if (spos.y - wndA.pivot.y * wndA.sizeDelta.y < limitArray4[2]) { // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.RIGHT_TOP"); this.m_style = POS.RIGHT_TOP; offset.y = -offset.y; return false; } } else // 只需要适配4个方位,其他的位置可以通过这4个方位做偏移来实现 { return false; }return true;
} public void Move() { this.m_style = this.m_originStyle; callCount = 0; if (wndA == null || wndB == null) { return; } if(m_camera == null) { this.m_camera = GameObject.Find("UGuiSystem").GetComponent<Camera>(); } if(m_camera == null) { return; } if (this.canvasRect == null) { this.canvasRect = GameObject.Find("UGuiSystem/MainCanvas").GetComponent<RectTransform>(); } if(this.canvasRect == null) { return; } if(wndA.anchorMin.x != 0.5f || wndA.anchorMin.y != 0.5f || wndA.anchorMax.x != 0.5f || wndA.anchorMax.y != 0.5f) { //后续有时间再去处理不同anchorMin or Max的情况下对应的离屏测试 rktLogUtil.GLog("RectAToB 错误 请确保wndA的坐标系统是以图元的中心为中心"); return; } //获取目标窗口的世界坐标 var worldB = Vector3.zero; RectTransformUtility.ScreenPointToWorldPointInRectangle( canvasRect, m_camera.WorldToScreenPoint(wndB.position), m_camera, out worldB );wndA.transform.position = worldB;
MoveImp(); // Debug.Log("A的最终ui" + wndA.anchoredPosition); }private void MoveImp()
{ callCount = callCount + 1; if (callCount > 4) { //如果4个离屏测试都未能通过那么应该按原始tips来做 或者指定一个坐标去做 考虑一个偏移 var worldB = Vector3.zero; RectTransformUtility.ScreenPointToWorldPointInRectangle( canvasRect, m_camera.WorldToScreenPoint(canvasRect.position), m_camera, out worldB ); this.m_style = POS.SCREEN_CENTER; // 方便debug wndA.transform.position = worldB; var atoScreenCenterOffset = GetPosAnchoredPosition((int)POS.SCREEN_CENTER); SetAnchoredPosition(wndA.anchoredPosition + atoScreenCenterOffset + offset); return; } var atoBoffset = GetPosAnchoredPosition((int)this.m_style); // Debug.Log("A的世界" + wndA.transform.position + "A的ui" + wndA.anchoredPosition + "atoBoffset =" + atoBoffset); var finalPos = wndA.anchoredPosition + atoBoffset + offset; if (TestOutOfScreen((int)m_style, finalPos)) { SetAnchoredPosition(wndA.anchoredPosition + atoBoffset + offset); } else { MoveImp(); } } public void SetStyle(int pos) { m_originStyle = (POS)pos; this.m_style = (POS)pos; }public int GetStyle()
{ return (int)this.m_style; }public void SetAnchoredPosition(Vector2 pos) // 暴露给外部lua方便扩展
{ wndA.anchoredPosition = pos; }public Vector2 GetPosAnchoredPosition(int st) // 暴露给外部lua
{ var style = (POS)st; Vector2 atoBoffset = Vector2.zero; if (style == POS.LEFT_TOP) { atoBoffset.x = (wndA.pivot.x - 1) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y) * wndB.sizeDelta.y + (wndA.pivot.y ) * wndA.sizeDelta.y; } else if (style == POS.RIGHT_TOP) { atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y; }else if (style == POS.LEFT_BOTTOM)
{ atoBoffset.x = (wndA.pivot.x - 1) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x; atoBoffset.y = (-wndB.pivot.y) * wndB.sizeDelta.y - (1 - wndA.pivot.y) * wndA.sizeDelta.y; } else if (style == POS.RIGHT_BOTTOM) { atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x; atoBoffset.y = (-wndB.pivot.y) * wndB.sizeDelta.y - (1 - wndA.pivot.y) * wndA.sizeDelta.y; } else if (style == POS.SCREEN_CENTER) { atoBoffset.x = (wndA.pivot.x -0.5f) * wndA.sizeDelta.x ; atoBoffset.y = (wndA.pivot.y - 0.5f) * wndA.sizeDelta.y; } else if (style == POS.UP_LEFT) { atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y; } else if (style == POS.BOTTOM_LEFT) { atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y - 1) * wndB.sizeDelta.y + (wndA.pivot.y - 1) * wndA.sizeDelta.y; } else if (style == POS.LEFT_CENTER_UP) { atoBoffset.x = (wndA.pivot.x - 1) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y - 0.5f) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y; } else if (style == POS.LEFT_CENTER_DOWN) { atoBoffset.x = (wndA.pivot.x - 1) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y - 0.5f) * wndB.sizeDelta.y + (wndA.pivot.y - 1) * wndA.sizeDelta.y; } else if (style == POS.RIGHT_CENTER_UP) { atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y - 0.5f) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y; } else if (style == POS.RIGHT_CENTER_DOWN) { atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y - 0.5f) * wndB.sizeDelta.y + (wndA.pivot.y - 1) * wndA.sizeDelta.y; }else if (style == POS.UP_CENTER)
{ atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 0.5f) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y; } else if (style == POS.BOTTOM_CENTER) { atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 0.5f) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y - 1) * wndB.sizeDelta.y + (wndA.pivot.y - 1) * wndA.sizeDelta.y; } else if (style == POS.CENTER_CENTER) { atoBoffset.x = (wndA.pivot.x - 0.5f) * wndA.sizeDelta.x - (wndB.pivot.x - 0.5f) * wndB.sizeDelta.x; atoBoffset.y = (wndB.pivot.y + 0.5f) * wndB.sizeDelta.y + (wndA.pivot.y - 0.5f) * wndA.sizeDelta.y; } else if (style == POS.UP_RIGHT) { atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y; } else if (style == POS.BOTTOM_RIGHT) { atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x; atoBoffset.y = (1 - wndB.pivot.y - 1) * wndB.sizeDelta.y + (wndA.pivot.y - 1) * wndA.sizeDelta.y; } return atoBoffset; } }转载地址:https://blog.csdn.net/yangjie6898862/article/details/109692799 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!