My solution for dynamic font scaling in Godot (i.e. being able to increase/decrease all fonts in the game in the config menu). I searched for it a while ago, and found nothing, so I’m sharing my solution here to the next person who needs it.
EDIT: forgot to mention that this snippet runs on an autoload script
extends Node
signal font_size_changed
# Font size options, displayed in an
# OptionButton node in the config menu
enum FontSize {
SMALL = 0,
MEDIUM = 1,
LARGE = 2
}
var _current_font_size_mult: float = 1
var _original_sizes: Dictionary[Node, int] = {}
var _rich_text_original_sizes: Dictionary[Node, int] = {}
var _font_size_mult: Dictionary[FontSize, float] = {
FontSize.SMALL: 1,
FontSize.MEDIUM: 1.25,
FontSize.LARGE: 1.5
}
# Public functions
func get_font_size_mult() -> float:
return _current_font_size_mult
func get_font_size_index() -> FontSize:
return _font_size_mult.find_key(_current_font_size_mult)
func set_font_size_index(size: FontSize) -> void:
if not _font_size_mult.has(size):
return
var new_font_size = _font_size_mult.get(size)
if new_font_size == _current_font_size_mult:
return
_current_font_size_mult = new_font_size
_update_all_fonts()
font_size_changed.emit()
# Lifecycle overrides
func _ready() -> void:
get_tree().node_added.connect(_add_to_list_and_update)
get_tree().node_removed.connect(_remove_from_list)
_font_size_initial_update.call_deferred()
# Private functions
func _font_size_initial_update() -> void:
for node in get_tree().current_scene.find_children("*"):
_add_to_list_and_update(node)
# Also have to update the fonts on my scene manager autoload
for node in SceneManger.find_children("*"):
_add_to_list_and_update(node)
func _update_all_fonts() -> void:
for node in _original_sizes:
node.add_theme_font_size_override("font_size", _original_sizes[node] * _current_font_size_mult)
for rich_text in _rich_text_original_sizes:
rich_text.add_theme_font_size_override("normal_font_size", _rich_text_original_sizes[rich_text] * _current_font_size_mult)
func _add_to_list_and_update(node: Node) -> void:
if node is RichTextLabel:
_rich_text_original_sizes[node] = node.get_theme_font_size("normal_font_size")
node.add_theme_font_size_override("normal_font_size", _rich_text_original_sizes[node] * _current_font_size_mult)
elif node is Control or node is PopupMenu:
_original_sizes[node] = node.get_theme_font_size("font_size")
node.add_theme_font_size_override("font_size", _original_sizes[node] * _current_font_size_mult)
# If you have an OptionButton in your game, you need
# this snippet to uptade it's popup menu font
if node is OptionButton:
var popup_menu = node.get_popup()
_original_sizes[popup_menu] = _original_sizes[node]
popup_menu.add_theme_font_size_override("font_size", _original_sizes[popup_menu] * _current_font_size_mult)
func _remove_from_list(node: Node) -> void:
if node is RichTextLabel:
_rich_text_original_sizes.erase(node)
elif node is Control or node is PopupMenu:
_original_sizes.erase(node)