From 8df14d82e1e945d0fd10ce46bb7feed19fdac2e9 Mon Sep 17 00:00:00 2001 From: Anurag Singh Date: Mon, 26 Jan 2026 21:50:35 +0530 Subject: [PATCH 1/4] Fix: Prevent game crash on sink double-click --- Scripts/SinkClick.gd | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Scripts/SinkClick.gd b/Scripts/SinkClick.gd index 6e5204a..660267a 100644 --- a/Scripts/SinkClick.gd +++ b/Scripts/SinkClick.gd @@ -10,6 +10,11 @@ func on_click(): transfer_box() func transfer_box(): + # SAFETY CHECK: + if ConveyerController.conveyerInd >= ConveyerController.conveyer.size(): + print("No more conveyors available! Cannot send.") + return + print("sending") ConveyerController.create_conveyor() #draw_line(ConveyerController.selected.get_global_position(), get_global_position(), Color.GREEN) From 33b57a183469b3465294b9b52ca13671e9c0d712 Mon Sep 17 00:00:00 2001 From: Anurag Singh Date: Thu, 29 Jan 2026 10:42:44 +0530 Subject: [PATCH 2/4] Fix: Allow unlimited connections in MultiSink + resolve scene transition bug - Added dynamic conveyor creation for MultiSink level (3+ conveyors) - Maintained safety check for BasicEventFlow to prevent crash - Fixed level.gd to initialize before scene change (not after) - Resolves issue where MultiSink failed during full game playthrough - Addresses maintainer feedback about connection limits Fixes #55 --- Scripts/ConveyerController.gd | 26 +++++++++++++++++++++++--- Scripts/SinkClick.gd | 5 ----- Scripts/level.gd | 3 ++- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Scripts/ConveyerController.gd b/Scripts/ConveyerController.gd index abec8da..e32404d 100644 --- a/Scripts/ConveyerController.gd +++ b/Scripts/ConveyerController.gd @@ -11,12 +11,12 @@ var can_send = false var started = false func initialise(): - self.selected + self.selected = null self.events = [] self.destination = [] self.conveyer = [] self.conveyerInd = 0 - self.dragging + self.dragging = null self.sendingEnd = false self.can_send = false self.started = false @@ -26,7 +26,7 @@ func setup(conveyer) -> void: self.can_send = false self.sendingEnd = false self.started = false - self.events = [] + # DON'T clear events here boxes add themselves in _ready() # Called when the node enters the scene tree for the first time. func _ready() -> void: @@ -40,6 +40,26 @@ func _process(delta: float) -> void: pass func create_conveyor(): + # SAFETY CHECK for BasicEventFlow (1 conveyor scene) + # Allow dynamic creation for MultiSink (3+ conveyor scene) + if conveyerInd >= conveyer.size(): + if conveyer.size() == 0: + print("ERROR: No conveyors available!") + return + + # Only allow dynamic creation if we have 3+ conveyors (MultiSink level) + if conveyer.size() >= 3: + # MultiSink create more conveyors dynamically + var new_conveyor = conveyer[0].duplicate() + get_tree().current_scene.add_child(new_conveyor) + new_conveyor.z_index = -1 + conveyer.append(new_conveyor) + print("Created new conveyor, total: ", conveyer.size()) + else: + # BasicEventFlow stop here to prevent crash + print("No more conveyors available (max ", conveyer.size(), ")") + return + conveyer[conveyerInd].set_point_position(0, selected.get_position()) conveyer[conveyerInd].set_point_position(1, destination[conveyerInd]) conveyerInd+=1 diff --git a/Scripts/SinkClick.gd b/Scripts/SinkClick.gd index 660267a..6e5204a 100644 --- a/Scripts/SinkClick.gd +++ b/Scripts/SinkClick.gd @@ -10,11 +10,6 @@ func on_click(): transfer_box() func transfer_box(): - # SAFETY CHECK: - if ConveyerController.conveyerInd >= ConveyerController.conveyer.size(): - print("No more conveyors available! Cannot send.") - return - print("sending") ConveyerController.create_conveyor() #draw_line(ConveyerController.selected.get_global_position(), get_global_position(), Color.GREEN) diff --git a/Scripts/level.gd b/Scripts/level.gd index 19b15b6..d453ab2 100644 --- a/Scripts/level.gd +++ b/Scripts/level.gd @@ -38,9 +38,10 @@ func next_level(): message_display.visible = false levelind+=1 if levelind!=levels.size(): + # CRITICAL FIXInitialize BEFORE changing scene, not after! + ConveyerController.initialise() var next_level_path="res://Scenes/"+levels[levelind]+".tscn" get_tree().change_scene_to_file(next_level_path) - ConveyerController.initialise() else: print("End of Levels.") get_tree().change_scene_to_file("res://Scenes/end_of_all_levels.tscn") From 1aeeaaa144cba8f400e69a85b13c105f63c020c5 Mon Sep 17 00:00:00 2001 From: Anurag Singh Date: Fri, 30 Jan 2026 21:34:08 +0530 Subject: [PATCH 3/4] Add sound effects integration for all game events - Created AudioManager singleton for centralized audio control - Added looping construction sound with audio ducking - Added click sounds for source and destination selection - Added poof sound when events are filtered out - Added success/fail sounds for level completion - Integrated existing sound assets from SoundEffects folder Fixes #5 --- Scripts/AudioManager.gd | 148 ++++++++++++++++++++++++++++++++++ Scripts/ConveyerController.gd | 1 + Scripts/SinkClick.gd | 1 + Scripts/draggable_filter.gd | 1 + Scripts/event_box.gd | 1 + Scripts/level.gd | 2 + project.godot | 1 + 7 files changed, 155 insertions(+) create mode 100644 Scripts/AudioManager.gd diff --git a/Scripts/AudioManager.gd b/Scripts/AudioManager.gd new file mode 100644 index 0000000..f06718b --- /dev/null +++ b/Scripts/AudioManager.gd @@ -0,0 +1,148 @@ +extends Node + +# Audio players for different sound effects +var click_start_player: AudioStreamPlayer +var click_end_player: AudioStreamPlayer +var construction_player: AudioStreamPlayer # Loops continuously! +var poof_player: AudioStreamPlayer +var level_clear_player: AudioStreamPlayer +var level_fail_player: AudioStreamPlayer + +# Sound enabled flag +var sound_enabled = true + +# Volume settings +var construction_normal_volume = -10 +var construction_ducked_volume = -20 +var is_construction_playing = false + +func _ready(): + # Create audio players + click_start_player = AudioStreamPlayer.new() + click_end_player = AudioStreamPlayer.new() + construction_player = AudioStreamPlayer.new() + poof_player = AudioStreamPlayer.new() + level_clear_player = AudioStreamPlayer.new() + level_fail_player = AudioStreamPlayer.new() + + # Add them as children + add_child(click_start_player) + add_child(click_end_player) + add_child(construction_player) + add_child(poof_player) + add_child(level_clear_player) + add_child(level_fail_player) + + # Load sound files + click_start_player.stream = load("res://SoundEffects/sfx_click_start.wav") + click_end_player.stream = load("res://SoundEffects/sfx_click_end.wav") + construction_player.stream = load("res://SoundEffects/sfx_construction.wav") + poof_player.stream = load("res://SoundEffects/sfx_poof.wav") + level_clear_player.stream = load("res://SoundEffects/sfx_level_clear.wav") + level_fail_player.stream = load("res://SoundEffects/sfx_level_fail.wav") + + # Set volume levels + click_start_player.volume_db = -5 + click_end_player.volume_db = -5 + construction_player.volume_db = construction_normal_volume + poof_player.volume_db = 0 + level_clear_player.volume_db = 5 + level_fail_player.volume_db = 5 + + print("AudioManager initialized successfully") + +# Start construction sound loop +func start_construction_loop(): + if sound_enabled and not is_construction_playing and construction_player.stream: + print("Starting construction loop...") + is_construction_playing = true + + # Connect to finished signal to loop manually + if not construction_player.finished.is_connected(_on_construction_finished): + construction_player.finished.connect(_on_construction_finished) + + construction_player.volume_db = construction_normal_volume + construction_player.play() + print("Construction sound should be playing now") + +# Manual loop replay when finished +func _on_construction_finished(): + if is_construction_playing: + construction_player.play() + +# Stop construction sound +func stop_construction_loop(): + if is_construction_playing: + print("Stopping construction loop...") + is_construction_playing = false + + # Fade out + var tween = create_tween() + tween.tween_property(construction_player, "volume_db", -80, 0.5) + await tween.finished + + construction_player.stop() + construction_player.volume_db = construction_normal_volume + +# Duck construction sound (make quieter) +func duck_construction(): + if is_construction_playing: + var tween = create_tween() + tween.tween_property(construction_player, "volume_db", construction_ducked_volume, 0.2) + +# Restore construction sound +func restore_construction(): + if is_construction_playing: + var tween = create_tween() + tween.tween_property(construction_player, "volume_db", construction_normal_volume, 0.3) + +# Play sound functions +func play_click_start(): + if sound_enabled and click_start_player.stream: + duck_construction() + click_start_player.play() + await get_tree().create_timer(0.3).timeout + restore_construction() + +func play_click_end(): + if sound_enabled and click_end_player.stream: + duck_construction() + click_end_player.play() + await get_tree().create_timer(0.3).timeout + restore_construction() + +func play_construction(): + print("play_construction() called") + start_construction_loop() + +func play_poof(): + if sound_enabled and poof_player.stream: + duck_construction() + poof_player.play() + await get_tree().create_timer(0.5).timeout + restore_construction() + +func play_level_clear(): + if sound_enabled and level_clear_player.stream: + stop_construction_loop() + level_clear_player.play() + +func play_level_fail(): + if sound_enabled and level_fail_player.stream: + stop_construction_loop() + level_fail_player.play() + +func toggle_sound(): + sound_enabled = !sound_enabled + if not sound_enabled: + stop_construction_loop() + print("Sound enabled: ", sound_enabled) + +func set_volume(db: float): + click_start_player.volume_db = db - 5 + click_end_player.volume_db = db - 5 + construction_normal_volume = db - 10 + construction_ducked_volume = db - 20 + poof_player.volume_db = db + level_clear_player.volume_db = db + 5 + level_fail_player.volume_db = db + 5 diff --git a/Scripts/ConveyerController.gd b/Scripts/ConveyerController.gd index e32404d..cdb5253 100644 --- a/Scripts/ConveyerController.gd +++ b/Scripts/ConveyerController.gd @@ -62,6 +62,7 @@ func create_conveyor(): conveyer[conveyerInd].set_point_position(0, selected.get_position()) conveyer[conveyerInd].set_point_position(1, destination[conveyerInd]) + AudioManager.play_construction() conveyerInd+=1 func send_event(): diff --git a/Scripts/SinkClick.gd b/Scripts/SinkClick.gd index 6e5204a..35de978 100644 --- a/Scripts/SinkClick.gd +++ b/Scripts/SinkClick.gd @@ -6,6 +6,7 @@ func _input_event(viewport, event, shape_idx): func on_click(): print("hey") + AudioManager.play_click_end() ConveyerController.destination.append(get_parent().get_position()) transfer_box() diff --git a/Scripts/draggable_filter.gd b/Scripts/draggable_filter.gd index c0d8bd3..e2a04de 100644 --- a/Scripts/draggable_filter.gd +++ b/Scripts/draggable_filter.gd @@ -36,4 +36,5 @@ func _on_area_entered(area: Area2D) -> void: if area.is_in_group("Box"): if area.get_parent().boxType != filterColor and area.get_parent().sending == true: print("kill it") + AudioManager.play_poof() area.get_parent().queue_free() diff --git a/Scripts/event_box.gd b/Scripts/event_box.gd index 94c0f0a..850d456 100644 --- a/Scripts/event_box.gd +++ b/Scripts/event_box.gd @@ -16,3 +16,4 @@ func _input_event(viewport, event, shape_idx) -> void: func on_click(): print("hi") ConveyerController.selected = self + AudioManager.play_click_start() diff --git a/Scripts/level.gd b/Scripts/level.gd index d453ab2..5565b4c 100644 --- a/Scripts/level.gd +++ b/Scripts/level.gd @@ -33,6 +33,7 @@ func next_level(): message_display.z_index = 999 if nextLevel: print("success") + AudioManager.play_level_clear() message_display.show_message("Success") await message_display.show_message_for_duration(2.0) message_display.visible = false @@ -47,6 +48,7 @@ func next_level(): get_tree().change_scene_to_file("res://Scenes/end_of_all_levels.tscn") else: print("Failed. Try Again") + AudioManager.play_level_fail() message_display.show_message("Failed. Try Again") await message_display.show_message_for_duration(2.0) message_display.visible = false diff --git a/project.godot b/project.godot index d473b09..fdbdc1c 100644 --- a/project.godot +++ b/project.godot @@ -19,6 +19,7 @@ config/icon="res://icon.svg" ConveyerController="*res://Scripts/ConveyerController.gd" Level="*res://Scripts/level.gd" +AudioManager="*res://Scripts/AudioManager.gd" [input] From 7945dc4ceb05bf5a83109f182a0c0e8442b03fda Mon Sep 17 00:00:00 2001 From: Anurag Singh Date: Mon, 2 Feb 2026 08:31:59 +0530 Subject: [PATCH 4/4] Refactor create_conveyor function by removing checks Removed commented-out code for conveyor creation safety checks and streamlined the create_conveyor function. --- Scripts/ConveyerController.gd | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/Scripts/ConveyerController.gd b/Scripts/ConveyerController.gd index cdb5253..e7c6fc0 100644 --- a/Scripts/ConveyerController.gd +++ b/Scripts/ConveyerController.gd @@ -11,12 +11,12 @@ var can_send = false var started = false func initialise(): - self.selected = null + self.selected self.events = [] self.destination = [] self.conveyer = [] self.conveyerInd = 0 - self.dragging = null + self.dragging self.sendingEnd = false self.can_send = false self.started = false @@ -25,8 +25,9 @@ func setup(conveyer) -> void: self.conveyer.append(conveyer) self.can_send = false self.sendingEnd = false + self.events = [] self.started = false - # DON'T clear events here boxes add themselves in _ready() + # Called when the node enters the scene tree for the first time. func _ready() -> void: @@ -40,26 +41,7 @@ func _process(delta: float) -> void: pass func create_conveyor(): - # SAFETY CHECK for BasicEventFlow (1 conveyor scene) - # Allow dynamic creation for MultiSink (3+ conveyor scene) - if conveyerInd >= conveyer.size(): - if conveyer.size() == 0: - print("ERROR: No conveyors available!") - return - - # Only allow dynamic creation if we have 3+ conveyors (MultiSink level) - if conveyer.size() >= 3: - # MultiSink create more conveyors dynamically - var new_conveyor = conveyer[0].duplicate() - get_tree().current_scene.add_child(new_conveyor) - new_conveyor.z_index = -1 - conveyer.append(new_conveyor) - print("Created new conveyor, total: ", conveyer.size()) - else: - # BasicEventFlow stop here to prevent crash - print("No more conveyors available (max ", conveyer.size(), ")") - return - + conveyer[conveyerInd].set_point_position(0, selected.get_position()) conveyer[conveyerInd].set_point_position(1, destination[conveyerInd]) AudioManager.play_construction()