You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
        }
    }
}

额外优化提示

  1. 别在Update里每帧读PlayerPrefs,这是IO操作,频繁调用拖性能,初始化读一次、状态变化时写就行。
  2. 给PlayerPrefs的键名起个明确的名字,比如"Torso2FirstSelected",避免和其他功能冲突。
  3. 加个空引用判断,防止找不到对象时报错。

内容的提问来源于stack exchange,提问作者TirimasuBread

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 23:55:21