Unity 2D C#中如何在不同脚本间正确传递变量
错误原因
继承自MonoBehaviour的类禁止通过new关键字手动实例化,这是Unity开发和Java开发的核心差异点:所有MonoBehaviour子类的生命周期都由引擎管控,必须作为组件挂载在场景内的GameObject上,通过GetComponent、FindObjectOfType或者Inspector拖拽的方式获取真实运行的实例。你手动new出来的WispDisplay对象没有绑定场景中的UI引用,也不会触发Start/Update生命周期函数,完全不参与场景运行逻辑,自然无法正常工作。
修复方案
- 先在编辑器内完成基础配置:把
WispDisplay脚本挂载到持有Wisp计数UI文本的GameObject上,将对应的Text组件拖拽到脚本的WispText字段引用槽,初始Wisp数值可直接在Inspector面板设置。 - 修改两个脚本的逻辑,移除错误的new实例化逻辑,优先通过Inspector拖拽赋值引用,减少运行时查找开销。
修正后的拾取脚本 WispCode
public class WispCode : MonoBehaviour { // 直接在Inspector面板拖拽挂载了WispDisplay的对象赋值,无需new public WispDisplay wd; private void OnTriggerEnter2D(Collider2D other) { if (other.CompareTag("Player")) { // 兜底逻辑:如果忘记在Inspector拖引用,运行时自动查找场景中的WispDisplay实例 if (wd == null) { wd = FindObjectOfType<WispDisplay>(); } wd.setWisp(wd.getWisp() + 1); Destroy(gameObject); } } }
优化后的UI显示脚本 WispDisplay
原脚本每帧刷新文本的写法会产生不必要的性能开销,改为数值更新时主动刷新即可:
using UnityEngine.UI; public class WispDisplay : MonoBehaviour { public int Wisp = 5; public Text WispText; void Start() { RefreshWispText(); } public int getWisp() { return Wisp; } public void setWisp(int newWisp) { Wisp = newWisp; RefreshWispText(); } private void RefreshWispText() { WispText.text = "Wisp: " + Wisp.ToString(); } }
注意事项
- 标签判断优先用
CompareTag方法,直接用==对比tag字符串性能更低,且拼写错误时不会抛出提示,排查问题难度更高。 - 非必要不要在运行时用
FindObjectOfType查找对象,场景物体较多时该方法开销很高,Inspector拖拽赋值是最高效稳定的方案。 - 只要类继承了
MonoBehaviour,就永远不要手动写new 类名()来创建实例。
内容的提问来源于stack exchange,提问作者Victor Zhou
相关产品推荐
相关产品推荐

