如何仅使用 C# 代码创建边界?



我正在尝试创建一个统一脚本,仅使用 C# 代码(无边界框)检测玩家何时离开某个区域。一旦播放器离开,我的代码应该播放声音,但代码没有按预期工作,我看不到逻辑中的错误。

预期行为

当玩家走出边界时,声音将播放一次。

实际行为

无论玩家身在何处,声音都会一直播放。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EX2BoundaryDetect : MonoBehaviour {
// create a GameObject to represent the player
public GameObject playerObject;
public bool leaveArea = false;
// create an Audio-clip object. This assumes we drag a sound file onto the myclip box in the Inspector.
public AudioClip myclip;
// Use this for initialization
void Start () {
// associate playerObject with the player. This assumes the First Person Controller is name "player
playerObject = GameObject.Find ("player");
// get the actual Sound file from the Inspector
GetComponent<AudioSource>().clip = myclip;
}
// Update is called once per frame
void Update () {
PlayAudio1();
if (leaveArea) {
GetComponent<AudioSource> ().Play ();
}
}
public void PlayAudio1 () {
// play the sound if the player is outside some boundaries
if (transform.position.x > 10) {
leaveArea = true;
}
if (transform.position.x < -29) {
leaveArea = true;
}
if (transform.position.z > 10) {
leaveArea = true;
}
if (transform.position.z < -29) {
leaveArea = true;
}
}
}

leaveArea仅在类定义中设置为false。一旦设置为true,它可能永远不会再次设置为false,并且可能首先在场景定义中

被无意中覆盖。若要解决此问题,请在Update开头将其设置为false

void Update () {
leaveArea = false;
PlayAudio1();
if (leaveArea) {
GetComponent<AudioSource> ().Play ();
}
}

此外,GetComponent是一项昂贵的操作,最好尽可能避免Update调用它。因此,您可能希望将其移动到类属性中并在Start中设置一次:

private AudioSource audioSource;
void Start () {
// associate playerObject with the player. This assumes the First Person Controller is name "player
playerObject = GameObject.Find ("player");
audioSource = GetComponent<AudioSource>();
// get the actual Sound file from the Inspector
audioSource.clip = myclip;
}
// Update is called once per frame
void Update () {
leaveArea = false;
PlayAudio1();
if (leaveArea) {
audioSource.Play ();
}
}

通过添加

leaveArea = false;

Update方法。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EX2BoundaryDetect : MonoBehaviour {
// create a GameObject to represent the player
public GameObject playerObject;
public bool leaveArea = false;
// create an Audio-clip object. This assumes we drag a sound file onto the myclip box in the Inspector.
public AudioClip myclip;
// Use this for initialization
void Start () {
// associate playerObject with the player. This assumes the First Person Controller is name "player
playerObject = GameObject.Find ("player");
// get the actual Sound file from the Inspector
GetComponent<AudioSource>().clip = myclip;
}
// Update is called once per frame
void Update () {
PlayAudio1();
if (leaveArea) {
GetComponent<AudioSource> ().Play ();
}
leaveArea = false;
}
public void PlayAudio1 () {
// play the sound if the player is outside some boundaries
if (transform.position.x > 10) {
leaveArea = true;
}
if (transform.position.x < -29) {
leaveArea = true;
}
if (transform.position.z > 10) {
leaveArea = true;
}
if (transform.position.z < -29) {
leaveArea = true;
}

}
}

我认为上面的答案仍然不能解决您的"当玩家走出边界时,声音将播放一次"的问题。

我将分享一种更简洁的方法(可能经过优化)

使用边界

使用Boundshttps://docs.unity3d.com/ScriptReference/Bounds.html 创建我们自己的边界

Bounds的构造函数是Bounds(Vector3 center,vector3 size)

因此,在您的案例中心将是center = (-9.5f, 0, -9.5f)(中点公式),最后边界框的大小将size = (39.0f, 0f, 39.0f)

让我们转到代码部分

public class BoundsCheck: MonoBehaviour
{
public bool isInside = false;
public bool isPlayedOnce = false;
private Bounds bounds;
void Start()
{
bounds = new Bounds(new Vector3(-9.5f, 0, -9.5f), new Vector3(39.0f, 0f, 39.0f));
}

void Update()
{
CheckBounds();// play the sound if the player is outside some boundaries
if (!isInside &&!isPlayedOnce)
{
Debug.Log("PLAY");
isPlayedOnce = true;
}
}
private void CheckBounds()
{

bool isInsideBound = bounds.Contains(transform.position);
if (isInsideBound)
{
isInside = true;
if (isPlayedOnce)
{
isPlayedOnce = false;
}
}
else
{
isInside = false;
}
}
}


因此,我们可以通过使用bool isInsideBound = bounds.Contains(transform.position);来检查变换的位置是否在边界内,而不是多个 if。

注意:-为了只播放一次声音,我又用了一个布尔isPlayedOnce

我不确定这是否是最优化的方法。但肯定是一种更清洁的方式(通过代码)。

最新更新