Unity动画结束后物体文本不更新及循环迭代异常问题排查
问题排查与修复方案
核心问题分析
从你的代码中可以定位到几个导致循环异常、文本不更新的关键问题:
1. 数组索引越界与初始值错误
number初始值为0,Start()中第一次调用nextQuestion()时直接执行number++,导致跳过questions[0],且当number增长到等于questions或answer_keys的长度时,会触发数组越界异常,直接中断后续逻辑,循环自然无法继续。
2. 动画未等待结束就更新文本
当前代码播放动画后立刻修改胡萝卜的文本,但动画过程中可能会重置物体状态,或者你的需求是动画结束后再更新文本,这就导致文本被动画覆盖或者更新时机错误。
3. 随机索引的硬编码问题
随机索引使用Random.Range(0, 2.4f),硬编码上限如果和胡萝卜子物体数量不匹配,会导致要么重复赋值要么索引越界,破坏文本更新的逻辑。
4. 重复获取组件的冗余操作
多次重复调用GetComponent<TMP_Text>()、GetComponent<Animator>(),不仅影响性能,还可能因组件引用丢失导致空引用错误,中断文本更新流程。
修复后的完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using TMPro; public class Bunny : MonoBehaviour { public GameObject carrots; public float speed; public float currentYrotation; public string[] questions, answer_keys; string[] answers; int number = 0; public TMP_Text question_display; // 缓存组件,避免重复获取 private Animator carrotAnimator; private Rigidbody rb; void Start() { // 初始化缓存组件 carrotAnimator = carrots.GetComponent<Animator>(); rb = GetComponent<Rigidbody>(); // 直接加载第一个问题,避免初始number++跳过问题 StartCoroutine(LoadNextQuestion()); } void Update() { if (Input.GetKey(KeyCode.LeftArrow)) { rb.velocity = new Vector3(0, 0, speed); transform.rotation = Quaternion.Euler(0, currentYrotation - 20, 0); } if (Input.GetKey(KeyCode.RightArrow)) { rb.velocity = new Vector3(0, 0, -speed); transform.rotation = Quaternion.Euler(0, currentYrotation + 20, 0); } if (Input.GetKeyUp(KeyCode.RightArrow) || Input.GetKeyUp(KeyCode.LeftArrow)) { rb.velocity = new Vector3(0, 0, 0); transform.rotation = Quaternion.Euler(0, currentYrotation, 0); } } void OnTriggerEnter(Collider obj) { // 用引用比较替代名字判断,更可靠 if (obj.gameObject == carrots) { var firstCarrotText = carrots.transform.GetChild(0).GetChild(0).GetComponent<TMP_Text>().text; if (firstCarrotText == answers[0]) { print("correct"); } else { print("wrong"); } // 加载下一题前先判断是否还有题目,避免越界 if (number < questions.Length - 1) { StartCoroutine(LoadNextQuestion()); } else { print("所有题目已完成"); } } } IEnumerator LoadNextQuestion() { yield return new WaitForSeconds(0.25f); // 先判断是否越界,再更新题目 if (number >= questions.Length || number >= answer_keys.Length) { print("已无更多题目"); yield break; } // 更新题目显示 question_display.transform.parent.gameObject.SetActive(true); question_display.text = questions[number]; // 播放动画并等待动画结束 carrotAnimator.enabled = true; carrotAnimator.Play("carrots"); // 等待动画完成(需确保动画状态机中"carrots"动画的名称正确) yield return new WaitForSeconds(carrotAnimator.GetCurrentAnimatorStateInfo(0).length); // 拆分答案选项 answers = answer_keys[number].Split('|'); // 清空所有胡萝卜文本 for (int i = 0; i < carrots.transform.childCount; i++) { var textComp = carrots.transform.GetChild(i).GetChild(0).GetComponent<TMP_Text>(); if(textComp != null) textComp.text = ""; } // 随机分配答案,使用子物体数量作为随机上限 for (int i = 0; i < carrots.transform.childCount; i++) { if(i >= answers.Length) break; // 避免答案数组长度不足的情况 int index; do { index = Random.Range(0, carrots.transform.childCount); } while (!string.IsNullOrEmpty(carrots.transform.GetChild(index).GetChild(0).GetComponent<TMP_Text>().text)); var targetText = carrots.transform.GetChild(index).GetChild(0).GetComponent<TMP_Text>(); if(targetText != null) targetText.text = answers[i]; } // 最后再递增number,确保当前题目正确加载后再进入下一题 number++; } }
关键修复点说明
- 修正索引逻辑:将
number++移到协程末尾,确保当前题目正常加载后再进入下一题,同时增加数组越界判断,避免崩溃。 - 等待动画结束:通过
carrotAnimator.GetCurrentAnimatorStateInfo(0).length获取动画时长,等待动画完成后再更新文本,符合你的需求。 - 缓存组件:提前缓存
Animator和Rigidbody,避免重复获取组件的性能损耗和空引用风险。 - 动态随机范围:用
carrots.transform.childCount作为随机索引的上限,适配不同数量的胡萝卜子物体。 - 可靠的碰撞判断:用
obj.gameObject == carrots替代名字判断,避免因同名物体或拼写错误导致逻辑失效。
内容的提问来源于stack exchange,提问作者Natalia Adamczyk
相关产品推荐
相关产品推荐

