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

切换场景后OnTriggerEnter2D触发失效问题求助

问题描述

我开发了一款类似Flappy Bird的游戏,主菜单包含「开始游戏」和「更换鸽子皮肤」功能。皮肤系统通过ScrollRect实现,中心设置触发区来触发鸽子缩放动画。初始状态下功能正常,但点击「开始」切换到游戏场景,返回主菜单后再点击「皮肤」,触发区不再生效。

界面截图说明

  • 主菜单:显示「开始游戏」「更换皮肤」等核心选项
  • 切换场景前皮肤界面:ScrollRect中的鸽子皮肤进入中心触发区时,正常播放缩放动画
  • 切换场景后皮肤界面:返回主菜单打开皮肤界面,鸽子移动到触发区时无任何动画反馈

相关代码

挂载在ScrollRect元素上的碰撞检测脚本 ResizeFieldScript

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

public class ResizeFieldScript : MonoBehaviour
{
    private Animator _anim;

    private void Start()
    {
        _anim = GetComponent<Animator>();
    }

    public void OnTriggerEnter2D(Collider2D collider)
    {
        Debug.Log("Trigger is working");
        if(collider.tag == "ResizeField")
        {
            Debug.Log("Condition is working");
            _anim.SetBool("isInTrigger", true);
        }
    }

    public void OnTriggerExit2D(Collider2D collider)
    {
        _anim.SetBool("isInTrigger", false);
    }
}

挂载在空对象上的场景切换脚本 UIController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;

public class UIController : MonoBehaviour
{
    [SerializeField] private List<string> sceneNameList;
    private string sceneToFind;
    private int index = 0;

    public void SceneChanger()
    {
        sceneToFind = EventSystem.current.currentSelectedGameObject.name;

        foreach(string str in sceneNameList)
        {
            if(str == sceneToFind)
            {
                SceneManager.LoadScene(index);
                index = 0;
                break;
            }
            index++;
        }
    }

    public void Exit()
    {
        Application.Quit();
    }

    public void BackMenu()
    {
        SceneManager.LoadScene(4);
    }
}
问题分析
  1. Animator引用丢失:场景重新加载后,ResizeFieldScript在Start()中获取的Animator引用可能失效,导致触发事件无法调用动画参数。
  2. 碰撞检测失效:返回主菜单后,触发区的Collider2D可能被意外禁用、标签丢失,或者图层碰撞矩阵配置异常,导致OnTrigger事件无法触发。
  3. 场景加载后的初始化缺失:用SceneManager.LoadScene重新加载主菜单时,ScrollRect的皮肤元素没有重新触发碰撞检测的初始化逻辑,导致事件注册失败。
  4. UI元素碰撞兼容性问题:ScrollRect的元素通过RectTransform移动,而非Rigidbody2D驱动,2D碰撞检测对UI元素的支持不稳定,场景切换后更易出现异常。
解决方案

方案1:修复Animator引用的稳定性

将Animator的获取逻辑从Start()移到Awake(),并在触发事件中增加空引用检查,确保引用始终有效:

private Animator _anim;

private void Awake()
{
    _anim = GetComponent<Animator>();
}

public void OnTriggerEnter2D(Collider2D collider)
{
    // 空引用时重新获取Animator
    if (_anim == null)
        _anim = GetComponent<Animator>();

    Debug.Log("Trigger is working");
    if(collider.CompareTag("ResizeField"))
    {
        Debug.Log("Condition is working");
        _anim.SetBool("isInTrigger", true);
    }
}

public void OnTriggerExit2D(Collider2D collider)
{
    if (_anim == null)
        _anim = GetComponent<Animator>();
        
    _anim.SetBool("isInTrigger", false);
}

方案2:检查并修复碰撞检测配置

  • 确认触发区的Collider2D已勾选「Is Trigger」
  • 确保皮肤元素的Collider2D(推荐用BoxCollider2D)与触发区的Collider2D处于同一图层,或图层碰撞矩阵允许两者发生碰撞
  • 返回主菜单后,在编辑器中选中触发区对象,检查「ResizeField」标签是否存在且正确

方案3:优化场景加载后的初始化逻辑

在UIController中添加场景加载完成后的回调,主动重置皮肤界面的动画状态:

public void BackMenu()
{
    SceneManager.LoadScene(4);
    SceneManager.sceneLoaded += OnMainMenuLoaded;
}

private void OnMainMenuLoaded(Scene scene, LoadSceneMode mode)
{
    if (scene.buildIndex != 4) return;

    // 找到皮肤界面的所有ScrollRect元素,重置动画状态
    var skinItems = FindObjectsOfType<ResizeFieldScript>();
    foreach (var item in skinItems)
    {
        Animator anim = item.GetComponent<Animator>();
        if (anim != null)
        {
            anim.SetBool("isInTrigger", false);
        }
    }

    // 移除回调避免重复触发
    SceneManager.sceneLoaded -= OnMainMenuLoaded;
}

方案4:改用UI事件替代2D碰撞检测(推荐)

对于ScrollRect这类UI组件,用碰撞检测稳定性较差,建议直接监听ScrollRect的滚动事件,通过屏幕坐标判断元素是否在触发区内:

// 挂载到ScrollRect对象上的脚本
using UnityEngine;
using UnityEngine.UI;

public class SkinScrollTrigger : MonoBehaviour
{
    public ScrollRect skinScrollRect;
    public RectTransform centerTriggerZone; // 拖拽中心触发区的RectTransform到这里
    private Animator _lastActiveAnimator;

    private void Start()
    {
        skinScrollRect.onValueChanged.AddListener(OnScrollPositionChanged);
        // 初始检查一次当前选中的皮肤
        CheckSkinInTrigger();
    }

    private void OnScrollPositionChanged(Vector2 scrollPos)
    {
        CheckSkinInTrigger();
    }

    private void CheckSkinInTrigger()
    {
        var skinItems = skinScrollRect.content.GetComponentsInChildren<RectTransform>();
        foreach (var item in skinItems)
        {
            // 判断元素是否在触发区内
            bool isInZone = RectTransformUtility.RectangleContainsScreenPoint(
                centerTriggerZone, 
                RectTransformUtility.WorldToScreenPoint(Camera.main, item.position)
            );

            Animator anim = item.GetComponent<Animator>();
            if (anim == null) continue;

            if (isInZone)
            {
                if (anim != _lastActiveAnimator)
                {
                    // 重置上一个皮肤的动画
                    if (_lastActiveAnimator != null)
                        _lastActiveAnimator.SetBool("isInTrigger", false);
                    // 触发当前皮肤的缩放动画
                    anim.SetBool("isInTrigger", true);
                    _lastActiveAnimator = anim;
                }
            }
            else
            {
                if (anim != _lastActiveAnimator)
                {
                    anim.SetBool("isInTrigger", false);
                }
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 01:50:30