From d53e4601e4ac176cd24a01fd1323f476f8c0dc21 Mon Sep 17 00:00:00 2001 From: Yogi Wiguna Date: Tue, 10 Mar 2026 17:04:01 +0800 Subject: [PATCH] feat: Introduce comprehensive settings management with UI for video, audio, and remappable controls. --- project.godot | 4 + scenes/ui/settings_menu.tscn | 274 +++++++++++++++++++---- scripts/managers/player_input_manager.gd | 22 +- scripts/managers/settings_manager.gd | 74 +++++- scripts/ui/settings_menu.gd | 66 +++++- 5 files changed, 382 insertions(+), 58 deletions(-) diff --git a/project.godot b/project.godot index 99f73ce..b6032df 100644 --- a/project.godot +++ b/project.godot @@ -69,24 +69,28 @@ move_north={ "deadzone": 0.5, "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":87,"physical_keycode":0,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null) , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194320,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null) ] } move_south={ "deadzone": 0.5, "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":83,"physical_keycode":0,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null) , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194322,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null) ] } move_west={ "deadzone": 0.5, "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":65,"physical_keycode":0,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null) , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null) ] } move_east={ "deadzone": 0.5, "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":68,"physical_keycode":0,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null) , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194321,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null) ] } move_northeast={ diff --git a/scenes/ui/settings_menu.tscn b/scenes/ui/settings_menu.tscn index adda038..b7cac60 100644 --- a/scenes/ui/settings_menu.tscn +++ b/scenes/ui/settings_menu.tscn @@ -37,6 +37,23 @@ corner_radius_bottom_left = 10 font_size = 24 font_color = Color(0.9, 0.9, 0.9, 1) +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_section_header"] +content_margin_left = 15.0 +content_margin_top = 5.0 +content_margin_right = 15.0 +content_margin_bottom = 5.0 +bg_color = Color(0.2, 0.5, 0.8, 0.3) +corner_radius_top_left = 5 +corner_radius_top_right = 5 +corner_radius_bottom_right = 5 +corner_radius_bottom_left = 5 + +[sub_resource type="LabelSettings" id="LabelSettings_section"] +font_size = 18 +font_color = Color(0.4, 0.9, 1, 1) +outline_size = 2 +outline_color = Color(0, 0, 0, 1) + [node name="SettingsMenu" type="CanvasLayer" unique_id=1319114632] layer = 100 script = ExtResource("1_script") @@ -140,6 +157,62 @@ label_settings = SubResource("LabelSettings_heading") unique_name_in_owner = true layout_mode = 2 +[node name="Resolution" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox" unique_id=100000100] +layout_mode = 2 + +[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox/Resolution" unique_id=100000101] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Resolution" +label_settings = SubResource("LabelSettings_heading") + +[node name="ResolutionBtn" type="OptionButton" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox/Resolution" unique_id=100000102] +unique_name_in_owner = true +custom_minimum_size = Vector2(240, 40) +layout_mode = 2 + +[node name="MSAA" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox" unique_id=100000103] +layout_mode = 2 + +[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox/MSAA" unique_id=100000104] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Anti-Aliasing (MSAA)" +label_settings = SubResource("LabelSettings_heading") + +[node name="MSAABtn" type="OptionButton" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox/MSAA" unique_id=100000105] +unique_name_in_owner = true +custom_minimum_size = Vector2(240, 40) +layout_mode = 2 + +[node name="Shadows" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox" unique_id=100000106] +layout_mode = 2 + +[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox/Shadows" unique_id=100000107] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Shadow Quality" +label_settings = SubResource("LabelSettings_heading") + +[node name="ShadowBtn" type="OptionButton" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox/Shadows" unique_id=100000108] +unique_name_in_owner = true +custom_minimum_size = Vector2(240, 40) +layout_mode = 2 + +[node name="FPSCap" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox" unique_id=100000109] +layout_mode = 2 + +[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox/FPSCap" unique_id=100000110] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Max FPS Cap" +label_settings = SubResource("LabelSettings_heading") + +[node name="FPSCapBtn" type="OptionButton" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Video/VBox/FPSCap" unique_id=100000111] +unique_name_in_owner = true +custom_minimum_size = Vector2(240, 40) +layout_mode = 2 + [node name="Audio" type="VBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer" unique_id=1585166620] visible = false layout_mode = 2 @@ -199,123 +272,232 @@ metadata/_tab_index = 2 [node name="VBox" type="VBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls" unique_id=1592525164] layout_mode = 2 size_flags_horizontal = 3 -theme_override_constants/separation = 10 +theme_override_constants/separation = 15 -[node name="P1" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=2065564199] +[node name="ControllerToggleContainer" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000001] layout_mode = 2 -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/P1" unique_id=85468293] +[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/ControllerToggleContainer" unique_id=100000002] +layout_mode = 2 +size_flags_horizontal = 3 +text = "ENABLE CONTROLLER (JOYSTICK)" +label_settings = SubResource("LabelSettings_heading") + +[node name="UseControllerBtn" type="CheckButton" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/ControllerToggleContainer" unique_id=100000003] +unique_name_in_owner = true +layout_mode = 2 + +[node name="MovementSection" type="PanelContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000004] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_section_header") + +[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MovementSection" unique_id=100000005] +layout_mode = 2 +text = "MOVEMENT CONTROL" +label_settings = SubResource("LabelSettings_section") + +[node name="MoveGrid" type="GridContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000006] +layout_mode = 2 +theme_override_constants/h_separation = 20 +theme_override_constants/v_separation = 10 +columns = 2 + +[node name="UpLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000007] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Move Up" +label_settings = SubResource("LabelSettings_heading") + +[node name="MoveUpBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000008] +unique_name_in_owner = true +custom_minimum_size = Vector2(150, 40) +layout_mode = 2 +text = "W" + +[node name="DownLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000009] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Move Down" +label_settings = SubResource("LabelSettings_heading") + +[node name="MoveDownBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000010] +unique_name_in_owner = true +custom_minimum_size = Vector2(150, 40) +layout_mode = 2 +text = "S" + +[node name="LeftLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000011] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Move Left" +label_settings = SubResource("LabelSettings_heading") + +[node name="MoveLeftBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000012] +unique_name_in_owner = true +custom_minimum_size = Vector2(150, 40) +layout_mode = 2 +text = "A" + +[node name="RightLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000013] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Move Right" +label_settings = SubResource("LabelSettings_heading") + +[node name="MoveRightBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000014] +unique_name_in_owner = true +custom_minimum_size = Vector2(150, 40) +layout_mode = 2 +text = "D" + +[node name="PowerUpSection" type="PanelContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000015] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_section_header") + +[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpSection" unique_id=100000016] +layout_mode = 2 +text = "POWER UP CONTROL" +label_settings = SubResource("LabelSettings_section") + +[node name="PowerUpGrid" type="GridContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000017] +layout_mode = 2 +theme_override_constants/h_separation = 20 +theme_override_constants/v_separation = 10 +columns = 2 + +[node name="P1Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000018] layout_mode = 2 size_flags_horizontal = 3 text = "PowerUp 1 (Speed)" label_settings = SubResource("LabelSettings_heading") -[node name="Powerup1Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/P1" unique_id=643351652] +[node name="Powerup1Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000019] unique_name_in_owner = true custom_minimum_size = Vector2(150, 40) layout_mode = 2 text = "1" -[node name="P2" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=1529813635] -layout_mode = 2 - -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/P2" unique_id=1645306219] +[node name="P2Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000020] layout_mode = 2 size_flags_horizontal = 3 -text = "PowerUp 2 (Freeze)" +text = "PowerUp 2 (Freeze/Ghost)" label_settings = SubResource("LabelSettings_heading") -[node name="Powerup2Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/P2" unique_id=937262208] +[node name="Powerup2Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000021] unique_name_in_owner = true custom_minimum_size = Vector2(150, 40) layout_mode = 2 text = "2" -[node name="P3" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=69920143] -layout_mode = 2 - -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/P3" unique_id=448782584] +[node name="P3Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000022] layout_mode = 2 size_flags_horizontal = 3 text = "PowerUp 3 (Wall)" label_settings = SubResource("LabelSettings_heading") -[node name="Powerup3Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/P3" unique_id=1817070904] +[node name="Powerup3Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000023] unique_name_in_owner = true custom_minimum_size = Vector2(150, 40) layout_mode = 2 text = "3" -[node name="P4" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=559680686] -layout_mode = 2 - -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/P4" unique_id=1049586584] +[node name="P4Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000024] layout_mode = 2 size_flags_horizontal = 3 text = "PowerUp 4 (Ghost)" label_settings = SubResource("LabelSettings_heading") -[node name="Powerup4Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/P4" unique_id=1027617123] +[node name="Powerup4Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000025] unique_name_in_owner = true custom_minimum_size = Vector2(150, 40) layout_mode = 2 text = "4" -[node name="Attack" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=1722218076] +[node name="PowerBarSection" type="PanelContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000026] layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_section_header") -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/Attack" unique_id=1040943113] +[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerBarSection" unique_id=100000027] +layout_mode = 2 +text = "POWER BAR CONTROL" +label_settings = SubResource("LabelSettings_section") + +[node name="PowerBarGrid" type="GridContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000028] +layout_mode = 2 +theme_override_constants/h_separation = 20 +theme_override_constants/v_separation = 10 +columns = 2 + +[node name="AttackLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerBarGrid" unique_id=100000029] layout_mode = 2 size_flags_horizontal = 3 text = "Attack Mode" label_settings = SubResource("LabelSettings_heading") -[node name="AttackModeBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/Attack" unique_id=1913469674] +[node name="AttackModeBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerBarGrid" unique_id=100000030] unique_name_in_owner = true custom_minimum_size = Vector2(150, 40) layout_mode = 2 text = "Q" -[node name="Grab" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=951480662] -layout_mode = 2 - -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/Grab" unique_id=1050214223] -layout_mode = 2 -size_flags_horizontal = 3 -text = "Grab" -label_settings = SubResource("LabelSettings_heading") - -[node name="GrabBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/Grab" unique_id=1307913086] -unique_name_in_owner = true -custom_minimum_size = Vector2(150, 40) -layout_mode = 2 -text = "Space" - -[node name="SpawnBoost" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=1495993475] -layout_mode = 2 - -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/SpawnBoost" unique_id=1933746399] +[node name="SpawnBoostLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerBarGrid" unique_id=100000031] layout_mode = 2 size_flags_horizontal = 3 text = "Spawn Boost" label_settings = SubResource("LabelSettings_heading") -[node name="SpawnBoostBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/SpawnBoost" unique_id=1836762532] +[node name="SpawnBoostBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerBarGrid" unique_id=100000032] unique_name_in_owner = true custom_minimum_size = Vector2(150, 40) layout_mode = 2 text = "E" -[node name="TektonGrab" type="HBoxContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=263116515] +[node name="OtherSection" type="PanelContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000033] layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_section_header") -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/TektonGrab" unique_id=1041049284] +[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherSection" unique_id=100000034] +layout_mode = 2 +text = "INTERACTION CONTROL" +label_settings = SubResource("LabelSettings_section") + +[node name="OtherGrid" type="GridContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000035] +layout_mode = 2 +theme_override_constants/h_separation = 20 +theme_override_constants/v_separation = 10 +columns = 2 + +[node name="GrabLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000036] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Grab Item" +label_settings = SubResource("LabelSettings_heading") + +[node name="GrabBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000037] +unique_name_in_owner = true +custom_minimum_size = Vector2(150, 40) +layout_mode = 2 +text = "Space" + +[node name="PutLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000038] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Put Item" +label_settings = SubResource("LabelSettings_heading") + +[node name="PutBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000039] +unique_name_in_owner = true +custom_minimum_size = Vector2(150, 40) +layout_mode = 2 +text = "R" + +[node name="TektonGrabLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000040] layout_mode = 2 size_flags_horizontal = 3 text = "Grab Tekton" label_settings = SubResource("LabelSettings_heading") -[node name="TektonGrabBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/TektonGrab" unique_id=1884439337] +[node name="TektonGrabBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000041] unique_name_in_owner = true custom_minimum_size = Vector2(150, 40) layout_mode = 2 diff --git a/scripts/managers/player_input_manager.gd b/scripts/managers/player_input_manager.gd index 47f8806..37594d3 100644 --- a/scripts/managers/player_input_manager.gd +++ b/scripts/managers/player_input_manager.gd @@ -18,12 +18,22 @@ func _process(delta): if TurnManager.turn_based_mode: return - # Continuous movement input var move_vec = Vector2i.ZERO - if Input.is_action_pressed("move_north"): move_vec.y -= 1 - if Input.is_action_pressed("move_south"): move_vec.y += 1 - if Input.is_action_pressed("move_east"): move_vec.x += 1 - if Input.is_action_pressed("move_west"): move_vec.x -= 1 + # 1. Controller / Joystick Movement + if SettingsManager and SettingsManager.settings.controls.get("use_controller", false): + var joystick_vec = Input.get_vector("move_west", "move_east", "move_north", "move_south") + if joystick_vec.length() > 0.3: # Deadzone + if abs(joystick_vec.x) > abs(joystick_vec.y): + move_vec.x = 1 if joystick_vec.x > 0 else -1 + else: + move_vec.y = 1 if joystick_vec.y > 0 else -1 + + # 2. Keyboard Movement (Fallback) + if move_vec == Vector2i.ZERO: + if Input.is_action_pressed("move_north"): move_vec.y -= 1 + if Input.is_action_pressed("move_south"): move_vec.y += 1 + if Input.is_action_pressed("move_east"): move_vec.x += 1 + if Input.is_action_pressed("move_west"): move_vec.x -= 1 # Fallback for explicit diagonal actions (if mapped) if move_vec == Vector2i.ZERO: @@ -33,7 +43,7 @@ func _process(delta): elif Input.is_action_pressed("move_northwest"): move_vec = Vector2i(-1, -1) - # Action inputs (still momentary) + # 3. Action inputs (momentary) if Input.is_action_just_pressed("action_grab"): player.grab_item(player.current_position) elif Input.is_action_just_pressed("action_put"): diff --git a/scripts/managers/settings_manager.gd b/scripts/managers/settings_manager.gd index a1d4e56..2a3dd74 100644 --- a/scripts/managers/settings_manager.gd +++ b/scripts/managers/settings_manager.gd @@ -5,12 +5,24 @@ extends Node const SETTINGS_FILE = "user://game_settings.cfg" +const RESOLUTIONS = [ + Vector2i(1024, 576), + Vector2i(1280, 720), + Vector2i(1366, 768), + Vector2i(1600, 900), + Vector2i(1920, 1080), + Vector2i(2560, 1440) +] + # Default values var settings = { "video": { "fullscreen": true, "vsync": true, - "resolution_idx": 1 + "resolution_idx": 1, + "msaa": 0, # 0: Disabled, 1: 2x, 2: 4x, 3: 8x + "shadow_quality": 2, # 0: Low, 1: Med, 2: High, 3: Ultra + "fps_cap": 2 # 0: Unlimited, 1: 30, 2: 60, 3: 120, 4: 144 }, "audio": { "master_volume": 0.8, @@ -18,15 +30,24 @@ var settings = { "sfx_volume": 0.9 }, "controls": { + "use_controller": false, + # Movement (Keybinds are typically fixed to WASD/Arrows in Input Map, but we show them) + "move_up": KEY_W, + "move_down": KEY_S, + "move_left": KEY_A, + "move_right": KEY_D, + # Actions + "grab": KEY_SPACE, + "put": KEY_R, + "tekton_grab": KEY_G, + # Power-Up Controls "powerup_1": KEY_1, "powerup_2": KEY_2, "powerup_3": KEY_3, "powerup_4": KEY_4, - "grab": KEY_SPACE, - "put": KEY_R, + # Power Bar Controls / Special "attack_mode": KEY_Q, - "spawn_boost": KEY_E, - "tekton_grab": KEY_G + "spawn_boost": KEY_E } } @@ -63,16 +84,59 @@ func apply_all_settings(): func apply_video_settings(): var video = settings.video + if video.fullscreen: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) else: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) + # Apply resolution size when windowed + var res_idx = video.resolution_idx + if res_idx >= 0 and res_idx < RESOLUTIONS.size(): + var target_res = RESOLUTIONS[res_idx] + DisplayServer.window_set_size(target_res) + # Center window after resize + var screen = DisplayServer.window_get_current_screen() + var screen_rect = DisplayServer.screen_get_usable_rect(screen) + var window_size = DisplayServer.window_get_size() + DisplayServer.window_set_position(screen_rect.position + (screen_rect.size - window_size) / 2) + if video.vsync: DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED) else: DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED) + # Apply MSAA + var viewport = get_viewport() + match video.msaa: + 0: viewport.msaa_3d = Viewport.MSAA_DISABLED + 1: viewport.msaa_3d = Viewport.MSAA_2X + 2: viewport.msaa_3d = Viewport.MSAA_4X + 3: viewport.msaa_3d = Viewport.MSAA_8X + + # Apply FPS Cap + match video.fps_cap: + 0: Engine.max_fps = 0 + 1: Engine.max_fps = 30 + 2: Engine.max_fps = 60 + 3: Engine.max_fps = 120 + 4: Engine.max_fps = 144 + + # Apply Shadow Quality (Simplified for Forward+) + match video.shadow_quality: + 0: # Low + RenderingServer.directional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_LOW) + RenderingServer.positional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_LOW) + 1: # Medium + RenderingServer.directional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_MEDIUM) + RenderingServer.positional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_MEDIUM) + 2: # High + RenderingServer.directional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_HIGH) + RenderingServer.positional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_HIGH) + 3: # Ultra + RenderingServer.directional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_ULTRA) + RenderingServer.positional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_ULTRA) + func apply_audio_settings(): var audio = settings.audio set_bus_volume("Master", audio.master_volume) diff --git a/scripts/ui/settings_menu.gd b/scripts/ui/settings_menu.gd index f47b915..8e4218b 100644 --- a/scripts/ui/settings_menu.gd +++ b/scripts/ui/settings_menu.gd @@ -8,6 +8,10 @@ extends CanvasLayer # Video Controls @onready var fullscreen_toggle = %FullscreenToggle @onready var vsync_toggle = %VSyncToggle +@onready var resolution_btn = %ResolutionBtn +@onready var msaa_btn = %MSAABtn +@onready var shadow_btn = %ShadowBtn +@onready var fps_btn = %FPSCapBtn # Audio Controls @onready var master_slider = %MasterSlider @@ -15,6 +19,7 @@ extends CanvasLayer @onready var sfx_slider = %SFXSlider # Controls (Keybinds) +@onready var use_controller_btn = %UseControllerBtn @onready var SettingsManager = get_node_or_null("/root/SettingsManager") var listening_action: String = "" # Set when waiting for a keypress @@ -37,31 +42,76 @@ func _load_ui_values(): fullscreen_toggle.button_pressed = s.video.fullscreen vsync_toggle.button_pressed = s.video.vsync + # Populate Resolution dropdown if not already populated + if resolution_btn.item_count == 0: + for i in range(SettingsManager.RESOLUTIONS.size()): + var res = SettingsManager.RESOLUTIONS[i] + resolution_btn.add_item("%dx%d" % [res.x, res.y]) + resolution_btn.selected = s.video.resolution_idx + + # MSAA + if msaa_btn.item_count == 0: + msaa_btn.add_item("Disabled") + msaa_btn.add_item("2x") + msaa_btn.add_item("4x") + msaa_btn.add_item("8x") + msaa_btn.selected = s.video.msaa + + # Shadows + if shadow_btn.item_count == 0: + shadow_btn.add_item("Low") + shadow_btn.add_item("Medium") + shadow_btn.add_item("High") + shadow_btn.add_item("Ultra") + shadow_btn.selected = s.video.shadow_quality + + # FPS Cap + if fps_btn.item_count == 0: + fps_btn.add_item("Unlimited") + fps_btn.add_item("30 FPS") + fps_btn.add_item("60 FPS") + fps_btn.add_item("120 FPS") + fps_btn.add_item("144 FPS") + fps_btn.selected = s.video.fps_cap + # Audio master_slider.value = s.audio.master_volume music_slider.value = s.audio.music_volume sfx_slider.value = s.audio.sfx_volume # Controls + use_controller_btn.button_pressed = s.controls.get("use_controller", false) _update_all_key_labels() func _connect_signals(): # Video fullscreen_toggle.toggled.connect(_on_video_setting_changed) vsync_toggle.toggled.connect(_on_video_setting_changed) + resolution_btn.item_selected.connect(_on_resolution_selected) + msaa_btn.item_selected.connect(_on_video_property_changed.bind("msaa")) + shadow_btn.item_selected.connect(_on_video_property_changed.bind("shadow_quality")) + fps_btn.item_selected.connect(_on_video_property_changed.bind("fps_cap")) # Audio master_slider.value_changed.connect(_on_audio_setting_changed.bind("master_volume")) music_slider.value_changed.connect(_on_audio_setting_changed.bind("music_volume")) sfx_slider.value_changed.connect(_on_audio_setting_changed.bind("sfx_volume")) + # Controls + use_controller_btn.toggled.connect(_on_control_setting_changed.bind("use_controller")) + # Close close_button.pressed.connect(func(): visible = false) - # Connect remapping buttons + # Connect remapping buttons (exclude non-keybinds like use_controller) for action_name in SettingsManager.settings.controls.keys(): + if action_name == "use_controller": + continue + var btn = get_node_or_null("%" + action_name.to_pascal_case() + "Btn") if btn: + if btn.pressed.is_connected(_on_remap_button_pressed): + btn.pressed.disconnect(_on_remap_button_pressed) btn.pressed.connect(_on_remap_button_pressed.bind(action_name)) func _on_video_setting_changed(_unused = false): @@ -70,11 +120,25 @@ func _on_video_setting_changed(_unused = false): SettingsManager.save_settings() SettingsManager.apply_video_settings() +func _on_resolution_selected(idx: int): + SettingsManager.settings.video.resolution_idx = idx + SettingsManager.save_settings() + SettingsManager.apply_video_settings() + +func _on_video_property_changed(idx: int, property_name: String): + SettingsManager.settings.video[property_name] = idx + SettingsManager.save_settings() + SettingsManager.apply_video_settings() + func _on_audio_setting_changed(key: String, value: float): SettingsManager.settings.audio[key] = value SettingsManager.save_settings() SettingsManager.apply_audio_settings() +func _on_control_setting_changed(value: bool, key: String): + SettingsManager.settings.controls[key] = value + SettingsManager.save_settings() + func _on_remap_button_pressed(action_name: String): listening_action = action_name var btn = get_node_or_null("%" + action_name.to_pascal_case() + "Btn")