Unity报错:Transform child out of bounds问题排查求助
问题概述
项目其余功能正常运行,但按下Grab键触发pressedButton函数时,弹出Transform child out of bounds错误。预期行为是获取标记为按钮的GameObject的第一个子物体(索引0的空物体,初始状态SetActive(false))并将其激活,但调用transform.GetChild(0)时触发越界异常。
相关代码
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Unity.VisualScripting; using UnityEditor; using UnityEngine; using UnityEngine.InputSystem; public class PlayerControllerV01q : MonoBehaviour { [Header("Basico")] public Rigidbody rb; public PlayerInput input; [Header("Movement")] private float speed; public float speedMax, speedMin, accelerationSpeed; private float acceleration; private Vector3 dir; public float gravity; public float jumpForce; public float speedRotation; public Transform groundPoint; public bool isGrounded; public LayerMask maskGround; public float airTime; public float bufferAirTime; public float secondsInAir; [Header("Actions")] public float killJump; public float attackArea; public bool holdingItem; public String[] itemTags; public float pickUpArea; public GameObject detectedObject; public float throwForce; public Transform throwPlace; [Header("Button")] public GameObject activableButton; public GameObject DetectedButtonCandidate; public float activableArea; public String[] buttonTags; public Animator anim; [Header("Surfaces")] public bool isInwall; public Transform facePoint; public LayerMask maskWall; public Vector3 dirWall; void Start() { } void Update() { if (input.actions["Grab"].WasPressedThisFrame()) { Debug.Log("I am trying to grab"); Collider[] allDetects = Physics.OverlapSphere(throwPlace.transform.position, pickUpArea); for (int i = 0; i < allDetects.Length; i++) { GameObject detectedObjectCandidate = allDetects[i].gameObject; if (Array.Exists(itemTags, tag => tag == detectedObjectCandidate.tag)) { detectedObject = detectedObjectCandidate; holdingItem = true; break; } } } if (holdingItem == true) { Debug.Log("I am actually grabbing"); detectedObject.transform.SetParent(transform); if (detectedObject.GetComponent<Rigidbody>() != null) { Rigidbody detectedObjectRB = detectedObject.GetComponent<Rigidbody>(); if (input.actions["Throw"].WasPressedThisFrame()) { Debug.Log("I am trying to throw this"); detectedObject.transform.parent = null; detectedObjectRB.AddForce(Vector3.forward * throwForce, ForceMode.Impulse); holdingItem = false; } } } Vector2 move = input.actions["Move"].ReadValue<Vector2>(); if(move.y != 0) { anim.SetBool("Move", true); anim.SetFloat("Speed", move.y); } else { anim.SetBool("Move", false); } if(move.magnitude != 0) { acceleration = Mathf.MoveTowards(acceleration, 1.0f, Time.deltaTime * accelerationSpeed); } else { acceleration = 0; } speed = Mathf.Lerp(speedMin, speedMax, acceleration); dir = transform.TransformDirection(new Vector3(0, rb.velocity.y, move.y * speed)); rb.velocity = dir; transform.Rotate(Vector3.up * move.x * speedRotation * Time.deltaTime); isGrounded = Physics.OverlapSphere(groundPoint.position, 0.2f, maskGround).Length > 0; if (isGrounded) { anim.SetBool("Ground", true); airTime = 0; if (input.actions["Jump"].WasPressedThisFrame()) { rb.velocity *= 0; rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse); } } else { anim.SetBool("Ground", false); Collider[] allDetects = Physics.OverlapSphere(groundPoint.transform.position, attackArea); for (int i = 0; i < allDetects.Length; i++) { if (allDetects[i].GetComponent<DestroyObject>() != null) { Debug.Log("I am jumping higher"); rb.AddForce(Vector3.up * killJump * 0.8f, ForceMode.Impulse); airTime = 0; allDetects[i].GetComponent<DestroyObject>().GetHits(); } } airTime += Time.deltaTime; if (input.actions["Jump"].IsPressed() && secondsInAir >= airTime && airTime >= bufferAirTime) { rb.AddForce(Vector3.up * jumpForce * 0.8f, ForceMode.Force); } rb.AddForce(Vector3.down * gravity, ForceMode.Force); } isInwall = Physics.OverlapSphere(facePoint.position, 0.4f, maskWall).Length > 0; if (isInwall) { if (input.actions["Climb"].IsPressed()) { Debug.Log("Im trying to climb"); dir = Vector3.zero; dirWall = transform.TransformDirection(new Vector3(0, move.y * speed, rb.velocity.y)); rb.velocity = dirWall; } } if (input.actions["Grab"].WasPressedThisFrame()) { Collider[] allDetects = Physics.OverlapSphere(transform.position, activableArea); for (int i = 0; i < allDetects.Length; i++) { allDetects = allDetects.Where(col => col.gameObject != gameObject).ToArray(); if (buttonTags.Contains(allDetects[i].tag)) { DetectedButtonCandidate = allDetects[i].gameObject; activableButton = DetectedButtonCandidate; pressedButton(); break; } } } } public void pressedButton() { Transform activableButtonChildTransform = activableButton.transform.GetChild(0); if (activableButtonChildTransform != null) { GameObject activableButtonChild = activableButtonChildTransform.gameObject; activableButtonChild.SetActive(true); } } }
报错信息
UnityException: Transform child out of bounds PlayerControllerV01q.pressedButton () (at Assets/Scripts/PlayerControllerV01.cs:218) PlayerControllerV01q.Update () (at Assets/Scripts/PlayerControllerV01.cs:209)
问题原因
- 目标按钮无符合要求的子物体:调用
GetChild(0)时,检测到的activableButton物体没有子物体,导致索引越界。 - 检测循环逻辑错误:在按钮检测的循环中,遍历过程中修改了
allDetects数组(allDetects = allDetects.Where(...)),这会改变数组长度,可能导致索引错位,甚至误识别物体。 - Grab键重复监听:代码中两次监听
Grab键的按下事件,可能导致同一按键触发两种逻辑,引发冲突。
修复方案
1. 安全获取子物体
修改pressedButton方法,先判断子物体数量,避免越界:
public void pressedButton() { // 先判断按钮物体是否为空 if (activableButton == null) { Debug.LogError("activableButton未赋值"); return; } // 检查是否存在索引0的子物体 if (activableButton.transform.childCount > 0) { Transform activableButtonChildTransform = activableButton.transform.GetChild(0); GameObject activableButtonChild = activableButtonChildTransform.gameObject; activableButtonChild.SetActive(true); } else { Debug.LogError($"按钮物体[{activableButton.name}]没有子物体,请检查Hierarchy结构"); } }
2. 修正按钮检测逻辑
将数组过滤操作移到循环外,避免遍历过程中修改数组:
if (input.actions["Grab"].WasPressedThisFrame()) { Collider[] allDetects = Physics.OverlapSphere(transform.position, activableArea); // 先过滤掉自身,再遍历 var filteredDetects = allDetects.Where(col => col.gameObject != gameObject).ToArray(); for (int i = 0; i < filteredDetects.Length; i++) { if (buttonTags.Contains(filteredDetects[i].tag)) { DetectedButtonCandidate = filteredDetects[i].gameObject; activableButton = DetectedButtonCandidate; pressedButton(); break; } } }
3. 合并Grab键监听逻辑
避免同一按键触发两种冲突逻辑,优先处理按钮交互,再处理物品拾取:
if (input.actions["Grab"].WasPressedThisFrame()) { bool triggeredButton = false; // 先检测按钮 Collider[] buttonDetects = Physics.OverlapSphere(transform.position, activableArea); var filteredButtonDetects = buttonDetects.Where(col => col.gameObject != gameObject).ToArray(); for (int i = 0; i < filteredButtonDetects.Length; i++) { if (buttonTags.Contains(filteredButtonDetects[i].tag)) { DetectedButtonCandidate = filteredButtonDetects[i].gameObject; activableButton = DetectedButtonCandidate; pressedButton(); triggeredButton = true; break; } } // 未触发按钮时,再处理物品拾取 if (!triggeredButton) { Debug.Log("I am trying to grab"); Collider[] allDetects = Physics.OverlapSphere(throwPlace.transform.position, pickUpArea); for (int i = 0; i < allDetects.Length; i++) { GameObject detectedObjectCandidate = allDetects[i].gameObject; if (Array.Exists(itemTags, tag => tag == detectedObjectCandidate.tag)) { detectedObject = detectedObjectCandidate; holdingItem = true; break; } } } }
4. 验证按钮物体结构
在Unity编辑器中选中目标按钮GameObject,检查Hierarchy面板,确认它存在索引为0的子物体,且该子物体未被意外删除或禁用。
内容的提问来源于stack exchange,提问作者Aitor Legorburu
相关产品推荐
相关产品推荐

