英文:
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<ObjPrefabScript>(); //now I take the script, if I haven't done that yet
isGet = true;
}
else
{
if (OPScript.BoolVariable) //here I'm cheking a variable from that script
{
Destroy(Obj); //if it's true, I destroy the object
}
}
}
}
The error is in this line:
if (OPScript.BoolVariable) //here I'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 && 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 && 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<ScriptName>().publicBoolVariable
来访问该变量,或者可以为您的布尔变量添加一个getter方法。
英文:
Where you instatiate/spawn your GO, keep a reference of your newly added GO. You can access the variable by spawnedGO.GetComponent<ScriptName>().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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论