RPG #11 - Options

Any game worth its weight in salt provides an options screen for players to modify their experience. I figured it’s probably best to build this feature early on so that I can already take it into account when building new features.

UI

I don’t know what options I will be supporting in the future, so I’m starting with something simple and flexible.

Options screen with one vertical column of options

Another important set of options, especially on PC is the ability to change controls. No matter how much thought you put in your control scheme, there are always people that prefer it differently (I am such people).

Input mapping that allows modifying Godot’s Input Map

Persistance

In order to make the options available throughout the game I’ve created an Options AutoLoad singleton that exposes methods to set and retrieve certain options, and sends out signals whenever something changes. At the cost of a bit more work up-front I decided to write methods for each option to improve autocomplete and make things a bit less error prone to use.

const config_path = 'user://settings.cfg'

func _ready() -> void:
	config = ConfigFile.new()
	var err = config.load(config_path)
	if err == ERR_FILE_NOT_FOUND:
		err = config.save(config_path)

func set_fullscreen_enabled(fullscreen_enabled: bool) -> void:
	config.set_value(FULLSCREEN_SECTION, FULLSCREEN_KEY, fullscreen_enabled)

func get_fullscreen_enabled() -> bool:
	return config.get_value(FULLSCREEN_SECTION, FULLSCREEN_KEY, FULLSCREEN_DEFAULT)

func save():
	config.save(config_path)

Using a ConfigFile allows me to easily maintain an .ini file with the users selected options. In order to keep it around for the next time the player starts the game I store the config file in the User path.

For the input mapping screen I used Godot’s InputMap to read and restore input mappings using the input_mapping as an example.