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

Unity 3D拾取物体触发异常:隔次生效或失效问题求助

Unity拾取C4隔次触发问题排查与修复

编写Unity 3D游戏时遇到C4拾取触发逻辑隔次生效的问题,并非每次都能正常触发,原实现代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PickupC4 : MonoBehaviour
{
    public GameObject camera;
    public float distance;
    GameObject currentС4;
    bool canPickUp;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q)) OnDropEnter();
    }

    void OnTriggerEnter(Collider other)
    {
        RaycastHit hit;

        if (Physics.Raycast(camera.transform.position, camera.transform.forward, out hit, distance))
        {
            if (hit.transform.tag == "Bomb")
            {
                if (canPickUp) OnDropEnter();

                currentС4 = hit.transform.gameObject;
                currentС4.GetComponent<Rigidbody>().isKinematic = true;
                currentС4.transform.parent = transform;
                currentС4.transform.localPosition = Vector3.zero;
                currentС4.transform.localEulerAngles = new Vector3(10f, 0f, 0f);
                canPickUp = true;

            }
        }
    }


    void OnDropEnter()
    {
        currentС4.transform.parent = null;
        currentС4.GetComponent<Rigidbody>().isKinematic = false;
        canPickUp = false;
        currentС4 = null;
    }
}

问题根源分析

  1. 触发逻辑耦合错误:将拾取操作直接放在OnTriggerEnter中,该方法仅在碰撞体进入触发区域时调用一次,同时叠加Raycast检测,双重条件导致触发时机完全不可控,容易出现漏触发。
  2. 状态逻辑混乱:canPickUp的切换没有配合空值判断,当未持有C4时进入触发区域,执行if (canPickUp) OnDropEnter()会直接调用空对象的方法,引发隐藏错误,导致后续逻辑异常。
  3. 拾取逻辑不符合交互习惯:自动拾取而非通过输入触发,既不符合玩家操作直觉,也容易在多次进入触发区域时触发冲突逻辑。

修复后的代码实现

using UnityEngine;

public class PickupC4 : MonoBehaviour
{
    public GameObject camera;
    public float pickupDistance = 2f;
    public GameObject heldC4;
    // 标记是否处于可拾取C4的区域内
    private bool isInPickupRange;
    // 缓存当前触发区域内的C4对象
    private GameObject targetC4;

    private void Update()
    {
        // 拾取逻辑:未持有C4 + 在拾取范围内 + 按下拾取键(示例用E)
        if (heldC4 == null && isInPickupRange && Input.GetKeyDown(KeyCode.E))
        {
            PickupTargetC4();
        }

        // 丢弃逻辑:持有C4 + 按下丢弃键(Q)
        if (heldC4 != null && Input.GetKeyDown(KeyCode.Q))
        {
            DropHeldC4();
        }
    }

    // 进入触发区域时记录目标C4
    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Bomb"))
        {
            isInPickupRange = true;
            targetC4 = other.gameObject;
        }
    }

    // 离开触发区域时清空标记
    private void OnTriggerExit(Collider other)
    {
        if (other.CompareTag("Bomb"))
        {
            isInPickupRange = false;
            targetC4 = null;
        }
    }

    private void PickupTargetC4()
    {
        if (targetC4 == null) return;

        Rigidbody c4Rb = targetC4.GetComponent<Rigidbody>();
        if (c4Rb == null) return;

        // 禁用物理效果,设置父物体
        c4Rb.isKinematic = true;
        targetC4.transform.SetParent(transform);
        targetC4.transform.localPosition = Vector3.zero;
        targetC4.transform.localEulerAngles = new Vector3(10f, 0f, 0f);

        heldC4 = targetC4;
        targetC4 = null;
        isInPickupRange = false;
    }

    private void DropHeldC4()
    {
        Rigidbody c4Rb = heldC4.GetComponent<Rigidbody>();
        if (c4Rb == null) return;

        // 恢复物理效果,解除父物体
        heldC4.transform.SetParent(null);
        c4Rb.isKinematic = false;
        // 可选:给丢弃的C4一个初速度,模拟抛出效果
        c4Rb.AddForce(camera.transform.forward * 2f, ForceMode.Impulse);

        heldC4 = null;
    }
}

修复要点说明

  • 分离触发区域检测与拾取操作:用OnTriggerEnter/OnTriggerExit标记是否在可拾取范围,在Update中监听输入执行拾取/丢弃,逻辑更清晰可控。
  • 完善空值判断:所有操作前先检查对象是否为null,避免空指针异常导致逻辑中断。
  • 符合玩家交互习惯:必须通过拾取键触发操作,避免自动拾取带来的逻辑冲突。
  • 增加缓存:缓存触发区域内的目标C4,避免重复查找组件,提升性能。

内容的提问来源于stack exchange,提问作者Mr. Bait

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 23:35:41