Menu
CoddyTech

Patrón Singleton

Parte de la sección Programación orientada a objetos del Journey de GDScript de Coddy. Lección 46 de 65.

El patrón Singleton garantiza que una clase tenga exactamente un objeto y ofrece a todos los scripts una forma de acceder a él. Úsalo para cosas de las que un juego solo tiene una: la configuración, el sistema de guardado y el gestor de puntuación.

En GDScript, una static var contiene el objeto único, y una static func lo crea la primera vez que alguien lo 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 pertenece a la clase, no a un objeto, así que todos los scripts ven la misma variable. La primera llamada la encuentra vacía y crea el objeto; todas las llamadas posteriores devuelven ese mismo 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 y b son dos variables que contienen un mismo objeto, así que el cambio realizado mediante a también se refleja en b. Para los objetos, == es true solo cuando ambos lados son el mismo objeto.

GDScript no puede hacer que _init() sea privado, así que nada impide que un script llame a GameSettings.new() y obtenga un segundo objeto. El guion bajo en _instance y el método get_instance() son el acuerdo: los scripts solicitan el objeto, nunca lo crean.

En un proyecto de Godot, la forma habitual de obtener un objeto compartido es mediante un autoload: un script que registras en la configuración del proyecto, que Godot crea una vez al iniciar el juego y pone a disposición por nombre en todos los scripts. Es un Singleton que Godot administra por ti. Los autoloads se configuran en el editor, así que los desafíos de aquí construyen el patrón en código con static var.

challenge icon

Desafío

Fácil

Cada moneda de un juego se suma a una única puntuación compartida. Convierte ScoreManager en un singleton:

  • Un static var guarda el único objeto.
  • static func get_instance() lo devuelve y lo crea en la primera llamada. Justo después de crearlo, imprime Score manager created.
  • add_points(points) suma puntos a score.

En coin.gd, collect() suma el value de la moneda a la puntuación mediante ScoreManager.get_instance().

El código proporcionado lee cuántos eventos vienen a continuación y luego lee un evento por línea: coin VALUE recoge una moneda nueva, bonus POINTS suma puntos directamente. Después de cada evento, imprime la puntuación y, al final, indica si dos llamadas a get_instance() devuelven el mismo objeto. Para coin 5 y bonus 20, la salida es:

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

Tu código va en score_manager.gd y coin.gd. main.gd contiene el código de entrada/salida proporcionado y no se puede editar.

Pruébalo tú mismo

extends Node

func _ready():
	# Código de entrada/salida proporcionado: mantenlo tal 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 iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de GDScript online