diff --git a/assets/shaders/test_filter.gdshader b/assets/shaders/test_filter.gdshader new file mode 100644 index 0000000..30c97d1 --- /dev/null +++ b/assets/shaders/test_filter.gdshader @@ -0,0 +1,15 @@ +shader_type canvas_item; + +uniform sampler2D SCREEN_TEXTURE : hint_screen_texture; + +vec2 warp(vec2 uv) { + return vec2( + uv.x + sin(TIME + uv.y * 50.0) * 0.005, + uv.y + ); +} + +void fragment() { + vec2 uv = warp(SCREEN_UV); + COLOR = texture(SCREEN_TEXTURE, uv); +} \ No newline at end of file diff --git a/autoloads/scene_manager.gd b/autoloads/scene_manager.gd new file mode 100644 index 0000000..6258ad2 --- /dev/null +++ b/autoloads/scene_manager.gd @@ -0,0 +1,88 @@ +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") +) + + +## 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 diff --git a/autoloads/scene_manager.tscn b/autoloads/scene_manager.tscn new file mode 100644 index 0000000..c6b2b0d --- /dev/null +++ b/autoloads/scene_manager.tscn @@ -0,0 +1,49 @@ +[gd_scene load_steps=2 format=3 uid="uid://ckgsfhfpg00ys"] + +[ext_resource type="Script" path="res://autoloads/scene_manager.gd" id="1_1hxm1"] + +[node name="SceneManager" type="Node" node_paths=PackedStringArray("viewport", "viewport_holder")] +script = ExtResource("1_1hxm1") +viewport = NodePath("ViewportHolder/ViewportContainer/SubViewport") +viewport_holder = NodePath("ViewportHolder") + +[node name="ClearColor" type="CanvasLayer" parent="."] +layer = -128 + +[node name="ColorRect" type="ColorRect" parent="ClearColor"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0, 0, 0, 1) + +[node name="ViewportHolder" type="Control" parent="."] +layout_mode = 3 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -144.0 +offset_top = -108.0 +offset_right = 144.0 +offset_bottom = 108.0 +grow_horizontal = 2 +grow_vertical = 2 +pivot_offset = Vector2(144, 108) + +[node name="ViewportContainer" type="SubViewportContainer" parent="ViewportHolder"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +pivot_offset = Vector2(144, 108) + +[node name="SubViewport" type="SubViewport" parent="ViewportHolder/ViewportContainer"] +handle_input_locally = false +canvas_item_default_texture_filter = 0 +size = Vector2i(288, 216) +render_target_update_mode = 4 diff --git a/autoloads/test_filter.tscn b/autoloads/test_filter.tscn new file mode 100644 index 0000000..bcba337 --- /dev/null +++ b/autoloads/test_filter.tscn @@ -0,0 +1,14 @@ +[gd_scene load_steps=3 format=3 uid="uid://bbrh8j4w6pgj2"] + +[ext_resource type="Shader" path="res://assets/shaders/test_filter.gdshader" id="1_un711"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_au4vs"] +shader = ExtResource("1_un711") + +[node name="TestFilter" type="ColorRect" groups=["screen_overlay"]] +material = SubResource("ShaderMaterial_au4vs") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 diff --git a/project.godot b/project.godot index 7b43b40..c727868 100644 --- a/project.godot +++ b/project.godot @@ -15,12 +15,15 @@ run/main_scene="res://maps/level1.tscn" config/features=PackedStringArray("4.3", "GL Compatibility") config/icon="res://icon.svg" +[autoload] + +SceneManager="*res://autoloads/scene_manager.tscn" +TestFilter="*res://autoloads/test_filter.tscn" + [display] window/size/viewport_width=288 window/size/viewport_height=216 -window/stretch/mode="viewport" -window/stretch/scale_mode="integer" [editor_plugins] @@ -31,11 +34,16 @@ enabled=PackedStringArray("res://addons/godot_state_charts/plugin.cfg") folder_colors={ "res://addons/": "gray", "res://assets/": "yellow", +"res://autoloads/": "orange", "res://maps/": "blue", "res://objects/": "red", "res://scripts/": "teal" } +[global_group] + +screen_overlay="Autoload that will be rendered over the game viewport at full resolution." + [layer_names] 2d_physics/layer_1="solid"