feat: gameplay settings screen (deadzone + sensitivity)

This commit is contained in:
2026-03-19 03:47:15 +01:00
parent e647cd7b29
commit 38c86f1a67
5 changed files with 208 additions and 8 deletions

View File

@@ -0,0 +1,97 @@
[gd_scene load_steps=3 format=3 uid="uid://gameplay_settings_scene"]
[ext_resource type="Script" uid="uid://gameplay_settings_script" path="res://scripts/UI/GameplaySettings.cs" id="1_gameplay"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gameplay"]
bg_color = Color(0, 0, 0, 1)
[node name="Gameplay Settings" type="Control" node_paths=PackedStringArray("DeadzoneSlider", "DeadzoneValueLabel", "SensitivitySlider", "SensitivityValueLabel", "GameplaySettingsControl")]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 6
size_flags_vertical = 6
script = ExtResource("1_gameplay")
DeadzoneSlider = NodePath("PanelContainer/MarginContainer/VBoxContainer/Deadzone/HSlider")
DeadzoneValueLabel = NodePath("PanelContainer/MarginContainer/VBoxContainer/Deadzone/HBoxContainer/DeadzoneValueLabel")
SensitivitySlider = NodePath("PanelContainer/MarginContainer/VBoxContainer/Sensitivity/HSlider")
SensitivityValueLabel = NodePath("PanelContainer/MarginContainer/VBoxContainer/Sensitivity/HBoxContainer/SensitivityValueLabel")
GameplaySettingsControl = NodePath(".")
[node name="PanelContainer" type="PanelContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_gameplay")
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"]
layout_mode = 2
theme_override_constants/margin_left = 8
theme_override_constants/margin_top = 8
theme_override_constants/margin_right = 8
theme_override_constants/margin_bottom = 8
[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"]
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
[node name="Gameplay" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "GAMEPLAY"
horizontal_alignment = 1
vertical_alignment = 1
uppercase = true
[node name="Spacer" type="Control" parent="PanelContainer/MarginContainer/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
size_flags_vertical = 3
[node name="Deadzone" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 4
[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/Deadzone"]
layout_mode = 2
[node name="DeadzoneLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/Deadzone/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "GAMEPAD_DEADZONE"
[node name="DeadzoneValueLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/Deadzone/HBoxContainer"]
layout_mode = 2
text = "0.20"
[node name="HSlider" type="HSlider" parent="PanelContainer/MarginContainer/VBoxContainer/Deadzone"]
custom_minimum_size = Vector2(64, 0)
layout_mode = 2
value = 0.2
[node name="Sensitivity" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 4
[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/Sensitivity"]
layout_mode = 2
[node name="SensitivityLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/Sensitivity/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "GAMEPAD_SENSITIVITY"
[node name="SensitivityValueLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/Sensitivity/HBoxContainer"]
layout_mode = 2
text = "1.00"
[node name="HSlider" type="HSlider" parent="PanelContainer/MarginContainer/VBoxContainer/Sensitivity"]
custom_minimum_size = Vector2(64, 0)
layout_mode = 2
value = 1.0

View File

@@ -68,7 +68,6 @@ flat = true
[node name="Gameplay Settings Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"] [node name="Gameplay Settings Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
layout_mode = 2 layout_mode = 2
disabled = true
text = "GAMEPLAY_BUTTON" text = "GAMEPLAY_BUTTON"
flat = true flat = true

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=7 format=3 uid="uid://cl00e2ocomk3m"] [gd_scene load_steps=8 format=3 uid="uid://cl00e2ocomk3m"]
[ext_resource type="PackedScene" uid="uid://8b6ol5sssbgo" path="res://objects/ui/main_menu.tscn" id="1_ekxnf"] [ext_resource type="PackedScene" uid="uid://8b6ol5sssbgo" path="res://objects/ui/main_menu.tscn" id="1_ekxnf"]
[ext_resource type="PackedScene" uid="uid://y0ae6e7t70fj" path="res://objects/ui/settings_menu.tscn" id="2_bqqt6"] [ext_resource type="PackedScene" uid="uid://y0ae6e7t70fj" path="res://objects/ui/settings_menu.tscn" id="2_bqqt6"]
@@ -6,6 +6,7 @@
[ext_resource type="PackedScene" uid="uid://b5fx1vdfky307" path="res://objects/ui/audio_settings.tscn" id="4_8ln24"] [ext_resource type="PackedScene" uid="uid://b5fx1vdfky307" path="res://objects/ui/audio_settings.tscn" id="4_8ln24"]
[ext_resource type="PackedScene" uid="uid://cvfsbiy5ggrpg" path="res://objects/ui/input_settings.tscn" id="5_rtw2f"] [ext_resource type="PackedScene" uid="uid://cvfsbiy5ggrpg" path="res://objects/ui/input_settings.tscn" id="5_rtw2f"]
[ext_resource type="PackedScene" uid="uid://display_settings_scene" path="res://objects/ui/display_settings.tscn" id="6_dispset"] [ext_resource type="PackedScene" uid="uid://display_settings_scene" path="res://objects/ui/display_settings.tscn" id="6_dispset"]
[ext_resource type="PackedScene" uid="uid://gameplay_settings_scene" path="res://objects/ui/gameplay_settings.tscn" id="7_gameplay"]
[node name="Main menu" type="CanvasLayer"] [node name="Main menu" type="CanvasLayer"]
@@ -29,11 +30,8 @@ visible = false
[node name="Input Settings" parent="." instance=ExtResource("5_rtw2f")] [node name="Input Settings" parent="." instance=ExtResource("5_rtw2f")]
visible = false visible = false
[node name="Gameplay Settings" type="Control" parent="."] [node name="Gameplay Settings" parent="." instance=ExtResource("7_gameplay")]
layout_mode = 3 visible = false
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
[node name="Display Settings" parent="." instance=ExtResource("6_dispset")] [node name="Display Settings" parent="." instance=ExtResource("6_dispset")]
visible = false visible = false

View File

@@ -0,0 +1,101 @@
using Godot;
using Mr.BrickAdventures.Autoloads;
namespace Mr.BrickAdventures.scripts.UI;
public partial class GameplaySettings : Control
{
[Export] public HSlider DeadzoneSlider { get; set; }
[Export] public Label DeadzoneValueLabel { get; set; }
[Export] public HSlider SensitivitySlider { get; set; }
[Export] public Label SensitivityValueLabel { get; set; }
[Export] public Control GameplaySettingsControl { get; set; }
private UIManager UIManager => UIManager.Instance;
public override void _Ready()
{
DeadzoneSlider.FocusMode = Control.FocusModeEnum.All;
SensitivitySlider.FocusMode = Control.FocusModeEnum.All;
DeadzoneSlider.MinValue = 0.05;
DeadzoneSlider.MaxValue = 0.5;
DeadzoneSlider.Step = 0.05;
DeadzoneSlider.Value = 0.2;
SensitivitySlider.MinValue = 0.5;
SensitivitySlider.MaxValue = 2.0;
SensitivitySlider.Step = 0.1;
SensitivitySlider.Value = 1.0;
LoadSettings();
DeadzoneSlider.ValueChanged += OnDeadzoneChanged;
SensitivitySlider.ValueChanged += OnSensitivityChanged;
if (InputDeviceManager.Instance != null)
InputDeviceManager.Instance.DeviceChanged += OnDeviceChanged;
GameplaySettingsControl.VisibilityChanged += OnVisibilityChanged;
}
public override void _ExitTree()
{
if (InputDeviceManager.Instance != null)
InputDeviceManager.Instance.DeviceChanged -= OnDeviceChanged;
GameplaySettingsControl.VisibilityChanged -= OnVisibilityChanged;
SaveSettings();
}
public override void _UnhandledInput(InputEvent @event)
{
if (!@event.IsActionReleased("ui_cancel")) return;
if (!UIManager.IsScreenOnTop(GameplaySettingsControl)) return;
SaveSettings();
UIManager.PopScreen();
}
private void OnVisibilityChanged()
{
if (GameplaySettingsControl.IsVisibleInTree() && InputDeviceManager.Instance?.IsPointerless == true)
GrabFirstFocus();
}
private void OnDeviceChanged(int device)
{
var d = (InputDeviceManager.InputDevice)device;
if (d != InputDeviceManager.InputDevice.Mouse && GameplaySettingsControl.IsVisibleInTree())
GrabFirstFocus();
}
private void GrabFirstFocus() => DeadzoneSlider.GrabFocus();
private void OnDeadzoneChanged(double value)
{
SettingsManager.Instance.GamepadDeadzone = (float)value;
foreach (var action in new[] { "left", "right", "up", "down" })
{
if (InputMap.HasAction(action))
InputMap.ActionSetDeadzone(action, (float)value);
}
DeadzoneValueLabel.Text = $"{value:F2}";
SaveSettings();
}
private void OnSensitivityChanged(double value)
{
SettingsManager.Instance.GamepadSensitivity = (float)value;
SensitivityValueLabel.Text = $"{value:F2}";
SaveSettings();
}
private void LoadSettings()
{
DeadzoneSlider.Value = SettingsManager.Instance.GamepadDeadzone;
SensitivitySlider.Value = SettingsManager.Instance.GamepadSensitivity;
DeadzoneValueLabel.Text = $"{SettingsManager.Instance.GamepadDeadzone:F2}";
SensitivityValueLabel.Text = $"{SettingsManager.Instance.GamepadSensitivity:F2}";
}
private void SaveSettings() => SettingsManager.Instance.SaveGameplaySettings();
}

View File

@@ -1,4 +1,5 @@
using Godot; using Godot;
using Mr.BrickAdventures.Autoloads;
namespace Mr.BrickAdventures.scripts.components; namespace Mr.BrickAdventures.scripts.components;
@@ -15,7 +16,11 @@ public partial class PlayerInputHandler : Node
public override void _PhysicsProcess(double delta) public override void _PhysicsProcess(double delta)
{ {
MoveDirection = Input.GetVector("left", "right", "up", "down"); var rawInput = Input.GetVector("left", "right", "up", "down");
var sensitivity = SettingsManager.Instance?.GamepadSensitivity ?? 1.0f;
MoveDirection = rawInput.Length() > 0
? rawInput.Normalized() * Mathf.Min(rawInput.Length() * sensitivity, 1.0f)
: Vector2.Zero;
JumpPressed = Input.IsActionJustPressed("jump"); JumpPressed = Input.IsActionJustPressed("jump");
JumpReleased = Input.IsActionJustReleased("jump"); JumpReleased = Input.IsActionJustReleased("jump");