1. 程式人生 > 實用技巧 >Unity ugui Anchor錨點自動適配畫布中的相對位置

Unity ugui Anchor錨點自動適配畫布中的相對位置

本隨筆參考了以下部落格,在此基礎上進行優化和改進:

https://blog.csdn.net/qq_39640124/article/details/88284191

ugui中的Anchor預設如下:

允許我們快速對齊父物體的一部分軸向頂點或邊,但有時我們並不是要對齊這些,而是需要對齊特定位置的某個點,例如:

如上圖,上面的作戰結束之後的等級資訊B它應該是對齊父物體面板的什麼位置呢?

當然了,你可以簡單的將它設定為對齊螢幕右側中點或者右上,那麼此時無論螢幕解析度如何改變,它的錨點Pivot距離螢幕右邊緣的距離都不變。

但如果出現一種極端例子,螢幕的寬度小到比預設的距離還小,那麼B早就跑到螢幕左側去了。

顯然,這樣的Anchor預設調整是不太精準的,在螢幕解析度改變較大時,很多不同對齊方式的元素有極大機率出現位置偏移甚至重疊。

ugui除了通過自帶的預設,也可以手動輸入Anchor的最大值和最小值來調整,當最大值和最小值相同時,它對齊的是相對百分比的一個點:

例如上面的B字母的中點精準的對齊方式是,距離父物體畫布寬的82.9%高72.7%左右的位置,這樣無論父物體隨著解析度如何改變,B的相對位置都保持不變。

值得注意的是,為了保證無任何偏移的可能,需要保證anchoredPosition為零,也就是面板中Pos為零。

但很遺憾的是,Unity編輯器暫時還沒有辦法自動對齊Anchor到物體的錨點Pivot或邊框,當然了你可以每次嘗試手動拖動,但保證你馬上就會有口區的感覺,而且總會差那麼一點對不齊。

下面是自動對齊的編輯器指令碼,在網上參考了之前網友寫過的對齊邊框的寫法,但發現只要錨點Pivot不在物件中心就會自動移動物體位置,在這裡進行了一些優化修正,並增加了另一種對齊模式:

 using UnityEngine;
using UnityEditor; public class AnchorsAdapt
{
[MenuItem("Tools/AnchorsAdaptSize")]
private static void SelectionMS()
{
GameObject[] gos = Selection.gameObjects;
for (int i = ; i < gos.Length; i++)
{
if (gos[i].GetComponent<RectTransform>() == null)
continue;
AdaptSize(gos[i]);
}
} [MenuItem("Tools/AnchorsAdaptPivot")]
private static void SelectionMP()
{
GameObject[] gos = Selection.gameObjects;
for (int i = ; i < gos.Length; i++)
{
if (gos[i].GetComponent<RectTransform>() == null)
continue;
AdaptPivot(gos[i]);
}
} private static void AdaptPivot(GameObject go)
{
//------獲取rectTransform----
RectTransform partentRect = go.transform.parent.GetComponent<RectTransform>();
RectTransform localRect = go.GetComponent<RectTransform>(); //位置資訊
Vector3 partentPos = go.transform.parent.position;
Vector3 localPos = go.transform.position; float partentWidth = partentRect.rect.width;
float partentHeight = partentRect.rect.height; //---------位移差------
float offX = localPos.x - partentPos.x;
float offY = localPos.y - partentPos.y; float rateW = offX / partentWidth;
float rateH = offY / partentHeight;
var anchor = new Vector2(.5f + rateW, .5f + rateH);
localRect.SetRtAnchorSafe(anchor, anchor);
} private static void AdaptSize(GameObject go)
{
//位置資訊
Vector3 partentPos = go.transform.parent.position;
Vector3 localPos = go.transform.position;
//------獲取rectTransform----
RectTransform partentRect = go.transform.parent.GetComponent<RectTransform>();
RectTransform localRect = go.GetComponent<RectTransform>(); float partentWidth = partentRect.rect.width;
float partentHeight = partentRect.rect.height;
float localWidth = localRect.rect.width * 0.5f;
float localHeight = localRect.rect.height * 0.5f;
//---------位移差------
float offX = localPos.x - partentPos.x;
float offY = localPos.y - partentPos.y; float rateW = offX / partentWidth;
float rateH = offY / partentHeight;
localRect.anchorMax = localRect.anchorMin = new Vector2(0.5f + rateW, 0.5f + rateH);
localRect.anchoredPosition = Vector2.zero; //大小偏移
partentHeight = partentHeight * 0.5f;
partentWidth = partentWidth * 0.5f;
float rateX = (localWidth / partentWidth) * 0.5f;
float rateY = (localHeight / partentHeight) * 0.5f; //錨點偏移值
var pivotOffX = localRect.pivot.x-.5f;
var pivotOffY = localRect.pivot.y-.5f;
var pivotOff = new Vector2(localWidth * pivotOffX / partentWidth, localHeight * pivotOffY / partentHeight); localRect.anchorMax = new Vector2(localRect.anchorMax.x + rateX, localRect.anchorMax.y + rateY) - pivotOff;
localRect.anchorMin = new Vector2(localRect.anchorMin.x - rateX, localRect.anchorMin.y - rateY) - pivotOff;
localRect.offsetMax = localRect.offsetMin = Vector2.zero;
}
}

此指令碼為編輯器Editor指令碼,需要放在Editor資料夾下才能生效。其中安全設定Anchor的拓展方法如下:

     public static void SetRtAnchorSafe(this RectTransform rt, Vector2 anchorMin, Vector2 anchorMax)
{
if (anchorMin.x < || anchorMin.x > || anchorMin.y < || anchorMin.y > || anchorMax.x < || anchorMax.x > || anchorMax.y < || anchorMax.y > )
return; var lp = rt.localPosition;
//注意不要直接用sizeDelta因為該值會隨著anchor改變而改變
var ls = new Vector2(rt.rect.width, rt.rect.height); rt.anchorMin = anchorMin;
rt.anchorMax = anchorMax; //動態改變anchor後size和localPostion可能會發生變化需要重新設定
rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, ls.x);
rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, ls.y);
rt.localPosition = lp;
}