Unity躲桌时Player对象未隐藏问题求助
Unity问题:躲进桌下时Player对象无法隐藏
我正在制作一个支持玩家躲进储物柜和桌子下方的Unity小项目。目前躲进储物柜时Player能正常隐藏,但触发桌子的互动脚本时,Player始终保持显示状态,无法隐藏,多方排查无果,寻求解决办法。
桌子绑定脚本
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class TriggerTable : MonoBehaviour { [SerializeField] private bool isHidingTable; [SerializeField] private bool canHideTable; [SerializeField] private Transform cameraTablePos; [SerializeField] private new Transform camera; [SerializeField] private GameObject player; [SerializeField] private Camera playerCamera; [SerializeField] private Camera tableCamera; void Start() { cameraTablePos = GameObject.Find("TablePosition").transform; player = GameObject.Find("Player"); playerCamera = GameObject.Find("Main Camera").GetComponent<Camera>(); tableCamera = GameObject.Find("TableCamera").GetComponent<Camera>(); playerCamera.enabled = true; tableCamera.enabled = false; tableCamera.transform.SetParent(null); } void switchToTableCam() { player.SetActive(false); playerCamera.enabled = false; tableCamera.enabled = true; } void switchToPlayerCam() { player.SetActive(true); tableCamera.enabled = false; playerCamera.enabled = true; } private void OnTriggerEnter(Collider collision) { if (collision.CompareTag("Player")) { canHideTable = true; } } private void OnTriggerExit(Collider collision) { if (collision.CompareTag("Player")) { canHideTable = false; } } void Update() { if (Input.GetKeyDown(KeyCode.E) && canHideTable) { isHidingTable = !isHidingTable; } if (isHidingTable) { tableCamera.transform.SetParent(null); camera.parent = cameraTablePos; camera.position = cameraTablePos.position; switchToTableCam(); } else { switchToPlayerCam(); } } }
储物柜绑定脚本
using System; using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UI; public class TriggerLockerDoor : MonoBehaviour { [SerializeField] private bool isHidingLocker; [SerializeField] private bool canHideLocker; [SerializeField] private Transform cameraLockerPos; [SerializeField] private new Transform camera; [SerializeField] private GameObject player; [SerializeField] private Camera playerCamera; [SerializeField] private Camera lockerCamera; void Start() { cameraLockerPos = GameObject.Find("LockerPosition").transform; player = GameObject.Find("Player"); playerCamera = GameObject.Find("Main Camera").GetComponent<Camera>(); lockerCamera = GameObject.Find("LockerCamera").GetComponent<Camera>(); playerCamera.enabled = true; lockerCamera.enabled = false; lockerCamera.transform.SetParent(null); } void switchToLockerCam() { playerCamera.enabled = false; lockerCamera.enabled = true; } private void OnTriggerEnter(Collider collision) { if (collision.CompareTag("Player")) { canHideLocker = true; } } private void OnTriggerExit(Collider collision) { if (collision.CompareTag("Player")) { canHideLocker = false; } } void Update() { if (Input.GetKeyDown(KeyCode.E) && canHideLocker) { isHidingLocker = !isHidingLocker; } if (isHidingLocker) { lockerCamera.transform.SetParent(null); camera.parent = cameraLockerPos; player.SetActive(false); camera.position = cameraLockerPos.position; switchToLockerCam(); } else { player.SetActive(true); lockerCamera.enabled = false; playerCamera.enabled = true; } } }
问题原因
两个脚本同时操作同一个Player对象的激活状态,导致冲突:
- 当玩家躲进桌子时,
TriggerTable脚本会调用switchToTableCam()将Player设为隐藏,但TriggerLockerDoor脚本的Update方法中,因为isHidingLocker为false,每帧都会执行player.SetActive(true),直接覆盖了桌子脚本的设置,导致Player始终显示。
解决方法
方法1:统一管理隐藏状态
创建全局状态管理器,专门处理Player的隐藏/显示逻辑,避免多个脚本直接修改Player的active状态:
using UnityEngine; public class HideManager : MonoBehaviour { public static HideManager Instance; [SerializeField] private GameObject player; private bool isPlayerHidden; void Awake() { Instance = this; player = GameObject.Find("Player"); } public void SetPlayerHidden(bool hidden) { if (isPlayerHidden != hidden) { isPlayerHidden = hidden; player.SetActive(!hidden); } } }
修改两个脚本中的Player激活逻辑:
- 在
TriggerTable的switchToTableCam()中替换player.SetActive(false)为HideManager.Instance.SetPlayerHidden(true) - 在
switchToPlayerCam()中替换player.SetActive(true)为HideManager.Instance.SetPlayerHidden(false) - 在
TriggerLockerDoor的隐藏分支中替换player.SetActive(false)为HideManager.Instance.SetPlayerHidden(true) - 在else分支中替换
player.SetActive(true)为HideManager.Instance.SetPlayerHidden(false)
方法2:修改脚本逻辑,避免每帧重复设置
只在状态改变时修改Player的active状态,而非每帧执行:
以TriggerLockerDoor为例,添加状态标记,仅当状态变化时才更新Player:
// 在TriggerLockerDoor中添加变量 private bool wasHidingLocker; void Update() { if (Input.GetKeyDown(KeyCode.E) && canHideLocker) { isHidingLocker = !isHidingLocker; } if (isHidingLocker != wasHidingLocker) { wasHidingLocker = isHidingLocker; if (isHidingLocker) { lockerCamera.transform.SetParent(null); camera.parent = cameraLockerPos; player.SetActive(false); camera.position = cameraLockerPos.position; switchToLockerCam(); } else { player.SetActive(true); lockerCamera.enabled = false; playerCamera.enabled = true; } } }
对TriggerTable脚本做同样修改,添加wasHidingTable变量,仅在状态变化时执行Player的显示/隐藏逻辑,避免每帧重复设置导致的冲突。
内容的提问来源于stack exchange,提问作者heymasin
相关产品推荐
相关产品推荐

