93 lines
2.8 KiB
GDScript
93 lines
2.8 KiB
GDScript
extends Node
|
|
|
|
|
|
## Emitted when the current scene is changed.
|
|
signal current_scene_changed(new_scene: 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")
|
|
)
|
|
|
|
|
|
## 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.call_deferred(current_scene)
|
|
current_scene.queue_free()
|
|
# add new scene
|
|
if new_scene.is_inside_tree():
|
|
new_scene.get_parent().remove_child.call_deferred(new_scene)
|
|
viewport.add_child.call_deferred(new_scene)
|
|
current_scene = new_scene
|
|
current_scene_changed.emit(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
|