如何引用Unity中附加到预制体的脚本中的变量

huangapple go评论61阅读模式
英文:

How to reference to a variable that's on a script attached to a prefab in Unity

问题

在我的游戏中,在某个特定时刻,我生成一个对象,然后尝试从刚刚生成的对象中获取一个变量,但我得到了 'NullReferenceException'。

代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript1 : MonoBehaviour
{
    public GameObject ObjPrefab; // 这是我的预制体
    private GameObject Obj; // 这是我将要生成的空对象
    private bool isGet = false; // 这个布尔值告诉我是否已经获取了脚本
    public ObjPrefabScript OPScript; // 这是预制体的脚本

    // 初始化
    void Start()
    {
        Obj = Instantiate(ObjPrefab); // 在这里生成对象
    }

    // 每帧更新
    void Update()
    {
        if (!isGet)
        {
            OPScript = Obj.GetComponent<ObjPrefabScript>(); // 现在我获取脚本,如果我还没有这样做
            isGet = true; 
        }
        else
        {
            if (OPScript.BoolVariable) // 在这里我检查来自该脚本的一个变量
            {
                Destroy(Obj); // 如果为真,我销毁对象
            }
        }
    }
}

错误在这一行:

 if (OPScript.BoolVariable) // 在这里我检查来自该脚本的一个变量
英文:

In my game at a certain point I spawn an object and then I'm trying to get a variable from that object that I just spawned, but I get the 'NullReferenceException'.

It looks like this

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript1 : MonoBehaviour
{
    public GameObject ObjPrefab; //this is my prefab
    private GameObject Obj; //this is my empty object that I will spawn
    private bool isGet = false; //this bool tell me if I arledy got the script
    public ObjPrefabScript OPScript; //this is the script of the prefab

    // Use this for initialization
    void Start()
    {
        Obj = Instantiate(ObjPrefab); //here I spawn the object
    }

    // Update is called once per frame
    void Update()
    {
        if (!isGet)
        {
            OPScript = Obj.GetComponent&lt;ObjPrefabScript&gt;(); //now I take the script, if I haven&#39;t done that yet
            isGet = true; 
        }
        else
        {
            if (OPScript.BoolVariable) //here I&#39;m cheking a variable from that script 
            {
                Destroy(Obj); //if it&#39;s true, I destroy the object
            }
        }
    }
}

The error is in this line:

 if (OPScript.BoolVariable) //here I&#39;m cheking a variable from that script 

答案1

得分: 2

在这种情况下,立即将您的预制体字段设置为正确的类型:

public ObjPrefabScript ObjPrefab;
public ObjPrefabScript OPScriptInstance;

private void Awake()
{
    OPScriptInstance = Instantiate(ObjPrefab);
}

这样可以确保在检视面板中,您只能引用那些已经附加了该组件的对象作为预制体。这已经排除了 GetComponent 返回 null 的情况,因为该组件不存在。

此外,您还需要检查 Obj 的存在... 即使在对象被销毁后,您仍然会在每帧调用 Update

void Update()
{
    if (OPScriptInstance && OPScriptInstance.BoolVariable)
    {
        Destroy(OPScriptInstance.gameObject);
    }
}

此外,您还可以禁用或销毁此组件,因为在 OPScriptInstance 被销毁后,该组件已经没有意义,而且只会浪费不必要的 Update 调用。

void Update()
{
    if (OPScriptInstance && OPScriptInstance.BoolVariable)
    {
        Destroy(OPScriptInstance.gameObject);
        enabled = false;
        // 或者甚至
        Destroy(this); // 只销毁此组件,不影响其所附加的游戏对象
    }
}

总的来说,我会避免每帧进行此类轮询检查。在对象被销毁后,这个组件完全失去了它的意义。因此,我宁愿将销毁对象的操作移到 ObjPrefabScript 中。

无论如何,设置标志的人都可以直接立即执行 Destroy 操作,而无需一直使用组件来轮询检查标志。

英文:

In such cases make your prefab field of the correct type right away

public ObjPrefabScript ObjPrefab;

public ObjPrefabScript OPScriptInstance;

private void Awake()
{
    OPScriptInstance = Instantiate(ObjPrefab);
}

this ensures that in the Inspector you already can only reference those objects that actually do have such component attached as a prefab. This already rules out the case that GetComponent retuns null because the component isn't there.

Further you would need to check for the existence of Obj .. you continue to call Update every frame even after the object has been destroyed.

void Update()
{
    if (OPScriptInstance &amp;&amp; OPScriptInstance.BoolVariable)
    {
        Destroy(OPScriptInstance.gameObject);
    }
}

additionally you could also disable or even destroy this component as well since it looses its purpose after OPScriptInstance has been destroyed and is basically a wasted unnecessary Update call.

void Update()
{
    if (OPScriptInstance &amp;&amp; OPScriptInstance.BoolVariable)
    {
        Destroy(OPScriptInstance.gameObject);
        enabled = false;
        // or even
        Destroy(this); // only destroys this component, not the GameObject it is attached to
    }
}

In general I would avoid this kind of poll checking every frame.
This component completely looses its entire purpose after the object has been destroyed anyway. So I would rather move the destroying of the object into the ObjPrefabScript itself.

Whoever is setting the flag can rather directly Destroy it right away instead without the need for any component poll checking the flag all the time.

答案2

得分: 0

在实例化/生成GO的位置,保留对新添加的GO的引用。您可以通过spawnedGO.GetComponent&lt;ScriptName&gt;().publicBoolVariable来访问该变量,或者可以为您的布尔变量添加一个getter方法。

英文:

Where you instatiate/spawn your GO, keep a reference of your newly added GO. You can access the variable by spawnedGO.GetComponent&lt;ScriptName&gt;().publicBoolVariable or alternatively can add a getter method for your bool variable.

答案3

得分: 0

isGet = true 并不能保证 OPScript 已经加载。它只能保证程序尝试获取它。

isGet = true; 

改为

isGet = OPScript != null; 

还要确保 ObjPrefabScript.BoolVariable 可以访问。

英文:

The isGet = true isn't a guarantee that OPScript was loaded. It only guarantees that the program tried to grab it.

Change

isGet = true; 

to

isGet = OPScript != null; 

Also, make sure ObjPrefabScript.BoolVariable is accessible.

huangapple
  • 本文由 发表于 2023年6月2日 14:04:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76387523.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定