我的代码将对象设置为错误的父级,我该如何解决?

问题描述 投票:0回答:1

所以我目前正在为一篇学校论文编程,我的代码目前的计划是,或者至少我认为应该是,在使用碰撞作为拖放条件下将对象设置为指定父对象的子对象使用 if 条件的传感器。然而,当我运行游戏时,我想设置为孩子的对象却去了错误的父母。这基本上就是发生的事情。

所以在层次结构中看到的网格下的图像是我想由另一个父母指定为孩子的图像。

层次结构中的 LetterSLot 是我想在运行时指定为图像的父对象。

当我运行游戏时,基本上会发生以下情况:

如您所见,在我看来,图像游戏对象以某种方式将自己指定为场景本身的子项,如果我理解正确的话。

这是我用于此逻辑的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class ParentSetter : MonoBehaviour
{
    public bool IsOnSlot = false;
    [SerializeField] GameObject[] LetterInputTile;
    
    [SerializeField] GameObject letterInputTileParent;
    // Start is called before the first frame update
    void Start()
    {
        letterInputTileParent = new GameObject("LetterInputTileParent");
        LetterInputTile = GameObject.FindGameObjectsWithTag("MLetterTile");
    }

    // Update is called once per frame
    void Update()
    {
        foreach (GameObject obj in LetterInputTile)
        {
            if (IsOnSlot)
            {
                for (int i = 0; i < LetterInputTile.Length; i++)
                {
                    LetterInputTile[i].transform.SetParent(letterInputTileParent.transform);
                }
            }
            else
            {
                for (int i = 0; i < LetterInputTile.Length; i++)
                {
                    LetterInputTile[i].transform.SetParent(null);
                }
            }
        }

    }

    private void OnCollisionEnter2D(Collision2D other)
    {
        if(other.gameObject.CompareTag("MLetterTile"))
        {
            IsOnSlot = true;
        }
    }

    private void OnCollisionExit2D(Collision2D other)
    {
        if (other.gameObject.CompareTag("MLetterTile"))
        {
            IsOnSlot = false;
        }
    }
}

我的逻辑有什么地方错了吗?还是我在检查员中设置了错误的东西? 检查员图片:

Inspector中的Parent Setter组件?

我该如何解决这个问题?

更新: 如图所示,根据检查员的说法,代码似乎按预期工作。

但是问题似乎仍然存在,层次结构似乎并不这么认为,并且仍然将自己指定为对象的父级。

我该如何解决?

c# unity3d game-development
1个回答
0
投票

你在做什么

 LetterInputTile[i].transform.SetParent(null);

这会将您的对象设置为场景根级别。但它们似乎是

UI.Image
组件,必须嵌套在
Canvas
下才能被渲染。

您新创建的对象

LetterInputTileParent
也没有嵌套在
Canvas
下,而是嵌套在场景根级别。

=> 你很可能更愿意维护

  • LetterInputTileParent
  • 和瓷砖本身
对于所有情况,

总是嵌套在

Canvas
下。

为此,您可以例如找到它并做

// If possible it is always better to directly reference your objects via the Inspector
// In order to avoid any runtime issues and save some performance
[SerializeField] Canvas _canvas;

private void Awake()
{
    // As a fallback find the canvas on runtime - assuming there is only one anyway
    if(!_canvas) _canvas = FindObjectOfType<Canvas>();

    // You could/should also rather create this one beforehand 
    // and reference this directly via the Inpector
    if(!letterInputTileParent ) 
    {
        letterInputTileParent = new GameObject("LetterInputTileParent");
        // Make sure it is under the Canvas
        letterInputTileParent.AddComponent<RectTransform>();
        letterInputTileParent.SetParent(_canvas.transform, false);
    }

    LetterInputTile = GameObject.FindGameObjectsWithTag("MLetterTile");
}

总的来说,我不完全理解你的组件背后的逻辑。但是您似乎将它附加到每个

LetterSlot
。然而,你确实找到了 all 带有标签
MLetterTile
的对象。他们不会同时运行吗?

我也不会一次又一次地使用

Update
和一个布尔标志来做到这一点。

您已经有两个事件消息,所以为什么不在那里处理结果once.

另请注意,您的循环

foreach
然后是嵌套的
for
循环是完全多余的并且迭代相同的项目

private void OnCollisionEnter2D(Collision2D other)
{
    if(other.gameObject.CompareTag("MLetterTile"))
    {
        foreach (GameObject obj in LetterInputTile)
        {
            obj.transform.SetParent(letterInputTileParent.transform);
        }
    }
}

private void OnCollisionExit2D(Collision2D other)
{
    if (other.gameObject.CompareTag("MLetterTile"))
    {
        foreach (GameObject obj in LetterInputTile)
        {
            obj.transform.SetParent(/*probably not null but something else see above*/);
        }
    }
}

很可能你甚至根本不想迭代 - 考虑一下,在我看来你检查是否与数组中的对象完全相同的标签=>你宁愿只做父母this

other
您碰撞的对象,甚至可能不需要创建新的父对象。

我怀疑你更想达到的是

  • 如果带有标签
    MLetterTile
    的物体与槽相撞
  • 将这个插槽设置为对象的新父对象
  • 如果它退出插槽
  • 将其设置回原来的父级

所以我宁愿期待像这样的东西

public class ParentSetter : MonoBehaviour
{
    private readonly Dictionary<Transform, Transform> originalParents = new ();

    private void OnCollisionEnter2D(Collision2D other)
    {
        if(!other.gameObject.CompareTag("MLetterTile")) return;
        
        originalParents[other.transform] = other.transform.parent;

        other.transform.SetParent(transform);
    }

    private void OnCollisionExit2D(Collision2D other)
    {
        if(!other.gameObject.CompareTag("MLetterTile")) return;
        
        if(!originalParents.Remove(other.transform, out var originalParent)) return;

        other.transform.SetParent(originalParent);
    }
}

originalParents
你现在同时找到

  • 当前在此插槽中的对象 (
    originalParents.Keys
    )
  • 原来的父母在退出插槽时重置他们
© www.soinside.com 2019 - 2024. All rights reserved.