Menu
CoddyTech

单例

本课属于 Coddy Unity 学习旅程的“打造真正的游戏”单元。第 13 课,共 60 课。

Inspector 引用需要有可供拖入的对象。Spawner 在游戏过程中生成的敌人来自预制体,而预制体只能引用资源和自身的组件,不能引用场景中的对象,所以它们的 GameManager 字段是空的。通常的解决办法是使用单例:GameManager 将自身存储在一个字段中,每个脚本都可以通过类名访问这个字段。

public class GameManager : MonoBehaviour
{
    public static GameManager Instance;
    private int kills;

    void Awake()
    {
        Instance = this;
    }

    public void EnemyDown()
    {
        kills++;
        Debug.Log("Kills: " + kills);
    }
}
// Enemy.cs,挂在敌人预制体上
public void Die()
{
    GameManager.Instance.EnemyDown();
    Destroy(gameObject);
}

static 表示这个字段属于类,而不是某个对象。每个 GameManager 对象都会有自己的 kills,但整个游戏中只有一个 Instance,你可以通过类名访问它:GameManager.Instance。任何脚本都能读取它,包括刚刚生成的敌人,而且不需要为它填写自己的字段。

管理器会在 Awake 中设置 Instance = this;,其中 this 指的是脚本本身。Unity 会在运行任何 Start 之前,先运行场景中的每个 Awake,因此其他脚本从自己的 Start 开始就能使用 GameManager.Instance。如果场景中有第二个 GameManager,它会用自身覆盖 Instance;“场景和关卡”一章会介绍如何阻止这种情况。

challenge icon

挑战

简单

让流星通过单例访问 GameManager。

  1. 在 GameManager.cs 中,添加 public static GameManager Instance;,并添加包含 Instance = this; 的 Awake()。
  2. 在 Meteor.cs 中,删除 game 字段,并改为调用 GameManager.Instance.MeteorLanded() 和 GameManager.Instance.MeteorCaught()。

按下“开始”并接住一颗流星:界面会显示 Caught: 1,控制台中没有错误。然后点击“检查”。

亲手试试

using UnityEngine;
using TMPro;

public class GameManager : MonoBehaviour
{
    public TMP_Text caughtText;
    public TMP_Text shieldText;
    private int caught;
    private int shield = 3;

    public void MeteorCaught()
    {
        caught++;
        caughtText.text = "Caught: " + caught;
    }

    public void MeteorLanded()
    {
        shield--;
        shieldText.text = "Shield: " + shield;
    }
}

打造真正的游戏中的所有课

自己练习: Unity 在线编辑器