Почему 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 шт):

Автор решения: Yaroslav

Это не пространство сцены, а канвас! Тут на позицию влияют настройка самого лейаута, размеры канваса, канвас скеёлер и т.д. Началом координатной оси лейаута может быть не цент, а любая точка, любой угол. В зависимости от настроек и компонентов родителя, лейаут так-же может изменить свои настройки. 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;
}
→ Ссылка
Автор решения: Miketo

Причина найдена! Весь код написан верно от начала и до конца. Было проведено очень большое количество проверок, я проверял и локальные, и якорные, и абсолютные позиции, и вот какой вывод пришёл:

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();
    }
...

Это реально работает, однако в сети мало кто об этом знает и говорит, поэтому, надеюсь, это кому-то поможет!))

→ Ссылка