问候语,
我正在尝试用C#创建一个脚本,允许玩家打开和关闭门和抽屉。为了节省自己的额外工作,我决定把门和抽屉都标记为",试图一举两得;门";,以及在它们上使用相同的脚本。由于两者共享相同的脚本,我决定通过使用一个可在Unity检查器中配置的私有整数来识别它们,以便区分两者。我试图根据整数ID以及门/抽屉是否打开来改变功能。我不希望门表现得像抽屉,反之亦然,所以我认为如果我要在两个对象上使用相同的脚本,那么提供一个整数值将是有益的。
我确保两个对象都有这个脚本,并且都被标记为";门";。两者都有它们自己的整数值设置在"0"处的检查器中;门ID";领域我把我的门命名为";"办公室门";值为0(用于门对象(,并将我的抽屉对象命名为"0";抽屉";值为1(对于抽屉对象(。
然而,我的问题是,虽然这个剧本适用于我的门,名为";"办公室门";对象,它不适用于我的名为"的抽屉对象;抽屉";。首先,我的抽屉对象认为它被命名为";"办公室门";,尽管已将其命名为";抽屉";在检查员中。此外,在检查调试时。Log((在播放时,我可以看到OpenDoor((/CloseDoor((函数是在抽屉上调用的,而不是OpenDrawer((/ColoseDrawer((,所以它仍然认为这是一扇门。
为我混乱的代码道歉,
门:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Door : MonoBehaviour
{
// Door Identifier
// 0 is swing door (regular)
// 1 is pull-out drawer
[SerializeField] int _doorID = 0;
private float _drawerSpeed = 1f; // Currently unused
[SerializeField] private string doorName = "Door";
private PlayerInteractiveBubble _playerBubble;
// Boolean variables
private bool _iAmOpen = false;
void Start() {
_playerBubble = GameObject.Find("Player/InteractiveBubble").GetComponent<PlayerInteractiveBubble>();
}
void Update() {
}
public void ManageDoor() {
if (_iAmOpen) {
if (_doorID == 0) {
CloseDoor();
} else if (_doorID == 1) {
CloseDrawer();
}
} else if (!_iAmOpen) {
if (_doorID == 0) {
OpenDoor();
} else if (_doorID == 1) {
OpenDrawer();
}
}
}
private void OpenDoor() {
if (_playerBubble.doorIsInRange) {
_iAmOpen = true;
Debug.Log("Door: " + doorName.ToString() + " is open.");
}
}
private void CloseDoor() {
if (_playerBubble.doorIsInRange) {
_iAmOpen = false;
Debug.Log("Door: " + doorName.ToString() + " is now closed.");
}
}
private void OpenDrawer() {
if (_playerBubble.doorIsInRange) {
// Todo: add new Vector3, plus 0.26f on Z-axis
_iAmOpen = true;
Debug.Log("Drawer: " + doorName.ToString() + " is open.");
}
}
private void CloseDrawer() {
if (_playerBubble.doorIsInRange) {
// Todo: add new Vector3, minus 0.26f on Z-axis
_iAmOpen = false;
Debug.Log("Drawer: " + doorName.ToString() + " is closed.");
}
}
}
我的函数在PlayerController.cs:的Update((函数中被调用
if (Input.GetButtonDown("Open")) {
_door.ManageDoor();
}
这是我检查碰撞的地方,PlayerInteractiveBubble.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerInteractiveBubble : MonoBehaviour
{
public bool doorIsInRange = false;
// Currently Unused
private PlayerController _playerController;
private UIManager _uiManager;
void Start() {
_playerController = GameObject.Find("Player").GetComponent<PlayerController>(); // Currently Unused
}
void Update() {
}
void OnTriggerEnter(Collider other) {
if (other.gameObject.CompareTag("Door")) {
doorIsInRange = true;
}
}
void OnTriggerExit(Collider other) {
if (other.gameObject.CompareTag("Door")) {
doorIsInRange = false;
}
}
}
感谢您花时间查看我的问题和代码。我很感激。
您似乎只检查任何门是否在范围内,然后打开/关闭当前分配给_door
的任何门。这似乎并不是你所期望的
您不应该只检查
if(_playerBubble.doorIsInRange)
而是实际存储范围内的门
public Door doorInRange;
void OnTriggerEnter(Collider other)
{
// There is no need for a Tag at all!
// Rather simply check if the object contains a Door (or derived) component
if (other.TryGetComponent<Door>(out var door))
{
doorInRange = door;
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.TryGetCompoment<Door>(out var _))
{
doorInRange = null;
}
}
然后只在PlayerController
脚本中执行
if (Input.GetButtonDown("Open"))
{
// In this case this is rather the implicit bool conversion
// and basically equals a check for != null
if(_playerBubble.doorInRange)
{
_playerBubble.doorInRange.ManageDoor();
}
}
门本身不需要仔细检查它们是否在射程内。
然后我个人不会使用int
来区分不同的门类型。相反,使用继承并拥有基类Door
public class Door : MonoBehaviour
{
private bool _iAmOpen = false;
public void ManageDoor ()
{
// Invert the flag
_iAmOpen = !_iAmOpen;
if(_iAmOpen)
{
// simply log the name of this door object, no need for an additional field
// by also including a context you can simply click once
// on the logged message in the console and this object will be highlighted
Debug.Log($"{name} is opened", this);
Open();
}
else
{
Debug.Log($"{name} is closed", this);
Close();
}
}
protected virtual void Open()
{
// Whatever a default door does
}
protected virtual void Close()
{
// Whatever a default door does
}
}
然后稍微扩展和修改的行为
public class Drawer : Door
{
public float drawerSpeed = 1f;
protected override void Open()
{
// Do different things for a drawer
// if you want to also include the default stuff additionally include a call to
//base.Open();
}
protected override void Close()
{
// Do different things for a drawer
// if you want to also do the default stuff additionally include a call to
//base.Close();
}
}