自动加载(AutoLoad)是Godot Engine一个特有的并且设计非常巧妙的机制。
文章目录什么是单例模式(Singleton)用GDScript无法实现单例模式用自动加载(AutoLoad)实现单例模式单例类1. 定义要单例化的类2. 设置自动加载3. 测试单例场景1. 定义要单例化的场景2. 设置自动加载3. 测试PS:自动加载的实例(场景)到底在哪? 什么是单例模式(Singleton)上世纪90年代由Gof(Gang of Four,四位软件界大牛)合写了一本《Design Patterns: Elements of Reusable Object-Oriented Software》(设计模式:可复用的面向对象软件元素),该书包含23种解决编程时特定问题的“套路”,也就是所谓的“设计模式”。这本书如同武林秘籍《降龙十八掌》,被后辈程序员们奉为必修经典之一。
单例模式就是这23种经典设计模式之一。它要解决两个问题:
某个类(Class)在整个系统中有且只有一个实例。 这个实例可以在整个系统被访问。单例模式是游戏开发最最常用的设计模式之一,比如:各种资源管理类,核心数据类等等的实现大都需要这种“单例类”。
用GDScript无法实现单例模式下面是一个C#版本的单例模式实现(其它语言版本也大体相似):
public class Singleton {
private static Singleton instance = null ;
private Singleton(){
}
public static Singleton Instance {
get {
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
}
实现单例模式的核心要素之一是:“需要一个静态变量指向该类唯一的实例并作为判定有无实例的标志位”。
然而,GDScript—这个简单粗暴的语言—压根儿就没有静态变量这种东西!!!刚接触Godot的时候,这种事实简直无法接受。后来才知道,这个由微型团队开发的游戏引擎,并没有自不量力地企图开发一种“高大全”的脚本语言,而采用了一种“语言不够引擎来凑”的设计策略,用所谓自动加载的引擎机制帮你完成了实现单例模式的需求。这种策略使得GDScript的语言内核足够精简从而容易实现和维护,同时也使它更加容易上手。下面我们来体验一下,用“自动加载”如何简单优雅地实现单例模式。
在Godot中我们不仅可以“单例化”一个类,还可以“单例化”一个配置好的场景。
单例类 1. 定义要单例化的类假设,我们想把下面这个存储游戏的数据的类单例化。
#GameData.gd
extends Node
var score = 0
var hp = 5
var level = 6
2. 设置自动加载
打开项目设置>自动加载
把“GameData.gd”脚本添加自动加载中
注意:这个名称就是你在程序中要调用的变量名
新建一个场景
#SingletonTest.gd
extends Node
func _ready():
print("Player HP: " + str(GameData.hp))
运行一下,输出结果
Player HP: 5
就这么简单地实现了。
单例场景 1. 定义要单例化的场景
下面是场景根节点"AudioManager"上的脚本:
#AudioManager.gd
extends Node
func play(name : String):
var sfx = find_node(name)
if sfx is AudioStreamPlayer:
sfx.play()
2. 设置自动加载
打开项目设置>自动加载
注意:这次我们要添加到自动加载中的不是“AudioManager.gd”脚本,而是挂接了该脚本的“AudioManager.tscn”场景。
3. 测试#ScoreArea.gd
extends Area2D
func _ready():
connect("body_exited",self,"_on_body_exited")
func _on_body_exited(_body):#当有物体穿过
if _body.name == "Bird":#并且判断该物体为小鸟时
AudioManager.play("sfx_point")#音效
这样,当小鸟穿越过一对柱子,就可以播放得分的音效了。
PS:自动加载的实例(场景)到底在哪?当我们运行游戏的时候,在远程
窗口下可以看到游戏运行时场景树的状态,单例的类实例和场景,被自动加载以后作为场景树的root
的直接子节点,而且会出现在其它节点的上方。