使用静态类
当您需要广泛访问程序的某些子系统时,静态类非常有用,因此它们在游戏中被广泛使用。
/// <summary>Save/load is a good example because it
/// doesn't need any settings and it's
/// useful to call it from almost anywhere.</summary>
public static class GameSaver {
/// <summary>I save the game when I'm run.</summary>
public static void Save() {
// Save the game!
}
}
要使用静态类,您只需直接使用成员 - 例如GameSaver.Save(); 将在“任何地方”工作。属性、字段、事件等都可以设为静态,但请先查看以下注释。
这是避免某种"god class" 的最简单方法 - 这似乎是您所描述的(是的,它们通常是代码灾难!) - 这是一个类过于复杂,什么都做。将其分解为一系列小的、独立的模块。
不过不要过度使用静态字段!
为此使用单例。
特别是在游戏中,只有一次实例化的事物(例如播放器或音频系统)非常普遍,它们还需要易于重置或具有大量属性。
重要的是不要将它们全部作为静态字段 - 这将难以重置和调试。这就是您使用静态字段并实例化普通类的地方 - 这称为 singleton:
/// <summary>There's only ever one background music source!
/// It has instance properties though (i.e. an AudioSource)
/// so it works well as a singleton.</summary>
public class BackgroundMusic {
/// <summary>The static field - use the Play method from anywhere.</summary>
private static BackgroundMusic Current;
/// <summary>Plays the given clip.</summary>
public static void Play(AudioClip clip) {
if (Current == null) {
// It's not been setup yet - create it now:
Current = new BackgroundMusic();
}
// E.g. Current.Source.Play(clip);
}
public BackgroundMusic() {
// Instance a source now.
}
}
这只是意味着BackgroundMusic.Play(..); 可以在任何地方使用。这种方法意味着您无需在检查器中设置任何内容 - 只需调用该方法即可按需设置。
当 MonoBehaviour 很棒时
通常认为所有代码都必须是 MonoBehaviour 并且必须附加到游戏对象。这不是 Unity 的实际工作方式。当一切都是 MonoBehaviour 并且必须全部手动实例化和连接时,这只会为使用编辑器的人带来更多的工作。
要明确,我并不是说根本不要使用 MonoBehaviour。相反,您应该根据代码实际表示的内容来使用组件模型和静态的适当组合。
一般:
- 如果某事只有一个实例,请使用单例。
-
但是如果只有一个并且它具有在检查器中编辑有用的属性,请使用 MonoBehaviour 并将对单个对象的引用也保留为静态字段。
其中一个例子是玩家(在单人游戏中)具有一系列您希望更改的默认设置。您可以将播放器设置为预制件,并拥有某种引用当前实例的 PlayerSettings.Current 静态字段:
/// <summary>Add this to a player prefab.</summary>
public class PlayerSettings : MonoBehaviour{
/// <summary>Still following the singleton pattern.</summary>
public static PlayerSettings Current;
/// <summary>Player speed. This can be edited in the inspector.</summary>
public float Speed;
public void Awake() {
// Update the static field:
Current = this;
}
}
这种方法两全其美——您可以在任何地方使用PlayerSettings.Current(在播放器预制件被实例化之后),而不必放弃检查器。它也比GameObject.Find("Player/Body").GetComponent<PlayerSettings>(); 之类的东西更容易重构,使其更易于维护。
多个实例
如果有多个实例的东西,比如 NPC,那么通常你总是会使用带有 MonoBehaviour 的预制件。但是,使用静态方法对以下情况非常有用:
public class NPC : MonoBehaviour{
/// <summary>Gets an NPC by their name.</summary>
public static NPC Locate(string name){
// E.g. get all GameObject instances with an NPC component.
// Return the first one which has a 'Name' value that matches.
}
/// <summary>The name of this NPC (editable in the inspector).
public string Name;
}
NPC.Locate("Dave"); 对于它的实际预期作用变得不言自明。