Unity跨脚本调用对象遇问题:SetActive与static引发CS0120错误
问题描述
需要在RunOnce脚本中引用SpeechAppearsSETACTIVE脚本内的speechBubbleTOSpawn对象,尝试将其设为public static变量时触发错误:
Assets/RunOnce.cs(8,37): error CS0120: An object reference is required for the non-static field method, or property 'SpeechAppearsSETACTIVE.speechBubbleTOSpawn'
核心需求:Torso 2首次被选中时显示气泡,后续选中不再显示,当前用PlayerPrefs记录状态,但跨脚本引用方式错误,寻求其他实现方法。
当前RunOnce脚本代码:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class RunOnce : MonoBehaviour { int FirstTime; //boolean true/false private GameObject YesSpeech => SpeechApearsSETACTIVE.speechBubbleTOSpawn; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { FirstTime = PlayerPrefs.GetInt("FirstTime"); //obtains int value // 0 = true // 1 = false if (FirstTime == 0) { YesSpeech.SetActive(true); } else { YesSpeech.SetActive(false); } } }
解决方案
方法1:单例模式获取脚本实例
给SpeechAppearsSETACTIVE添加单例逻辑,全局获取实例后就能访问非静态的speechBubbleTOSpawn:
public class SpeechAppearsSETACTIVE : MonoBehaviour { public GameObject speechBubbleTOSpawn; public static SpeechAppearsSETACTIVE Instance; void Awake() { if (Instance == null) Instance = this; else Destroy(gameObject); } }
修改RunOnce的引用代码:
private GameObject YesSpeech => SpeechAppearsSETACTIVE.Instance.speechBubbleTOSpawn;
方法2:直接查找组件/对象
如果SpeechAppearsSETACTIVE挂载的对象固定,可在RunOnce里直接查找,同时优化PlayerPrefs的读取逻辑(不要每帧读):
using System.Collections; using System.Collections.Generic; using UnityEngine; public class RunOnce : MonoBehaviour { int FirstTime; private GameObject YesSpeech; private SpeechAppearsSETACTIVE speechScript; void Start() { // 方式1:通过对象名查找 GameObject speechObj = GameObject.Find("SpeechAppearsObject"); speechScript = speechObj.GetComponent<SpeechAppearsSETACTIVE>(); // 方式2:场景只有一个该组件时用这个 // speechScript = FindObjectOfType<SpeechAppearsSETACTIVE>(); YesSpeech = speechScript.speechBubbleTOSpawn; // 初始化时读一次PlayerPrefs,默认值设为0(首次进入) FirstTime = PlayerPrefs.GetInt("FirstTime", 0); UpdateSpeechState(); } void UpdateSpeechState() { if (YesSpeech != null) YesSpeech.SetActive(FirstTime == 0); } // 不要在Update里瞎跑逻辑,Torso2被选中时手动调用这个方法 public void OnTorso2Selected() { if (FirstTime == 0) { UpdateSpeechState(); PlayerPrefs.SetInt("FirstTime", 1); PlayerPrefs.Save(); } } }
方法3:把逻辑整合到SpeechAppearsSETACTIVE中
既然气泡显示和Torso2首次选中强相关,直接把判断逻辑移到SpeechAppearsSETACTIVE里,彻底避免跨脚本引用:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SpeechAppearsSETACTIVE : MonoBehaviour { public GameObject speechBubbleTOSpawn; void Start() { int hasShown = PlayerPrefs.GetInt("Torso2SpeechShown", 0); speechBubbleTOSpawn.SetActive(hasShown == 0); } // Torso2被选中时调用这个方法 public void OnTorso2Selected() { int hasShown = PlayerPrefs.GetInt("Torso2SpeechShown", 0); if (hasShown == 0) { speechBubbleTOSpawn.SetActive(true); PlayerPrefs.SetInt("Torso2SpeechShown", 1); PlayerPrefs.Save(); } } }
额外优化提示
- 别在
Update里每帧读PlayerPrefs,这是IO操作,频繁调用拖性能,初始化读一次、状态变化时写就行。 - 给
PlayerPrefs的键名起个明确的名字,比如"Torso2FirstSelected",避免和其他功能冲突。 - 加个空引用判断,防止找不到对象时报错。
内容的提问来源于stack exchange,提问作者TirimasuBread
相关产品推荐
相关产品推荐

