У меня есть пустой холст, который имеет несколько объектов в качестве дочерних. По ходу игры к родителю добавляются новые дочерние элементы. Я хочу, чтобы родитель соответствовал размеру своих детей.
Я уже много читал на эту тему, но каждый раз натыкался на ContentSizeFitter, который у меня к сожалению не работает, так как ему нужна группа раскладок, которой у меня нет, т.к. дети не имеют порядка и дико размещен.
Я использую Unity 2018.3.4f1 Personal.
Родитель без размера:
Размер родителя (красный: новый, зеленый: старый):
Структура:
Canvas
|- Empty
|- Child 1
|- Child 2
|- Child X





Я думаю, вы можете найти самую левую и самую правую границу, а затем добавить разницу этого значения как sizeDelta родителя RectTransform.
Это должно исправить размер (повторите с верхом и низом для 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
}
ГИФ ЗДЕСЬ
Большое спасибо, ваш код не сработал, но он определенно помог мне и дал мне несколько хороших идей.
У меня было мало времени, чтобы помочь, но это что-то XD
Что-то вроде этого должно работать. Он перебирает все дочерние элементы объекта по вашему выбору, затем находит границы рендерера этих объектов и обновляет минимальное и максимальное значения по мере продвижения. В конце функции 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;
}
}
Вам все еще нужно использовать эти данные, которые вы каким-то образом получили
Ваш код не работает для меня. Родитель является потомком Canvas, поэтому у него есть Canvas Renderer. А t.GetComponent<Renderer> () возвращает ноль.
Есть ли у них сетчатые фильтры? вы можете попробовать изменить внутреннюю часть foreach следующим образом: Renderer mf = t.GetComponent<MeshFilter> (); if (mf!= null) { Vector2 min = mf.mesh.bounds.min; Vector2 max = mf.mesh.bounds.max; 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); }
Нет, у них есть только RectTransform, CanvasRenderer, Image, Outline и коллайдер.
Я написал небольшой кусок кода, который выполняет свою работу или делает так, как я хочу, и мне этого достаточно:
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);
}
}
4 вершины будут определять размер родителя: самая левая, самая правая, самая верхняя и самая нижняя. Имея их, можно измерить центр и размер родителя. Вычислите эти вершины в методе Update, и все готово.