单例模式
本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 46 课,共 65 课。
Singleton 模式确保一个类恰好只有一个对象,并为每个脚本提供一种访问它的方式。游戏中只有一个的东西适合使用这种模式,例如设置、存档系统和计分器。
在 GDScript 中,static var 保存唯一的对象,而 static func 会在有人首次请求该对象时创建它:
# game_settings.gd
class_name GameSettings
extends RefCounted
static var _instance: GameSettings = null
var volume := 50
static func get_instance() -> GameSettings:
if _instance == null:
_instance = GameSettings.new()
print("Creating settings")
return _instance_instance 属于类,而不属于对象,因此每个脚本看到的都是同一个变量。第一次调用时会发现它是空的,于是创建对象;之后每次调用都会返回同一个对象。
# main.gd
var a := GameSettings.get_instance()
var b := GameSettings.get_instance()
a.volume = 80
print(b.volume)
print(a == b)Creating settings
80
truea 和 b 是指向同一个对象的两个变量,因此通过 a 所做的更改也会通过 b 显现。对于对象,只有当两边是同一个对象时,== 才是 true。
GDScript 无法将 _init() 设为私有,因此无法阻止脚本调用 GameSettings.new() 并创建第二个对象。_instance 中的下划线和 get_instance() 方法共同构成约定:脚本只请求获取对象,不会自行创建对象。
在 Godot 项目中,获取一个共享对象的常用方法是使用自动加载:在项目设置中注册一个脚本,Godot 会在游戏启动时创建一次,并让每个脚本都能通过名称访问它。这是一个由 Godot 管理的单例。自动加载需要在编辑器中设置,因此这里的挑战会用代码通过 static var 实现这一模式。
挑战
简单游戏中的每枚硬币都会增加同一个共享分数。将 ScoreManager 实现为单例:
- 用一个
static var保存唯一的对象。 static func get_instance()返回该对象,并在首次调用时创建它。创建后立即打印Score manager created。add_points(points)将分数加到score上。
在 coin.gd 中,collect() 通过 ScoreManager.get_instance() 将硬币的 value 加到分数上。
给定代码会读取后续事件的数量,然后逐行读取每个事件:coin VALUE 会收集一枚新硬币,bonus POINTS 会直接增加分数。每个事件处理后都会打印分数,最后会打印两次调用 get_instance() 是否返回同一个对象。对于 coin 5 和 bonus 20,输出为:
Score manager created
Score: 5
Score: 25
Same object: true你的代码写在 score_manager.gd 和 coin.gd 中。main.gd 包含给定的输入/输出代码,不能编辑。
亲手试试
extends Node
func _ready():
# 提供的输入输出代码:保持原样。
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
if parts[0] == "coin":
Coin.new(int(parts[1])).collect()
elif parts[0] == "bonus":
ScoreManager.get_instance().add_points(int(parts[1]))
print("Score: %d" % ScoreManager.get_instance().score)
print("Same object: %s" % (ScoreManager.get_instance() == ScoreManager.get_instance()))
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: GDScript 在线编译器