Menu
CoddyTech

Singleton Pattern

Part of the Object Oriented Programming section of Coddy's GDScript journey. Lesson 46 of 65.

The Singleton pattern makes sure a class has exactly one object and gives every script one way to reach it. Use it for things a game has only one of: the settings, the save system, the score keeper.

In GDScript, a static var holds the single object, and a static func creates it the first time someone asks for it:

# 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 belongs to the class, not to an object, so every script sees the same variable. The first call finds it empty and creates the object; every later call returns that same object.

# 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 and b are two variables holding one object, so the change made through a shows through b. For objects, == is true only when both sides are the same object.

GDScript cannot make _init() private, so nothing stops a script from calling GameSettings.new() and getting a second object. The underscore in _instance and the get_instance() method are the agreement: scripts ask for the object, they never create it.

In a Godot project, the usual way to get one shared object is an autoload: a script you register in Project Settings, which Godot creates once when the game starts and makes available by name in every script. It is a Singleton that Godot manages for you. Autoloads are set up in the editor, so the challenges here build the pattern in code with static var.

challenge icon

Challenge

Easy

Every coin in a game adds to one shared score. Make ScoreManager a Singleton:

  • A static var holds the single object.
  • static func get_instance() returns it, creating it on the first call. Right after creating it, it prints Score manager created.
  • add_points(points) adds to score.

In coin.gd, collect() adds the coin's value to the score through ScoreManager.get_instance().

The supplied code reads how many events follow, then one event per line: coin VALUE collects a new coin, bonus POINTS adds points directly. After each event it prints the score, and at the end whether two calls of get_instance() return the same object. For coin 5 and bonus 20 the output is:

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

Your code goes in score_manager.gd and coin.gd. main.gd holds the supplied input/output code and cannot be edited.

Try it yourself

extends Node

func _ready():
	# Supplied input/output code: keep it as it is
	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 iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Online GDScript compiler