Menu
CoddyTech

Padrão Singleton

Parte da seção Programação orientada a objetos do Journey de GDScript da Coddy. Lição 46 de 65.

O padrão Singleton garante que uma classe tenha exatamente um objeto e oferece a cada script uma maneira de acessá-lo. Use-o para coisas das quais um jogo tem apenas uma: as configurações, o sistema de salvamento, o gerenciador de pontuação.

No GDScript, uma static var mantém o objeto único, e uma static func o cria na primeira vez que alguém o solicita:

# 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 pertence à classe, não a um objeto, então todos os scripts veem a mesma variável. A primeira chamada a encontra vazia e cria o objeto; todas as chamadas posteriores retornam esse mesmo objeto.

# 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 e b são duas variáveis que contêm um objeto, então a alteração feita por meio de a também aparece em b. Para objetos, == é true somente quando os dois lados são o mesmo objeto.

GDScript não pode tornar _init() privado, então nada impede que um script chame GameSettings.new() e obtenha um segundo objeto. O sublinhado em _instance e o método get_instance() são o acordo: os scripts solicitam o objeto, nunca o criam.

Em um projeto Godot, a maneira usual de obter um objeto compartilhado é por meio de um autoload: um script que você registra nas Configurações do Projeto, que o Godot cria uma vez quando o jogo inicia e disponibiliza pelo nome em todos os scripts. Ele é um Singleton gerenciado pelo Godot para você. Os autoloads são configurados no editor, então os desafios aqui criam o padrão em código com static var.

challenge icon

Desafio

Fácil

Cada moeda em um jogo aumenta uma pontuação compartilhada. Faça de ScoreManager um Singleton:

  • Uma static var armazena o único objeto.
  • static func get_instance() retorna esse objeto, criando-o na primeira chamada. Logo após criá-lo, ele imprime Score manager created.
  • add_points(points) adiciona pontos a score.

Em coin.gd, collect() adiciona o value da moeda à pontuação por meio de ScoreManager.get_instance().

O código fornecido lê quantos eventos vêm a seguir e, então, um evento por linha: coin VALUE coleta uma nova moeda, bonus POINTS adiciona pontos diretamente. Após cada evento, ele imprime a pontuação e, ao final, informa se duas chamadas de get_instance() retornam o mesmo objeto. Para coin 5 e bonus 20, a saída é:

Score manager created
Score: 5
Score: 25
Same object: true

Seu código deve ficar em score_manager.gd e coin.gd. main.gd contém o código de entrada/saída fornecido e não pode ser editado.

Experimente você mesmo

extends Node

func _ready():
	# Código de entrada/saída fornecido: mantenha-o como está
	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 iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação orientada a objetos

Pratique por conta própria: Compilador de GDScript online