Unity启动Coroutine后返回脚本逻辑问题:拾取物品后丢弃投掷功能失效
问题原因与修复方案
核心问题清单
- 1 生命周期方法嵌套错误
你把OnCollisionEnter、OnCollisionExit、waiter协程全部写在了Update方法内部,Unity无法识别嵌套的生命周期方法,这些逻辑全部不会正常执行,isgrounded状态永远不会被正确更新。 - 2
Start方法拼写错误
Unity的初始化生命周期方法是大写开头的Start(),你写的小写start()不会被自动调用,导致rb、inrange的初始化逻辑失效。 - 3 拾取状态与逻辑不同步
你按下E之后立刻修改了number计数,但是协程要等待1秒才会真正执行物品绑定逻辑,这期间的状态和物品实际归属不一致,容易触发逻辑混乱。 - 4 丢弃/投掷的判断条件错误
丢弃和投掷的逻辑里加了inrange == true的限制,物品被拾取到手上之后,已经脱离了玩家的触发区域,inrange会变为false,这两个分支永远不会被触发,这是丢弃投掷失效的直接原因。
修复后的完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PickUp : MonoBehaviour { bool isgrounded = true; public Animator animator; public GameObject Player; public Rigidbody rb; public bool inrange; public int number = 1; public Transform theDest; public float thrust = 1.0f; public float upthrust = 1.0f; // 新增标记防止重复触发拾取协程 private bool isPicking = false; void Start() { rb = GetComponent<Rigidbody>(); inrange = false; } private void OnTriggerEnter(Collider other) { if (other.gameObject.name == "Player") { inrange = true; } } private void OnTriggerExit(Collider other) { if (other.gameObject.name == "Player") { inrange = false; } } private void OnCollisionEnter(Collision theCollision) { if (theCollision.gameObject.name == "floor") { isgrounded = true; } } // 角色跳跃时会退出碰撞 private void OnCollisionExit(Collision theCollision) { if (theCollision.gameObject.name == "floor") { isgrounded = false; } } IEnumerator waiter() { isPicking = true; yield return new WaitForSeconds(1); GetComponent<BoxCollider>().enabled = false; rb.useGravity = false; rb.isKinematic = true; this.transform.position = theDest.position; this.transform.parent = theDest; number = number + 1; isPicking = false; } public void Update() { bool isPickUp = animator.GetBool("isPickUp"); bool pickuppressed = Input.GetKey("e"); if (isgrounded == true) { if (pickuppressed && !isPickUp && inrange==true && !isPicking) { animator.SetBool("isPickUp", true); } if ((!pickuppressed && isPickUp) || inrange == false) { animator.SetBool("isPickUp", false); } if (Input.GetKeyUp(KeyCode.E) && (number % 2) == 1 && inrange == true && !isPicking) { StartCoroutine(waiter()); } // 移除丢弃逻辑的inrange判断 else if (Input.GetKeyUp(KeyCode.E) && (number % 2) == 0 && !isPicking) { rb.isKinematic = false; GetComponent<BoxCollider>().enabled = true; this.transform.parent = null; rb.useGravity = true; number = number - 1; } // 移除投掷逻辑的inrange判断 else if (Input.GetKey(KeyCode.G) && (number % 2) == 0 && !isPicking) { rb.isKinematic = false; GetComponent<BoxCollider>().enabled = true; this.transform.parent = null; rb.useGravity = true; number = number - 1; rb.AddForce(Player.transform.forward * thrust); rb.AddForce(Player.transform.up * upthrust); } } } }
额外优化说明
- 新增了
isPicking标记,避免拾取动画播放期间重复触发拾取/丢弃逻辑,保证状态同步 - 把物品父级设置直接用你公开赋值的
theDest,避免运行时Find查找的性能损耗和查找失败的风险 - 统一用已经初始化的
rb变量操作刚体,不用重复调用GetComponent,提升性能
内容的提问来源于stack exchange,提问作者Coding_Goose
相关产品推荐
相关产品推荐

