From 5d32f20fc455a6355a01145bb8a98107c930e3ef Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Tue, 12 Aug 2025 13:28:28 +0200 Subject: [PATCH] Add audio settings management and platform movement component --- Autoloads/ConfigFileHandler.cs | 4 +- Mr. Brick Adventures.csproj | 1 + scripts/UI/AudioSettings.cs | 102 ++++++++++++++++++++ scripts/components/platform_movement.gd | 118 ++++++++++++++++++++++++ 4 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 scripts/UI/AudioSettings.cs create mode 100644 scripts/components/platform_movement.gd diff --git a/Autoloads/ConfigFileHandler.cs b/Autoloads/ConfigFileHandler.cs index 5799faf..67acdae 100644 --- a/Autoloads/ConfigFileHandler.cs +++ b/Autoloads/ConfigFileHandler.cs @@ -5,7 +5,9 @@ namespace Mr.BrickAdventures.Autoloads; public partial class ConfigFileHandler : Node { private ConfigFile _settingsConfig = new(); - private const string SettingsPath = "user://settings.ini"; + public const string SettingsPath = "user://settings.ini"; + + public ConfigFile SettingsConfig => _settingsConfig; public override void _Ready() { diff --git a/Mr. Brick Adventures.csproj b/Mr. Brick Adventures.csproj index 3fcf8b5..35922f6 100644 --- a/Mr. Brick Adventures.csproj +++ b/Mr. Brick Adventures.csproj @@ -92,6 +92,7 @@ + diff --git a/scripts/UI/AudioSettings.cs b/scripts/UI/AudioSettings.cs new file mode 100644 index 0000000..0d605b3 --- /dev/null +++ b/scripts/UI/AudioSettings.cs @@ -0,0 +1,102 @@ +using Godot; +using Mr.BrickAdventures.Autoloads; + +namespace Mr.BrickAdventures.scripts.UI; + +public partial class AudioSettings : Node +{ + [Export] public Slider MasterVolumeSlider { get; set; } + [Export] public Slider MusicVolumeSlider { get; set; } + [Export] public Slider SfxVolumeSlider { get; set; } + [Export] public Control AudioSettingsControl { get; set; } + [Export] public float MuteThreshold { get; set; } = -20f; + + private UIManager _uiManager; + private ConfigFileHandler _configFileHandler; + + public override void _Ready() + { + _uiManager = GetNode("/root/UIManager"); + _configFileHandler = GetNode("/root/ConfigFileHandler"); + Initialize(); + MasterVolumeSlider.ValueChanged += OnMasterVolumeChanged; + MusicVolumeSlider.ValueChanged += OnMusicVolumeChanged; + SfxVolumeSlider.ValueChanged += OnSfxVolumeChanged; + } + + public override void _UnhandledInput(InputEvent @event) + { + if (!@event.IsActionReleased("ui_cancel")) return; + if (!_uiManager.IsScreenOnTop(AudioSettingsControl)) return; + + SaveSettings(); + _uiManager.PopScreen(); + } + + private void OnSfxVolumeChanged(double value) + { + AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("sfx"), (float)value); + HandleMute(AudioServer.GetBusIndex("sfx"), (float)value); + } + + private void OnMusicVolumeChanged(double value) + { + AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("music"), (float)value); + HandleMute(AudioServer.GetBusIndex("music"), (float)value); + } + + private void OnMasterVolumeChanged(double value) + { + AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Master"), (float)value); + HandleMute(AudioServer.GetBusIndex("Master"), (float)value); + } + + private void Initialize() + { + var volumeDb = AudioServer.GetBusVolumeDb(AudioServer.GetBusIndex("Master")); + MasterVolumeSlider.Value = volumeDb; + MasterVolumeSlider.MinValue = MuteThreshold; + MasterVolumeSlider.MaxValue = 0f; + + var musicVolumeDb = AudioServer.GetBusVolumeDb(AudioServer.GetBusIndex("music")); + MusicVolumeSlider.Value = musicVolumeDb; + MusicVolumeSlider.MinValue = MuteThreshold; + MusicVolumeSlider.MaxValue = 0f; + + var sfxVolumeDb = AudioServer.GetBusVolumeDb(AudioServer.GetBusIndex("sfx")); + SfxVolumeSlider.Value = sfxVolumeDb; + SfxVolumeSlider.MinValue = MuteThreshold; + SfxVolumeSlider.MaxValue = 0f; + } + + private void HandleMute(int busIndex, float value) + { + AudioServer.SetBusMute(busIndex, value <= MuteThreshold); + } + + private void SaveSettings() + { + var settingsConfig = _configFileHandler.SettingsConfig; + settingsConfig.SetValue("audio_settings", "master_volume", MasterVolumeSlider.Value); + settingsConfig.SetValue("audio_settings", "music_volume", MusicVolumeSlider.Value); + settingsConfig.SetValue("audio_settings", "sfx_volume", SfxVolumeSlider.Value); + settingsConfig.SetValue("audio_settings", "mute_threshold", MuteThreshold); + settingsConfig.Save(ConfigFileHandler.SettingsPath); + } + + private void LoadSettings() + { + var settingsConfig = _configFileHandler.SettingsConfig; + if (!settingsConfig.HasSection("audio_settings")) return; + + var masterVolume = (float)settingsConfig.GetValue("audio_settings", "master_volume", MasterVolumeSlider.Value); + var musicVolume = (float)settingsConfig.GetValue("audio_settings", "music_volume", MusicVolumeSlider.Value); + var sfxVolume = (float)settingsConfig.GetValue("audio_settings", "sfx_volume", SfxVolumeSlider.Value); + var muteThreshold = (float)settingsConfig.GetValue("audio_settings", "mute_threshold", MuteThreshold); + + MasterVolumeSlider.Value = masterVolume; + MusicVolumeSlider.Value = musicVolume; + SfxVolumeSlider.Value = sfxVolume; + MuteThreshold = muteThreshold; + } +} \ No newline at end of file diff --git a/scripts/components/platform_movement.gd b/scripts/components/platform_movement.gd new file mode 100644 index 0000000..38773da --- /dev/null +++ b/scripts/components/platform_movement.gd @@ -0,0 +1,118 @@ +class_name PlatformMovement +extends PlayerMovement + +@export var speed: float = 300.0 +@export var jump_height: float = 100 +@export var jump_time_to_peak: float = 0.5 +@export var jump_time_to_descent: float = 0.4 +@export var coyote_frames: int = 6 +@export var jump_sfx: AudioStreamPlayer2D +@export var rotation_target: Node2D +@export var body: CharacterBody2D + +var gravity = ProjectSettings.get_setting("physics/2d/default_gravity") +var was_last_floor := false +var coyote_mode := false +var coyote_timer: Timer +var last_direction := Vector2.RIGHT + +@onready var jump_velocity: float = ((2.0 * jump_height) / jump_time_to_peak) * -1.0 +@onready var jump_gravity: float = ((-2.0 * jump_height) / (jump_time_to_peak * jump_time_to_peak)) * -1.0 +@onready var fall_gravity: float = ((-2.0 * jump_height) / (jump_time_to_descent * jump_time_to_descent)) * -1.0 + + +func _ready() -> void: + if not body: + return + + coyote_timer = Timer.new() + coyote_timer.one_shot = true + coyote_timer.wait_time = coyote_frames / 60.0 + coyote_timer.timeout.connect(on_coyote_timer_timeout) + add_child(coyote_timer) + + +func _process(_delta: float) -> void: + if not body or not enabled: + return + + if body.velocity.x > 0.0: + rotation_target.rotation = deg_to_rad(-10) + elif body.velocity.x < 0.0: + rotation_target.rotation = deg_to_rad(10) + else: + rotation_target.rotation = 0 + + calculate_jump_vars() + + +func _physics_process(delta) -> void: + if not body or not enabled: + return + + if body.is_on_floor(): + was_last_floor = true + coyote_mode = false # Reset coyote mode when back on the floor + coyote_timer.stop() # Stop timer when grounded + else: + if was_last_floor: # Start coyote timer only once + coyote_mode = true + coyote_timer.start() + was_last_floor = false + + if not body.is_on_floor(): + body.velocity.y += calculate_gravity() * delta + + if Input.is_action_pressed("jump") and (body.is_on_floor() or coyote_mode): + jump() + + if Input.is_action_just_pressed("down"): + body.position.y += 1 + + var direction := Input.get_axis("left", "right") + if direction != 0: + last_direction = handle_direction(direction) + + if direction: + body.velocity.x = direction * speed + else: + body.velocity.x = move_toward(body.velocity.x, 0, speed) + + previous_velocity = body.velocity + body.move_and_slide() + + +func jump() -> void: + if not body: + return + + body.velocity.y = jump_velocity + coyote_mode = false + if jump_sfx: + jump_sfx.play() + + +func calculate_gravity() -> float: + return jump_gravity if body.velocity.y < 0.0 else fall_gravity + + +func on_coyote_timer_timeout() -> void: + coyote_mode = false + + +func handle_direction(input_dir: float) -> Vector2: + if input_dir > 0: + return Vector2.RIGHT + elif input_dir < 0: + return Vector2.LEFT + return last_direction + + +func on_ship_entered() -> void: + rotation_target.rotation = 0 + + +func calculate_jump_vars() -> void: + jump_velocity = ((2.0 * jump_height) / jump_time_to_peak) * -1.0 + jump_gravity = ((-2.0 * jump_height) / (jump_time_to_peak * jump_time_to_peak)) * -1.0 + fall_gravity = ((-2.0 * jump_height) / (jump_time_to_descent * jump_time_to_descent)) * -1.0 \ No newline at end of file