Unity:使 parent 的大小适合孩子的大小
Unity: Fit size of parent to size of childs
我在 Canvas 中有一个空的,它有多个 objects 作为 children。随着游戏的进行,更多 children 被添加到 parent。我希望 parent 的大小适合其 children。
我已经阅读了很多关于这个主题的文章,但每次我遇到 ContentSizeFitter,不幸的是它对我不起作用,因为它需要一个布局组,而我没有,因为 children 没有订单,乱放
我使用的是 Unity 2018.3.4f1 个人版。
未调整大小parent:
尺码parent(红色:新,绿色:旧):
结构:
Canvas
|- Empty
|- Child 1
|- Child 2
|- Child X
我想你可以找到最左边框和最右边框,然后将那个值的差值添加为父 RectTransform
的 sizeDelta
。
这应该固定大小(重复 Y 的顶部和底部)。
对于可以在 Vector2
中获得最左边框和上边框的左上角的位置,然后将该向量设置为 anchoredPosition
到父 RectTransform
。
请注意,父级的枢轴必须位于左上角才能正常工作。
这段代码只是接近了一些东西,但还不够好。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FitParentToChildren : MonoBehaviour
{
#region INTERNAL
public RectTransform parent;
public RectTransform[] children;
public float minX = 100000;
public float maxX = -100000;
public float minY = 100000;
public float maxY = -100000;
#endregion
#region INITIALIZATION
void Awake()
{
parent = GetComponent<RectTransform>();
children = GetComponentsInChildren<RectTransform>();
}
void Start()
{
SetMinMaxValues();
FitToChildren();
}
#endregion
#region BEHAVIOURS
private void FitToChildren()
{
parent.sizeDelta = GetNewRect();
parent.anchoredPosition = GetTopLeftCornerPositon();
}
private void SetMinMaxValues()
{
for (int i = 1; i < children.Length; i++)
{
float tempMinX = children[i].anchoredPosition.x - children[i].sizeDelta.x / 2;
if (tempMinX < minX) minX = tempMinX;
float tempMaxX = children[i].anchoredPosition.x + children[i].sizeDelta.x / 2;
if (tempMaxX > maxX) maxX = tempMaxX;
float tempMinY = children[i].anchoredPosition.y - children[i].sizeDelta.y / 2;
if (tempMinY < minY) minY = tempMinY;
float tempMaxY = children[i].anchoredPosition.y + children[i].sizeDelta.y / 2;
if (tempMaxY > maxY) maxY = tempMaxY;
}
}
private Vector2 GetNewRect()
{
return new Vector2 (maxX - minX, maxY - minY);
}
private Vector2 GetTopLeftCornerPositon()
{
return new Vector2 (minX, maxY);
}
#endregion
}
GIF 在这里
像这样的东西应该有用。它循环遍历您选择的对象的所有子对象,然后找到这些对象的渲染器边界并更新最小值和最大值。在 Start() 函数的末尾,变量 min 和 max 保存定义边界的框角的坐标。
public class NewBehaviourScript : MonoBehaviour
{
void Start ()
{
Vector2 min = new Vector2 (0, 0);
Vector2 max = new Vector2 (0, 0);
GetParentBounds (gameObject, out min, out max);
Debug.Log (min);
Debug.Log (max);
}
void GetParentBounds (GameObject GO, out Vector2 pMin, out Vector2 pMax)
{
Transform[] ts = GO.GetComponentsInChildren<Transform> ();
Vector2 parentMin = new Vector2 (float.MaxValue, float.MaxValue);
Vector2 parentMax = new Vector2 (float.MinValue, float.MinValue);
foreach (Transform t in ts) {
Renderer rend = t.GetComponent<Renderer> ();
if (rend != null) {
Vector2 min = rend.bounds.min;
Vector2 max = rend.bounds.max;
Debug.Log (string.Format ("[{0}, {1}], [{2}, {3}]", min.x, min.y, max.x, max.y));
parentMin.x = Mathf.Min (parentMin.x, min.x);
parentMin.y = Mathf.Min (parentMin.y, min.y);
parentMax.x = Mathf.Max (parentMax.x, max.x);
parentMax.y = Mathf.Max (parentMax.y, max.y);
}
}
pMin = parentMin;
pMax = parentMax;
}
}
我已经编写了一小段代码来完成它的工作,或者按照我想要的方式来完成,这对我来说已经足够了:
using UnityEngine;
public class SizeFitter : MonoBehaviour {
public void CheckForChanges() {
RectTransform children = transform.GetComponentInChildren<RectTransform>();
float min_x, max_x, min_y, max_y;
min_x = max_x = transform.localPosition.x;
min_y = max_y = transform.localPosition.y;
foreach (RectTransform child in children) {
Vector2 scale = child.sizeDelta;
float temp_min_x, temp_max_x, temp_min_y, temp_max_y;
temp_min_x = child.localPosition.x - (scale.x / 2);
temp_max_x = child.localPosition.x + (scale.x / 2);
temp_min_y = child.localPosition.y - (scale.y / 2);
temp_max_y = child.localPosition.y + (scale.y / 2);
if (temp_min_x < min_x)
min_x = temp_min_x;
if (temp_max_x > max_x)
max_x = temp_max_x;
if (temp_min_y < min_y)
min_y = temp_min_y;
if (temp_max_y > max_y)
max_y = temp_max_y;
}
GetComponent<RectTransform>().sizeDelta = new Vector2(max_x - min_x, max_y - min_y);
}
}
Bounds bound = new Bounds();
for (int i = 0; i < children.Length; ++i)
{
RectTransform child = children[i];
if (child != null && child.gameObject.activeSelf)
{
Vector2 pos = child.localPosition;
Vector2 min = pos - child.sizeDelta * child.pivot;
Vector2 max = min + child.sizeDelta;
Bounds temp = new Bounds();
temp.SetMinMax(min, max);
bound.Encapsulate(temp);
}
}
我在 Canvas 中有一个空的,它有多个 objects 作为 children。随着游戏的进行,更多 children 被添加到 parent。我希望 parent 的大小适合其 children。
我已经阅读了很多关于这个主题的文章,但每次我遇到 ContentSizeFitter,不幸的是它对我不起作用,因为它需要一个布局组,而我没有,因为 children 没有订单,乱放
我使用的是 Unity 2018.3.4f1 个人版。
未调整大小parent:
尺码parent(红色:新,绿色:旧):
结构:
Canvas
|- Empty
|- Child 1
|- Child 2
|- Child X
我想你可以找到最左边框和最右边框,然后将那个值的差值添加为父 RectTransform
的 sizeDelta
。
这应该固定大小(重复 Y 的顶部和底部)。
对于可以在 Vector2
中获得最左边框和上边框的左上角的位置,然后将该向量设置为 anchoredPosition
到父 RectTransform
。
请注意,父级的枢轴必须位于左上角才能正常工作。
这段代码只是接近了一些东西,但还不够好。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FitParentToChildren : MonoBehaviour
{
#region INTERNAL
public RectTransform parent;
public RectTransform[] children;
public float minX = 100000;
public float maxX = -100000;
public float minY = 100000;
public float maxY = -100000;
#endregion
#region INITIALIZATION
void Awake()
{
parent = GetComponent<RectTransform>();
children = GetComponentsInChildren<RectTransform>();
}
void Start()
{
SetMinMaxValues();
FitToChildren();
}
#endregion
#region BEHAVIOURS
private void FitToChildren()
{
parent.sizeDelta = GetNewRect();
parent.anchoredPosition = GetTopLeftCornerPositon();
}
private void SetMinMaxValues()
{
for (int i = 1; i < children.Length; i++)
{
float tempMinX = children[i].anchoredPosition.x - children[i].sizeDelta.x / 2;
if (tempMinX < minX) minX = tempMinX;
float tempMaxX = children[i].anchoredPosition.x + children[i].sizeDelta.x / 2;
if (tempMaxX > maxX) maxX = tempMaxX;
float tempMinY = children[i].anchoredPosition.y - children[i].sizeDelta.y / 2;
if (tempMinY < minY) minY = tempMinY;
float tempMaxY = children[i].anchoredPosition.y + children[i].sizeDelta.y / 2;
if (tempMaxY > maxY) maxY = tempMaxY;
}
}
private Vector2 GetNewRect()
{
return new Vector2 (maxX - minX, maxY - minY);
}
private Vector2 GetTopLeftCornerPositon()
{
return new Vector2 (minX, maxY);
}
#endregion
}
GIF 在这里
像这样的东西应该有用。它循环遍历您选择的对象的所有子对象,然后找到这些对象的渲染器边界并更新最小值和最大值。在 Start() 函数的末尾,变量 min 和 max 保存定义边界的框角的坐标。
public class NewBehaviourScript : MonoBehaviour
{
void Start ()
{
Vector2 min = new Vector2 (0, 0);
Vector2 max = new Vector2 (0, 0);
GetParentBounds (gameObject, out min, out max);
Debug.Log (min);
Debug.Log (max);
}
void GetParentBounds (GameObject GO, out Vector2 pMin, out Vector2 pMax)
{
Transform[] ts = GO.GetComponentsInChildren<Transform> ();
Vector2 parentMin = new Vector2 (float.MaxValue, float.MaxValue);
Vector2 parentMax = new Vector2 (float.MinValue, float.MinValue);
foreach (Transform t in ts) {
Renderer rend = t.GetComponent<Renderer> ();
if (rend != null) {
Vector2 min = rend.bounds.min;
Vector2 max = rend.bounds.max;
Debug.Log (string.Format ("[{0}, {1}], [{2}, {3}]", min.x, min.y, max.x, max.y));
parentMin.x = Mathf.Min (parentMin.x, min.x);
parentMin.y = Mathf.Min (parentMin.y, min.y);
parentMax.x = Mathf.Max (parentMax.x, max.x);
parentMax.y = Mathf.Max (parentMax.y, max.y);
}
}
pMin = parentMin;
pMax = parentMax;
}
}
我已经编写了一小段代码来完成它的工作,或者按照我想要的方式来完成,这对我来说已经足够了:
using UnityEngine;
public class SizeFitter : MonoBehaviour {
public void CheckForChanges() {
RectTransform children = transform.GetComponentInChildren<RectTransform>();
float min_x, max_x, min_y, max_y;
min_x = max_x = transform.localPosition.x;
min_y = max_y = transform.localPosition.y;
foreach (RectTransform child in children) {
Vector2 scale = child.sizeDelta;
float temp_min_x, temp_max_x, temp_min_y, temp_max_y;
temp_min_x = child.localPosition.x - (scale.x / 2);
temp_max_x = child.localPosition.x + (scale.x / 2);
temp_min_y = child.localPosition.y - (scale.y / 2);
temp_max_y = child.localPosition.y + (scale.y / 2);
if (temp_min_x < min_x)
min_x = temp_min_x;
if (temp_max_x > max_x)
max_x = temp_max_x;
if (temp_min_y < min_y)
min_y = temp_min_y;
if (temp_max_y > max_y)
max_y = temp_max_y;
}
GetComponent<RectTransform>().sizeDelta = new Vector2(max_x - min_x, max_y - min_y);
}
}
Bounds bound = new Bounds();
for (int i = 0; i < children.Length; ++i)
{
RectTransform child = children[i];
if (child != null && child.gameObject.activeSelf)
{
Vector2 pos = child.localPosition;
Vector2 min = pos - child.sizeDelta * child.pivot;
Vector2 max = min + child.sizeDelta;
Bounds temp = new Bounds();
temp.SetMinMax(min, max);
bound.Encapsulate(temp);
}
}