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
相关产品推荐
相关产品推荐

