Unity横向门异常:首个门开启后无法关闭,后续门功能正常
问题分析与解决方案
我帮你找到了问题的核心根源,咱们一步步拆解:
问题所在
你的代码里使用了**静态变量HoriDoorManager.exitedDoor**来控制门的关闭逻辑,但静态变量是全局共享的,这就导致了第一个门的异常:
- 当玩家触发第一组门时,进入触发区调用
OpenDoor,随后EndOpen启动WaitToClose协程——这时候玩家还在触发区内,exitedDoor还是false,协程里的if条件不满足,直接跳过了关门逻辑。 - 当玩家离开第一组门的触发区时,
exitedDoor被设为true,但第一组门的协程已经结束了,所以永远不会关门。 - 后续的门触发时,
exitedDoor已经是true,所以它们的WaitToClose协程能正常执行等待和关门操作。
修复方案
我们需要让每个门组独立管理自己的状态,不要依赖全局静态变量,同时调整协程的逻辑时机。
修改后的HoriDoorManager脚本
using UnityEngine; using System.Collections; using System.Collections.Generic; public class HoriDoorManager : MonoBehaviour { // 把全局静态变量改为实例变量,每个门组独立维护状态 private bool exitedDoor = false; private bool doorLockState; private List<DoorHori> doors = new List<DoorHori>(); private void Start() { if (transform.parent != null) { Transform parent = transform.parent; var children = parent.GetComponentsInChildren<Transform>(); if(children != null) { foreach (Transform door in children) { if (door.name == "Door_Left" || door.name == "Door_Right") { DoorHori doorComp = door.GetComponent<DoorHori>(); doors.Add(doorComp); // 把当前门组的Manager实例传给每个门,确保状态对应 doorComp.SetDoorManager(this); } } } } } void OnTriggerEnter() { if (!doorLockState) { exitedDoor = false; // 进入触发区时重置离开状态 foreach (var door in doors) { door.OpenDoor(); } } } private void OnTriggerExit(Collider collide) { if (!doorLockState) { exitedDoor = true; } } public void ChangeLockState(bool lockState) { doorLockState = lockState; } // 给门提供获取当前门组离开状态的方法 public bool HasExited() { return exitedDoor; } }
修改后的DoorHori脚本
using UnityEngine; using System.Collections; public class DoorHori : MonoBehaviour { public float translateValue; public float easeTime; public OTween.EaseType ease; public float waitTime; private Vector3 StartlocalPos; private Vector3 endlocalPos; private HoriDoorManager doorManager; // 保存对应门组的Manager引用 private void Start() { StartlocalPos = transform.localPosition; gameObject.isStatic = false; } // 让门组Manager设置自己的引用 public void SetDoorManager(HoriDoorManager manager) { doorManager = manager; } public void OpenDoor() { OTween.ValueTo(gameObject, ease, 0.0f, -translateValue, easeTime, 0.0f, "StartOpen", "UpdateOpenDoor", "EndOpen"); GetComponent<AudioSource>().Play(); } private void UpdateOpenDoor(float f) { Vector3 pos = transform.TransformDirection(new Vector3(1, 0, 0)); transform.localPosition = StartlocalPos + pos * f; } private void UpdateCloseDoor(float f) { Vector3 pos = transform.TransformDirection(new Vector3(-f, 0, 0)); transform.localPosition = endlocalPos - pos; } private void EndOpen() { endlocalPos = transform.localPosition; StartCoroutine(WaitToClose()); } private IEnumerator WaitToClose() { // 先等待指定时间,再检查是否已离开触发区(确保等待过程中玩家离开也能触发关门) yield return new WaitForSeconds(waitTime); if (doorManager != null && doorManager.HasExited()) { OTween.ValueTo(gameObject, ease, 0.0f, translateValue, easeTime, 0.0f, "StartClose", "UpdateCloseDoor", "EndClose"); GetComponent<AudioSource>().Play(); } } }
关键修改点说明
- 移除全局静态状态:把
exitedDoor从静态变量改为每个HoriDoorManager的实例变量,确保每个门组的状态独立,不会互相干扰。 - 门与门组的关联:让每个
DoorHori持有对应门组的HoriDoorManager引用,保证它能获取到正确的触发区状态。 - 调整协程逻辑时机:把
exitedDoor的检查从协程启动时移到等待之后,这样即使在等待过程中玩家离开触发区,也能正确触发关门操作。 - 重置状态:在玩家进入触发区时重置
exitedDoor为false,确保每次触发的状态都是正确的。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

