无法将两个脚本统一链接在一起

时间:2018-03-14 17:46:47

标签: c# unity3d

我在正在开发的团结游戏中创建了两个脚本。第一个是名为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;
}


}

3 个答案:

答案 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;
    }
}

注意添加到OnTriggerEnterOnTriggerExit的参数(从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值)