Почему SetParent меняет положение объекта? Unity
(Реализовываю инвентарь) Есть функция, которая меняет положение объекта через смену родителя, и после этого смену локальной позиции. В первом варианте (когда объект "накинули" на mainCell) - все работает. Первый вариант:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class MainCell : MonoBehaviour, IDropHandler, IPointerEnterHandler, IPointerExitHandler
{
public void OnDrop(PointerEventData eventData)
{
InventoryItem dragItem = eventData.pointerDrag.GetComponent<ItemConsumables>();
if (dragItem == null)
dragItem = eventData.pointerDrag.GetComponent<ItemAmmunition>();
if (CheckCellFree(this, dragItem.size))
{
dragItem.prevMainCell = this;
dragItem.prevAmmunitionCell = null;
dragItem.SetPosition(dragItem, this, null); //Собсна, установка самого объекта на позицию. Код SetPosition, корня зла, далее.
CellOccupation(this, false, dragItem.size);
}
}
}
using System;
using UnityEngine;
using UnityEngine.EventSystems;
public abstract class InventoryItem : Item, IBeginDragHandler, IEndDragHandler, IDragHandler, IDropHandler
{
public virtual void SetPosition(InventoryItem _item, MainCell _mainCell, AmmunitionCell _ammunitionCell)
{
if (_mainCell)
{
_item.transform.SetParent(_mainCell.transform);
var newPos = Vector3.zero;
if (size.y > 1 || size.x > 1)
for (int y = 1; y <= 6; y++)
for (int x = 1; x <= 6; x++)
if (x == size.x && y == size.y)
{
newPos.y -= postIndex * (y - 1);
newPos.x += postIndex * (x - 1);
}
_item.transform.localPosition = newPos;
_item.transform.SetParent(_mainCell.inventory.transform); //В этом первом варианте вместе с "набрасыванием" на MainCell все работает. Однако после этого во втором случае **ниже** позиция объекта меняется.
if (_item.GetComponent<ItemAmmunition>() && Convert.ToString(_item.GetComponent<ItemAmmunition>().itemAmmunType) == "Gun")
_item.transform.rotation = new Quaternion(0, 0, 0, 0);
_mainCell.CellOccupation(_mainCell, false, size);
}
}
}
}
Во втором варианте SetParent начинает резко менять позицию объекта (В этом варианте вместо перемещения и "накидывания" уже созданного объекта создаём новый объект, пусть и с теми же параметрами. Код:
using System;
using UnityEngine.UI;
using UnityEngine;
public class PlayerInventory : Inventory
{
private void Start()
{
SpawnItemsInInventory();
}
private void SpawnItemsInInventory()
{
if (SaveManager.saveMg.activeSave.idInventoryGuns.Count != 0)
{
for (int a = 0; a < SaveManager.saveMg.activeSave.idInventoryGuns.Count; a++)
{
for (int b = 0; b < prefabsManager.gunsPrefabsInvetory.Length; b++)
{
//Все что выше - нам не важно.
if (prefabsManager.gunsPrefabsInvetory[b].GetComponent<Item>() && prefabsManager.gunsPrefabsInvetory[b].GetComponent<Item>().id == SaveManager.saveMg.activeSave.idInventoryGuns[a])
{
GameObject inventoryObject = Instantiate(prefabsManager.gunsPrefabsInvetory[b], transform.parent);
inventoryObject.GetComponent<InventoryItem>().canvas = transform.parent.GetComponent<Canvas>();
if (SaveManager.saveMg.activeSave.isConsumables[a])
{
inventoryObject.GetComponent<InventoryItem>().prevMainCell = cells[SaveManager.saveMg.activeSave.xCellIndexGuns[a], SaveManager.saveMg.activeSave.yCellIndexGuns[a]];
inventoryObject.GetComponent<InventoryItem>().SetPosition(inventoryObject.GetComponent<InventoryItem>(), inventoryObject.GetComponent<InventoryItem>().prevMainCell, null);
//Вот как раз тут и вызывается SetPosition, показанный ранее. И именно тут SetParent работает не правильно. Хз, почему.
} else {
...
}
}
}
}
}
}
Как я понял, что влияет именно SetParent? Что получается до SetParent:
Я бьюсь над этой проблемой уже два дня, помогите.
P.s. не закидывайте дизами, я сам не знаю, как точно описать эту проблему. Я могу скинуть весь код проекта, но это в любом случае не поможет. Просто попросите какую-то инфу, и я её предоставлю.
Ответы (2 шт):
Это не пространство сцены, а канвас! Тут на позицию влияют настройка самого лейаута, размеры канваса, канвас скеёлер и т.д. Началом координатной оси лейаута может быть не цент, а любая точка, любой угол. В зависимости от настроек и компонентов родителя, лейаут так-же может изменить свои настройки. Transform
с его position
/localPosition
, которыми мы оперируем на сцене тут бесполезены!
public void TrackMouse ()
{
RectTransform rect = transform as RectTransform;
RectTransform parentRect = transform.parent as RectTransform;
RectTransformUtility.ScreenPointToLocalPointInRectangle(parentRect, Input.mousePosition, null, out Vector2 localPoint);
rect.anchoredPosition = localPoint;
}
Причина найдена! Весь код написан верно от начала и до конца. Было проведено очень большое количество проверок, я проверял и локальные, и якорные, и абсолютные позиции, и вот какой вывод пришёл:
GridLayoutGroup расфасовывает свои объекты после Start-а (После первого кадра игры). То есть, если мы создали большое количество объектов в Awake, и поместили их в GridLayout, то они будут находиться в одном месте (в том самом центре, где по ошибке находился мой автомат), и именно поэтому все идёт наперекосяк, SetParent НЕ ВИНОВАТ В ЭТОЙ ОШИБКЕ.
Решение этого бага лёгкое - нужно вызвать принудительный просчёт и расфасовку ячеек GridLayoutGroup по своим местам до спавна объектов инвентаря.
...
[SerializeField] private GridLayoutGroup grid;
private void Start()
{
//Четыре строчки расфасовки. Есть более короткий вариант в одну строчку - LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)grid.transform), но с ним я пока не разобрался, он не работает. А то, что ниже - работает.
grid.CalculateLayoutInputHorizontal();
grid.CalculateLayoutInputVertical();
grid.SetLayoutHorizontal();
grid.SetLayoutVertical();
//Спавн объектов.
SpawnItemsInInventory();
}
...
Это реально работает, однако в сети мало кто об этом знает и говорит, поэтому, надеюсь, это кому-то поможет!))