You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 20:24:04