capri/autoloads/scene_manager.gd
2025-03-02 18:02:05 -05:00

89 lines
2.6 KiB
GDScript

extends Node
## Methods of scaling the game viewport.
enum ScaleMode {
## Maintain aspect ratio and scale by highest whole number that will fit within the screen.
INTEGER,
## Maintain aspect ratio and scale to fill at least one axis.
ASPECT,
## Stretch to fill screen, ignoring aspect ratio.
STRETCH,
}
## The [enum ScaleMode] currently in use.
@export var scale_mode: ScaleMode = ScaleMode.INTEGER
@export_group("Internal References")
## Viewport the game is rendered in.
@export var viewport: SubViewport
## Control that holds the viewport. Resized according to [member scale_mode].
@export var viewport_holder: Control
## Design/native resolution of the game.
@onready var resolution: Vector2 = Vector2(
ProjectSettings.get_setting("display/window/size/viewport_width"),
ProjectSettings.get_setting("display/window/size/viewport_height")
)
@onready var win_sound = $WinSound
## The currently active scene.
##
## Setting this will remove and free the previously active scene if it exists.
var current_scene: Node:
set(new_scene):
# do nothing if already current scene
if current_scene == new_scene:
return
# remove current scene
if current_scene:
viewport.remove_child(current_scene)
current_scene.queue_free()
# add new scene
if new_scene.is_inside_tree():
new_scene.get_parent().remove_child(new_scene)
viewport.add_child(new_scene)
current_scene = new_scene
func _ready() -> void:
var tree := get_tree()
await tree.process_frame
# capture the main scene
if tree.current_scene != self:
current_scene = tree.current_scene
tree.current_scene = self
# gather screen_overlay references
for child in tree.root.get_children():
if child is Control:#and child.is_in_group(&"screen_overlay")
child.get_parent().remove_child(child)
viewport_holder.add_child(child)
child.set_anchors_preset(Control.PRESET_CENTER, false)
child.size = resolution
child.pivot_offset = resolution * 0.5
# set up viewport display
viewport.size = resolution
viewport_holder.size = resolution
viewport_holder.pivot_offset = resolution * 0.5
_on_window_size_changed()
tree.root.size_changed.connect(_on_window_size_changed)
func _on_window_size_changed() -> void:
# gather resolution information
var screen_size := Vector2(get_tree().root.size)
var scale_delta := screen_size / resolution
# apply scale mode
match scale_mode:
ScaleMode.INTEGER:
var scale = floorf(minf(scale_delta.x, scale_delta.y))
viewport_holder.scale = Vector2(scale, scale)
ScaleMode.ASPECT:
var scale = minf(scale_delta.x, scale_delta.y)
viewport_holder.scale = Vector2(scale, scale)
ScaleMode.STRETCH:
viewport_holder.scale = scale_delta