Menu
CoddyTech

Singleton-Muster

Teil des Abschnitts Objektorientierte Programmierung der GDScript-Journey von Coddy. Lektion 46 von 65.

Das Singleton-Muster stellt sicher, dass eine Klasse genau ein Objekt hat, und bietet jedem Skript eine Möglichkeit, darauf zuzugreifen. Verwende es für Dinge, von denen es in einem Spiel nur eines gibt: die Einstellungen, das Speichersystem, die Punkteverwaltung.

In GDScript enthält eine static var das einzelne Objekt, und eine static func erstellt es, wenn zum ersten Mal danach gefragt wird:

# 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 gehört zur Klasse, nicht zu einem Objekt, daher sieht jedes Skript dieselbe Variable. Beim ersten Aufruf ist sie leer und das Objekt wird erstellt; jeder spätere Aufruf gibt dasselbe Objekt zurück.

# 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 und b sind zwei Variablen, die dasselbe Objekt enthalten, daher ist die über a vorgenommene Änderung auch über b sichtbar. Bei Objekten ist == nur dann true, wenn beide Seiten dasselbe Objekt sind.

GDScript kann _init() nicht privat machen, daher hindert nichts ein Skript daran, GameSettings.new() aufzurufen und ein zweites Objekt zu erhalten. Der Unterstrich in _instance und die Methode get_instance() bilden die Vereinbarung: Skripte fragen nach dem Objekt, sie erstellen es niemals selbst.

In einem Godot-Projekt erhält man ein gemeinsam genutztes Objekt üblicherweise über einen Autoload: ein Skript, das du in den Projekteinstellungen registrierst und das Godot beim Start des Spiels einmal erstellt und in jedem Skript unter seinem Namen verfügbar macht. Es ist ein Singleton, das Godot für dich verwaltet. Autoloads werden im Editor eingerichtet, daher bauen die Herausforderungen hier das Muster mit static var im Code nach.

challenge icon

Aufgabe

Einfach

Jede Münze in einem Spiel erhöht einen gemeinsamen Punktestand. Mache ScoreManager zu einem Singleton:

  • Ein static var enthält das einzelne Objekt.
  • static func get_instance() gibt es zurück und erstellt es beim ersten Aufruf. Direkt nach der Erstellung gibt es Score manager created aus.
  • add_points(points) addiert Punkte zu score.

In coin.gd addiert collect() den value der Münze über ScoreManager.get_instance() zum Punktestand.

Der bereitgestellte Code liest ein, wie viele Ereignisse folgen, und danach ein Ereignis pro Zeile: coin VALUE sammelt eine neue Münze ein, bonus POINTS addiert direkt Punkte. Nach jedem Ereignis gibt er den Punktestand aus und am Ende, ob zwei Aufrufe von get_instance() dasselbe Objekt zurückgeben. Für coin 5 und bonus 20 lautet die Ausgabe:

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

Dein Code gehört in score_manager.gd und coin.gd. main.gd enthält den bereitgestellten Eingabe-/Ausgabecode und kann nicht bearbeitet werden.

Probier es selbst

extends Node

func _ready():
	# Vorgegebener Ein-/Ausgabecode: unverändert lassen
	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 dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-GDScript-Compiler