Menu
CoddyTech

单例模式

本课属于 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
true

a 和 b 是指向同一个对象的两个变量,因此通过 a 所做的更改也会通过 b 显现。对于对象,只有当两边是同一个对象时,== 才是 true。

GDScript 无法将 _init() 设为私有,因此无法阻止脚本调用 GameSettings.new() 并创建第二个对象。_instance 中的下划线和 get_instance() 方法共同构成约定:脚本只请求获取对象,不会自行创建对象。

在 Godot 项目中,获取一个共享对象的常用方法是使用自动加载:在项目设置中注册一个脚本,Godot 会在游戏启动时创建一次,并让每个脚本都能通过名称访问它。这是一个由 Godot 管理的单例。自动加载需要在编辑器中设置,因此这里的挑战会用代码通过 static var 实现这一模式。

challenge icon

挑战

简单

游戏中的每枚硬币都会增加同一个共享分数。将 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()))
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: GDScript 在线编译器