我在正在开发的团结游戏中创建了两个脚本。第一个是名为Changetext的脚本(见下文),这似乎工作得很好,但是,我希望它只在玩家进入游戏世界的设定区域时运行,所以我创建了第二个脚本叫做TRigger(见下文)我试图创建一种方式,当玩家进入触发器对撞机时,它会调用此脚本,但每当我尝试这种统一时,只会出现错误,说“NullReferenceException:对象引用没有设置为对象的实例”
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Changetext : MonoBehaviour {
public float timeLeft = 5;
public Text countdownText;
void Update()
{
timeLeft -= Time.deltaTime;
countdownText.text = ("Time Left = " + timeLeft);
if (timeLeft <= 0)
{
countdownText.text = "You got the cash";
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TRigger : MonoBehaviour
{
void Start()
{
GetComponent<Changetext>().enabled = false;
}
void OnTriggerEnter()
{
GetComponent<Changetext>().enabled = true;
}
void OnTriggerLeave()
{
GetComponent<Changetext>().enabled = false;
}
}
答案 0 :(得分:2)
首先:您不必在第二个脚本中加入function Enable-MailboxSafely {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
$Identity,
$Database,
[switch]$WhatIf
)
$output = [pscustomobject][ordered]@{
Identity = $Identity.ToString()
Mailbox = $null
Message = 'Unknown Error'
Success = $false
}
$output.Mailbox = Get-Mailbox -Identity $Identity -ErrorAction SilentlyContinue
if ($output.Mailbox -ne $null) {
$output.Message = 'Mailbox already exists.'
$output.success = $true
}
Else {
$null = Enable-Mailbox -Identity $Identity -Database:$Database -ErrorAction SilentlyContinue
# Have to look for a mailbox, as a workaround to the Exchange 2010 Cmdlets not implementing exceptions correctly.
$output.Mailbox = Get-Mailbox -Identity $Identity -DomainController:$DomainController -ErrorAction SilentlyContinue
if ($output.Mailbox -ne $null) {
$output.Message = "Mailbox created for [$Identity] on database [$Database]."
$output.success = $true
}
else {
$output.Message = "Failed to create mailbox for [$Identity] on database [$Database]."
$output.Success = $false
}
}
Write-Output $output
}
Enable-MailboxSafely -Identity Somebody
。
您的脚本似乎没有附加到同一个游戏对象,在这种情况下,这对UnityEngine.UI
至关重要。
如果您的脚本不在同一个游戏对象上,您只需引用您的更改文字,例如
GetComponent
然后用
调用它 private GameObject changetext;
void Start()
{
changetext = FindObjectOfType<Changetext>().gameObject;
}
注意:这仅适用于场景中只有一个changetext.GetComponent<Changetext>().enabled = true;
的情况。
没有声明游戏对象的版本应该如下:
Changetext
然后用
调用它 private Changetext changetext;
void Start()
{
changetext = FindObjectOfType<Changetext>().gameObject.GetComponent<Changetext>();
}
答案 1 :(得分:2)
正如Alexander M.在他的回答中所说,只有当两个脚本都附加到同一个对象时,你的代码才有效。
他的回答提出了一种获取该引用的方法,但它是性能密集型的,只有在整个场景中只有该脚本的一个副本时才有效(两个副本将具有确定性,但可能是不期望的行为)。
你可能想要这样的东西:
public class TRigger : MonoBehaviour
{
void OnTriggerEnter(Collider other)
{
other.GetComponent<Changetext>().enabled = true;
}
void OnTriggerExit(Collider other)
{
other.GetComponent<Changetext>().enabled = false;
}
}
注意添加到OnTriggerEnter
和OnTriggerExit
的参数(从OnTriggerLeave
重命名):这些是必要的,否则您将拥有永远不会被调用的函数,因为它们不在{{3 }}
上面的代码会在触及触发器卷的对象上找到Changetext
。如果这不是脚本所在的位置,则需要其他方法来获取引用,例如手动将其分配给字段或使用MonoBehaviour script reference,只应在Start()
或Awake()
或类似内容中进行,并将结果缓存在类属性中。
答案 2 :(得分:0)
由于您说您需要将这些脚本放在不同的对象上,因此您还应该在此处正确分离关注点。关键方面:
你的Text对象上应该有一个ChangeTextScript。它唯一关心的是从另一个脚本中告知更新文本。这就是为什么它需要一个名为 StartChangingText 的公共方法,可以从外部调用,并且一旦玩家退出触发区域,可能会调用 ResetText 方法,以防您希望显示“玩家离开触发区域”消息或类似的东西。
您的播放器对象上应该有一个TriggerScript。玩家进入触发区域后,此脚本应该只调用上面提到的 StartChangingText 。当玩家离开触发区域时,它可以调用 ResetText 。
要实现此功能,首先将层次结构中的Text对象重命名为“CountdownText”,以便播放器对象上的TriggerScript按名称查找,这是一种比将对象拖放到检查器字段更安全的引用对象的方法。然后将新组件添加到播放器对象并将其命名为ChangeTextScript。将此更新版本的代码粘贴到其中:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ChangeTextScript : MonoBehaviour {
public float timeLeft = 5f;
private Text countdownText; //you can also set Text to public and
// drag the Text object into the inspector field,
// but it's prone to initialization errors when
// switching scenes or not saving your project
bool shouldBeChangingText = false;
void Start() {
countdownText = GetComponent<Text>();
}
public void StartChangingText() {
shouldBeChangingText = true;
}
public void ResetText() {
shouldBeChangingText = false;
countdownText.text = "Player left the area";
timeLeft = 5f;
}
void Update()
{
if (shouldBeChangingText) {
timeLeft -= Time.deltaTime;
countdownText.text = ("Time Left = " + timeLeft);
if (timeLeft <= 0)
{
shouldBeChangingText = false;
countdownText.text = "You got the cash";
timeLeft = 5f;
}
}
}
}
然后,将新组件添加到播放器对象,将其命名为TriggerScript并将此更新的代码粘贴到其中:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TriggerScript : MonoBehaviour {
private ChangeTextScript changeTextScript;
void Start() {
changeTextScript = GameObject.Find("CountdownText").GetComponent<ChangeTextScript>();
}
void OnTriggerEnter()
{
changeTextScript.StartChangingText();
}
void OnTriggerExit()
{
changeTextScript.ResetText();
}
}
注意,当计时器用完时,我们告诉我们的脚本它应该停止更新文本,但是我们重置计时器以便它可以再次启动,当你想再次运行它时,不需要启用和禁用脚本。
此外,在原始脚本中,不推荐将 gameObject.enabled 设置为true / false,而使用 gameObject.SetActive(bool值)。