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

Unity游戏灯光触发器反复调用Enter/ExitTrigger2D问题求助

Unity灯光触发器多次调用OnTriggerEnter2D/OnTriggerExit2D问题

我在制作Unity2D游戏时遇到灯光系统问题:想要实现敌人触碰到玩家灯光时停止移动,但敌人接触灯光时,OnTriggerEnter2D和OnTriggerExit2D会被同时多次调用。我推测是Update方法中灯光的处理方式导致的,尝试过禁用触发器但无效。

相关脚本代码

Player脚本

public class Player : MonoBehaviour
{
 #region Light
 [Header("Light Settings")]
 private bool lightOn;
 public GameObject lightUp;
 public GameObject lightDown;
 public GameObject lightLeft;
 public GameObject lightRight;
 #endregion

 void Start()
 {
     rb2D = GetComponent<Rigidbody2D>();
 }

 void Update()
 {
     batterySystem.UpdateBatteryUI();
     if (canMove)
     {
         HandleMovement();
         HandleLantern();
         batterySystem.HandleBatteryUsage(lightOn);
         if (Input.GetKey(KeyCode.Q))
         {
             batterySystem.HandleBatteryRecharge();
         }
         if (Input.GetKeyUp(KeyCode.Q))
         {
             batterySystem.CancelRecharge();
         }
     }
 }
 #region Light Methods
 public void HandleLantern()
 {
     if (Input.GetKeyDown(KeyCode.R) && batterySystem.batteryCount > 0)
     {
         lightOn = !lightOn;

         anim.SetBool("Light", lightOn);

         if (lightOn)
         {
             UpdateLightDirection(lastMove);
         }
         else
         {
             DisableAllLights();
         }
     }
 }

 private void UpdateLightDirection(Vector2 direction)
 {
     DisableAllLights();

     if (Mathf.Abs(direction.x) > Mathf.Abs(direction.y))
     {
         if (direction.x > 0)
         {
             lightRight.SetActive(true);
         }
         else if (direction.x < 0)
         {
             lightLeft.SetActive(true);
         }
     }
     else
     {
         if (direction.y > 0)
         {
             lightUp.SetActive(true);
         }
         else if (direction.y < 0)
         {
             lightDown.SetActive(true);
         }
     }
 }

 private void DisableAllLights()
 {
     lightUp.SetActive(false);
     lightDown.SetActive(false);
     lightLeft.SetActive(false);
     lightRight.SetActive(false);
 }


 public void TurnOffLight()
 {
     lightOn = false;
     anim.SetBool("Light", false);
     DisableAllLights(); 
 }
 #endregion

}

Enemy脚本

public class FollowEnemy : MonoBehaviour
{
    public float speed;
    public float defaultSpeed; 
    private float distance;
    public float minimumDistance;
    public float attackDistance;

    public bool canMove = true;

    void Start()
    {
        defaultSpeed = speed; 
    }

    void Update()
    {
            Walk();               
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Light"))
        {
            canMove = false;
            speed = 0f;
            Debug.Log("Entered Light Trigger");
        }
    }

    private void OnTriggerExit2D(Collider2D other)
    {
        if (other.CompareTag("Light"))
        {
            canMove = true;
            speed = defaultSpeed;
            Debug.Log("Exited Light Trigger");
        }
    }

    private void Walk()
    {
        if (canMove)
        { 
            distance = Vector2.Distance(transform.position, GameObject.FindGameObjectWithTag("Player").transform.position);

            Vector2 direction = GameObject.FindGameObjectWithTag("Player").transform.position - transform.position;
            direction.Normalize();
            float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;

            if (distance < minimumDistance)
            {
                transform.position = Vector2.MoveTowards(this.transform.position, GameObject.FindGameObjectWithTag("Player").transform.position, speed * Time.deltaTime);
                transform.rotation = Quaternion.Euler(Vector3.forward * angle);
            }
            if (distance < attackDistance)
            {
                speed = 0;
            }
        }
    }
}

问题原因与解决方案

核心原因

问题出在灯光对象频繁被激活/禁用:每次切换灯光方向时,UpdateLightDirection都会先调用DisableAllLights关闭所有灯光,再激活对应方向的灯光。这种频繁的激活/禁用操作会让Unity物理引擎反复检测触发器的进入和退出,导致OnTriggerEnter2D和OnTriggerExit2D被连续调用。

解决方案

方案1:控制灯光组件而非对象激活状态

不要通过SetActive切换整个灯光对象,而是控制灯光组件(如Light2D)的启用状态,避免物理引擎反复检测触发器:

// 修改UpdateLightDirection方法
private void UpdateLightDirection(Vector2 direction)
{
    // 禁用所有灯光组件
    lightUp.GetComponent<Light2D>().enabled = false;
    lightDown.GetComponent<Light2D>().enabled = false;
    lightLeft.GetComponent<Light2D>().enabled = false;
    lightRight.GetComponent<Light2D>().enabled = false;

    // 启用对应方向的灯光组件
    if (Mathf.Abs(direction.x) > Mathf.Abs(direction.y))
    {
        if (direction.x > 0)
        {
            lightRight.GetComponent<Light2D>().enabled = true;
        }
        else if (direction.x < 0)
        {
            lightLeft.GetComponent<Light2D>().enabled = true;
        }
    }
    else
    {
        if (direction.y > 0)
        {
            lightUp.GetComponent<Light2D>().enabled = true;
        }
        else if (direction.y < 0)
        {
            lightDown.GetComponent<Light2D>().enabled = true;
        }
    }
}

方案2:添加状态锁避免重复触发

在Enemy脚本中增加状态判断,防止重复执行状态切换逻辑:

private void OnTriggerEnter2D(Collider2D other)
{
    if (other.CompareTag("Light") && canMove)
    {
        canMove = false;
        speed = 0f;
        Debug.Log("Entered Light Trigger");
    }
}

private void OnTriggerExit2D(Collider2D other)
{
    if (other.CompareTag("Light") && !canMove)
    {
        canMove = true;
        speed = defaultSpeed;
        Debug.Log("Exited Light Trigger");
    }
}

方案3:优化灯光切换逻辑

如果必须通过激活/禁用对象切换灯光,可添加缓存避免重复操作:

private GameObject currentActiveLight;

private void UpdateLightDirection(Vector2 direction)
{
    GameObject targetLight = null;

    if (Mathf.Abs(direction.x) > Mathf.Abs(direction.y))
    {
        targetLight = direction.x > 0 ? lightRight : lightLeft;
    }
    else
    {
        targetLight = direction.y > 0 ? lightUp : lightDown;
    }

    // 目标灯光已激活则直接返回
    if (currentActiveLight == targetLight) return;

    // 关闭当前激活灯光
    if (currentActiveLight != null)
    {
        currentActiveLight.SetActive(false);
    }

    // 激活目标灯光
    targetLight.SetActive(true);
    currentActiveLight = targetLight;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 07:54:53