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

Unity2D宝箱功能bug:范围外按X进入范围后错误掉落道具求助

Unity2D宝箱触发Bug修复方案

问题根因

  • TouchingChestBoxCollider状态未正确重置:玩家离开宝箱触发范围后,该变量仍然保持为true,导致范围外按X也能触发xIsPressed赋值。同时OnTriggerStay2D中未判断碰撞对象就直接修改该变量,可能被其他碰撞体误触发。
  • xIsPressed状态永久残留:该变量被赋值为true后没有任何重置逻辑,只要历史上有过一次在TouchingChestBoxCollider为true时按下X的操作,后续进入宝箱范围时就会直接触发掉落。即使之前是误触发的xIsPressed=true,状态也会一直保留。

修复方案

推荐方案(逻辑最贴合需求)

利用xIsPressed仅需存活一帧的特性,每次Update结束后重置状态,从根源避免残留:

  1. 修正TouchingChestBoxCollider的赋值与重置逻辑,仅玩家碰撞时修改状态
  2. 在LateUpdate中重置xIsPressed为false,确保按下状态仅生效一帧
  3. 优化OnTriggerStay2D的判断顺序,减少无效逻辑执行

修改后完整代码

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

public class ChestOpener : MonoBehaviour
{
    [SerializeField]
    private GameObject ChestItSelf;

    [SerializeField]
    private GameObject[] itemsWeapon;

    [SerializeField]
    private GameObject[] itemsMedi;

    [SerializeField]
    private SpriteRenderer spriteRenderer;

    [SerializeField]
    private Sprite openSprite, closeSprite;

    private int random;
    private Vector2 destination;
    private GameObject objectsWeapon;
    private GameObject objectsWeapon2;
    private GameObject objectsMedi;
    private bool HasItDropped = false;
    private bool MoveItemNow = false;
    private bool xIsPressed = false;
    private bool TouchingChestBoxCollider = false;

    private void Update()
    {        
        if (Input.GetKeyDown(KeyCode.X)  && TouchingChestBoxCollider == true)
        {
            xIsPressed = true;
        }
        if (MoveItemNow == true )
        {
            objectsWeapon.transform.position = Vector2.Lerp(objectsWeapon.transform.position, new Vector2(transform.position.x, transform.position.y - 4), 
                Time.deltaTime * 1f);
            objectsWeapon2.transform.position = Vector2.Lerp(objectsWeapon2.transform.position, new Vector2(transform.position.x-2, transform.position.y - 4),
                Time.deltaTime * 1f);
        }  
    }

    // 新增LateUpdate,每帧结束重置X键按下状态,避免残留
    private void LateUpdate()
    {
        xIsPressed = false;
    }

    private void OnTriggerStay2D(Collider2D collision) 
    {
        // 仅处理玩家的碰撞事件
        if (collision.gameObject.tag != "Player") return;
        TouchingChestBoxCollider = true;
        if (HasItDropped == false && xIsPressed == true)
        {
            DropDownItem();
        }
    }
    private void DropDownItem()
    {
        spriteRenderer.sprite = openSprite;
        random = UnityEngine.Random.Range(0, itemsWeapon.Length);
        objectsWeapon = Instantiate(itemsWeapon[random], transform.position, Quaternion.identity);
        objectsWeapon2 = Instantiate(itemsWeapon[random], transform.position, Quaternion.identity);
        
        MoveItemNow = true; 
        HasItDropped = true;
    }
    private void OnTriggerExit2D(Collider2D collision)
    {
        // 仅玩家离开时重置触摸状态
        if (collision.gameObject.tag != "Player") return;
        TouchingChestBoxCollider = false;
        spriteRenderer.sprite = closeSprite;
        Invoke("FareWellChest", 2f);
       
    }
    private void FareWellChest()
    {
        if (HasItDropped == true)
        {
            Destroy(ChestItSelf);
        }
    } 
}

极简改法(改动量最小)

如果不想新增LateUpdate,也可以仅修改3处逻辑即可解决问题:

  1. OnTriggerStay2D中仅玩家碰撞时才给TouchingChestBoxCollider赋值为true
  2. OnTriggerExit2D玩家离开时,同时重置TouchingChestBoxCollider和xIsPressed为false
  3. DropDownItem执行完成后,重置xIsPressed为false

内容的提问来源于stack exchange,提问作者YuDotNet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 06:36:00