Unity中使用SetParent后GameObject运行时消失的修复方法
问题
开发类似Bookworm的游戏时,将LetterTile设置为子物体后,运行时物体莫名消失(编辑器中显示正常,且物体未被销毁)。以下是设置父物体的逻辑代码:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using TMPro; public class ParentSetter : MonoBehaviour { public bool IsOnSlot = false; public GameObject[] LetterInputTile; public GameObject letterInputTileParent; // Start is called before the first frame update void Start() { letterInputTileParent = new GameObject("LetterInputTileParent"); } // Update is called once per frame void Update() { 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; } } }
修复方案
问题根源
- 动态父物体层级错误:
Start()中创建的letterInputTileParent默认处于场景根节点,若LetterTile是UI元素(依赖Canvas渲染),将其挂载到非Canvas父物体下会导致UI无法渲染,视觉上表现为消失。 - 重复执行父物体设置:
Update()中每一帧都重复调用SetParent,会触发Transform的频繁重计算,可能导致层级异常或性能损耗。 - 碰撞逻辑缺陷:多个LetterTile碰撞时,
IsOnSlot会被反复切换,导致父物体设置逻辑混乱。
具体修复步骤
1. 给动态父物体指定正确层级
如果LetterTile是UI元素,必须将父物体挂载到Canvas下,确保UI渲染正常:
void Start() { letterInputTileParent = new GameObject("LetterInputTileParent"); // 绑定到场景中的Canvas Canvas canvas = FindObjectOfType<Canvas>(); if (canvas != null) { letterInputTileParent.transform.SetParent(canvas.transform); } // 添加RectTransform组件,适配UI布局 letterInputTileParent.AddComponent<RectTransform>(); }
2. 避免重复执行父物体设置
仅在IsOnSlot状态变化时执行设置逻辑,减少不必要的计算:
private bool _lastIsOnSlot; void Update() { if (IsOnSlot != _lastIsOnSlot) { _lastIsOnSlot = IsOnSlot; foreach (GameObject tile in LetterInputTile) { if (tile == null) continue; tile.transform.SetParent(IsOnSlot ? letterInputTileParent.transform : null); } } }
3. 修正碰撞计数逻辑
统计碰撞的LetterTile数量,只有当所有Tile离开时才切换IsOnSlot状态:
private int _collisionCount; private void OnCollisionEnter2D(Collision2D other) { if (other.gameObject.CompareTag("MLetterTile")) { _collisionCount++; IsOnSlot = true; } } private void OnCollisionExit2D(Collision2D other) { if (other.gameObject.CompareTag("MLetterTile")) { _collisionCount--; if (_collisionCount <= 0) { IsOnSlot = false; _collisionCount = 0; // 避免计数为负 } } }
4. 额外排查点
- 检查LetterTile的
gameObject.activeSelf是否为true,确保没有被意外禁用。 - 查看LetterTile的
transform.localScale,确认没有被缩放到0。
内容的提问来源于stack exchange,提问作者RGVC
相关产品推荐
相关产品推荐

