From 421e8a96f7df9d71b7c6b20192a3a4b30f41e9c7 Mon Sep 17 00:00:00 2001 From: prairie2022 Date: Sat, 18 Jul 2026 02:32:49 +0800 Subject: [PATCH 1/5] fix: some demo issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 倒數 321 的圖層在那些白色的字下 - 遊戲開始前,`EnergyLabel/LimitationLabel` 的位置不對 - demo 端的 Phase --- Scenes/demo.tscn | 53 ++++++++++++++++++++-------------------- Scenes/energy_label.tscn | 3 ++- Scripts/demo_renderer.gd | 2 +- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Scenes/demo.tscn b/Scenes/demo.tscn index 7d96a85a..5cb8d05c 100644 --- a/Scenes/demo.tscn +++ b/Scenes/demo.tscn @@ -99,10 +99,6 @@ viewport_path = NodePath("HigherThanPlayerA") [sub_resource type="ViewportTexture" id="ViewportTexture_high_b"] viewport_path = NodePath("HigherThanPlayerB") -[sub_resource type="FontVariation" id="FontVariation_countdown"] -base_font = ExtResource("4_font") -variation_transform = Transform2D(1, 0.15, 0, 1, 0, 0) - [sub_resource type="LabelSettings" id="LabelSettings_tcdmn"] font = ExtResource("4_font") font_size = 56 @@ -111,6 +107,9 @@ font_size = 56 font = ExtResource("4_font") font_size = 36 +[sub_resource type="FontVariation" id="FontVariation_countdown"] +base_font = ExtResource("4_font") +variation_transform = Transform2D(1, 0.15, 0, 1, 0, 0) [node name="DemoMain" type="Control" unique_id=1296044060] layout_mode = 3 @@ -384,29 +383,6 @@ script = ExtResource("5_high_stage") [node name="HUD" type="CanvasLayer" parent="." unique_id=1320686328] layer = 10 -[node name="PregameCountdown" type="Label" parent="HUD" unique_id=1745412148] -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = -36.0 -offset_top = -214.0 -offset_right = 34.0 -offset_bottom = -77.0 -grow_horizontal = 2 -grow_vertical = 2 -theme_override_colors/font_color = Color(1, 0.7058824, 0.09803922, 1) -theme_override_colors/font_shadow_color = Color(1.0039686, 0.33479407, 0, 0.98039216) -theme_override_colors/font_outline_color = Color(1, 0.7058824, 0.21568628, 1) -theme_override_constants/shadow_offset_x = 6 -theme_override_constants/shadow_offset_y = 4 -theme_override_fonts/font = SubResource("FontVariation_countdown") -theme_override_font_sizes/font_size = 85 -text = "3" -horizontal_alignment = 1 -script = ExtResource("2_countdown") - [node name="TimeLabel" type="Label" parent="HUD" unique_id=985672380] anchors_preset = 5 anchor_left = 0.5 @@ -575,6 +551,29 @@ label_settings = SubResource("LabelSettings_tcdmn") horizontal_alignment = 1 vertical_alignment = 1 +[node name="PregameCountdown" type="Label" parent="HUD" unique_id=1745412148] +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -36.0 +offset_top = -214.0 +offset_right = 34.0 +offset_bottom = -77.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_colors/font_color = Color(1, 0.7058824, 0.09803922, 1) +theme_override_colors/font_shadow_color = Color(1.0039686, 0.33479407, 0, 0.98039216) +theme_override_colors/font_outline_color = Color(1, 0.7058824, 0.21568628, 1) +theme_override_constants/shadow_offset_x = 6 +theme_override_constants/shadow_offset_y = 4 +theme_override_fonts/font = SubResource("FontVariation_countdown") +theme_override_font_sizes/font_size = 85 +text = "3" +horizontal_alignment = 1 +script = ExtResource("2_countdown") + [node name="DemoRenderer" type="Node" parent="." unique_id=295691669 node_paths=PackedStringArray("stage_a", "stage_b", "time_label", "phase_label", "pregame_countdown", "screen_a_energy", "screen_a_health", "screen_b_energy", "screen_b_health", "stage_layer", "high_stage_a", "high_stage_b", "camera_a", "camera_b")] script = ExtResource("1_demo") stage_a = NodePath("../ScreenA/SubViewport/StageA") diff --git a/Scenes/energy_label.tscn b/Scenes/energy_label.tscn index a35c3c25..8c3ff00f 100644 --- a/Scenes/energy_label.tscn +++ b/Scenes/energy_label.tscn @@ -32,7 +32,8 @@ text = "0" label_settings = SubResource("LabelSettings_6srxx") [node name="LimitationLabel" type="Label" parent="." unique_id=369878157] -offset_right = 40.0 +offset_left = 84.0 +offset_right = 124.0 offset_bottom = 23.0 text = "/0" label_settings = SubResource("LabelSettings_46qr4") diff --git a/Scripts/demo_renderer.gd b/Scripts/demo_renderer.gd index 68dabb90..4a0d7af7 100644 --- a/Scripts/demo_renderer.gd +++ b/Scripts/demo_renderer.gd @@ -122,7 +122,7 @@ func _identify_as_demo(nm: Node) -> void: func _on_demo_state_received(combined: Dictionary) -> void: var elapsed: float = combined.get("elapsed_time", 0.0) _update_time_display(elapsed) - _update_phase_display(combined.get("current_phase", 0)) + _update_phase_display(_compute_phase(elapsed)) if not _countdown_triggered and elapsed < 0.0: _countdown_triggered = true From ddbe0ad028010a35d0bc4fa94036e952aa12677e Mon Sep 17 00:00:00 2001 From: prairie2022 Date: Sat, 18 Jul 2026 03:18:16 +0800 Subject: [PATCH 2/5] fix: health icon not changed with skin --- Scenes/demo.tscn | 90 ---------------------------------------- Scripts/demo_renderer.gd | 6 ++- 2 files changed, 5 insertions(+), 91 deletions(-) diff --git a/Scenes/demo.tscn b/Scenes/demo.tscn index 5cb8d05c..db5de05a 100644 --- a/Scenes/demo.tscn +++ b/Scenes/demo.tscn @@ -421,102 +421,12 @@ position = Vector2(91, 112) [node name="ScreenA_Health" type="Node2D" parent="HUD" unique_id=261805975] position = Vector2(340, 112) -[node name="Icon0" type="TextureRect" parent="HUD/ScreenA_Health" unique_id=1452463056] -offset_left = -87.0 -offset_top = -15.0 -offset_right = -57.0 -offset_bottom = 15.0 -texture = ExtResource("6_feather") -expand_mode = 1 -stretch_mode = 5 - -[node name="Icon1" type="TextureRect" parent="HUD/ScreenA_Health" unique_id=1084471247] -offset_left = -51.0 -offset_top = -15.0 -offset_right = -21.0 -offset_bottom = 15.0 -texture = ExtResource("6_feather") -expand_mode = 1 -stretch_mode = 5 - -[node name="Icon2" type="TextureRect" parent="HUD/ScreenA_Health" unique_id=1030381543] -offset_left = -15.0 -offset_top = -15.0 -offset_right = 15.0 -offset_bottom = 15.0 -texture = ExtResource("6_feather") -expand_mode = 1 -stretch_mode = 5 - -[node name="Icon3" type="TextureRect" parent="HUD/ScreenA_Health" unique_id=2131930762] -offset_left = 21.0 -offset_top = -15.0 -offset_right = 51.0 -offset_bottom = 15.0 -texture = ExtResource("6_feather") -expand_mode = 1 -stretch_mode = 5 - -[node name="Icon4" type="TextureRect" parent="HUD/ScreenA_Health" unique_id=21353598] -offset_left = 57.0 -offset_top = -15.0 -offset_right = 87.0 -offset_bottom = 15.0 -texture = ExtResource("6_feather") -expand_mode = 1 -stretch_mode = 5 - [node name="ScreenB_Energy" parent="HUD" unique_id=1762839106 instance=ExtResource("3_energy")] position = Vector2(955, 112) [node name="ScreenB_Health" type="Node2D" parent="HUD" unique_id=1056993462] position = Vector2(812, 112) -[node name="Icon0" type="TextureRect" parent="HUD/ScreenB_Health" unique_id=1352515971] -offset_left = -87.0 -offset_top = -15.0 -offset_right = -57.0 -offset_bottom = 15.0 -texture = ExtResource("6_feather") -expand_mode = 1 -stretch_mode = 5 - -[node name="Icon1" type="TextureRect" parent="HUD/ScreenB_Health" unique_id=359298265] -offset_left = -51.0 -offset_top = -15.0 -offset_right = -21.0 -offset_bottom = 15.0 -texture = ExtResource("6_feather") -expand_mode = 1 -stretch_mode = 5 - -[node name="Icon2" type="TextureRect" parent="HUD/ScreenB_Health" unique_id=1213276918] -offset_left = -15.0 -offset_top = -15.0 -offset_right = 15.0 -offset_bottom = 15.0 -texture = ExtResource("6_feather") -expand_mode = 1 -stretch_mode = 5 - -[node name="Icon3" type="TextureRect" parent="HUD/ScreenB_Health" unique_id=425014722] -offset_left = 21.0 -offset_top = -15.0 -offset_right = 51.0 -offset_bottom = 15.0 -texture = ExtResource("6_feather") -expand_mode = 1 -stretch_mode = 5 - -[node name="Icon4" type="TextureRect" parent="HUD/ScreenB_Health" unique_id=457022701] -offset_left = 57.0 -offset_top = -15.0 -offset_right = 87.0 -offset_bottom = 15.0 -texture = ExtResource("6_feather") -expand_mode = 1 -stretch_mode = 5 - [node name="NameLabelA" type="Label" parent="HUD" unique_id=599978977] anchors_preset = 5 anchor_left = 0.5 diff --git a/Scripts/demo_renderer.gd b/Scripts/demo_renderer.gd index 4a0d7af7..6d61c1f5 100644 --- a/Scripts/demo_renderer.gd +++ b/Scripts/demo_renderer.gd @@ -81,6 +81,7 @@ func _ready() -> void: "prev_player": {}, "proxy": null, "loaded_skin_id": "", + "loaded_health_skin_id": "", "energy_label": screen_a_energy, "energy_value": 0, "health_root": screen_a_health, @@ -97,6 +98,7 @@ func _ready() -> void: "prev_player": {}, "proxy": null, "loaded_skin_id": "", + "loaded_health_skin_id": "", "energy_label": screen_b_energy, "energy_value": 0, "health_root": screen_b_health, @@ -461,7 +463,8 @@ func _update_health_hud(screen: Dictionary, skin_id: String, max_health: int) -> return var need_rebuild: bool = ( - skin_id != screen.get("loaded_skin_id", "") or health_root.get_child_count() != max_health + skin_id != screen.get("loaded_health_skin_id", "") + or health_root.get_child_count() != max_health ) if not need_rebuild: if screen["health_icons"].is_empty(): @@ -469,6 +472,7 @@ func _update_health_hud(screen: Dictionary, skin_id: String, max_health: int) -> if child is TextureRect: screen["health_icons"].append(child) return + screen["loaded_health_skin_id"] = skin_id # Clear old icons for icon in screen["health_icons"]: From 1ce1ba7b58d10461368617face21e55a2be6afea Mon Sep 17 00:00:00 2001 From: prairie2022 Date: Sat, 18 Jul 2026 05:16:08 +0800 Subject: [PATCH 3/5] feat: `Total Energy Spent` on result screen Before this commit, `Total Energy Spent` shown on result screen are always 0. --- Scripts/game_manager.gd | 1 - Scripts/network/state_serializer.gd | 2 +- Scripts/result_screen.gd | 8 ++++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Scripts/game_manager.gd b/Scripts/game_manager.gd index acff99f9..6f69c2c0 100644 --- a/Scripts/game_manager.gd +++ b/Scripts/game_manager.gd @@ -489,7 +489,6 @@ func finish_game(state: int = 0, authoritative_stats: Dictionary = {}) -> void: "distance_traveled": player.distance_traveled, "survival_time": survival_time, "remaining_health": health, - "trap_count": authoritative_stats.get("trap_count", 0), }, state ) diff --git a/Scripts/network/state_serializer.gd b/Scripts/network/state_serializer.gd index 4dffc0ff..d073ed33 100644 --- a/Scripts/network/state_serializer.gd +++ b/Scripts/network/state_serializer.gd @@ -78,7 +78,7 @@ func _serialize_player(p: Node) -> Dictionary: var energy := 0 var ball_count := 0 - var total_energy_spent := 0 + var total_energy_spent = game_manager.total_energy_spent if game_manager else 0 if game_manager: energy = game_manager.get("energy_amount") if "energy_amount" in game_manager else 0 ball_count = ( diff --git a/Scripts/result_screen.gd b/Scripts/result_screen.gd index aabb1129..24206faf 100644 --- a/Scripts/result_screen.gd +++ b/Scripts/result_screen.gd @@ -42,10 +42,10 @@ func show_results(results: Dictionary, state: int) -> void: ] var opponent_energy_balls := int(results.get("opponent_energy_balls", -1)) - if opponent_energy_balls >= 0: - # This row is multiplayer-only; single-player leaves opponent_energy_balls at -1. - names.insert(3, "Opponent Energy Balls") - values.insert(3, str(opponent_energy_balls)) + # if opponent_energy_balls >= 0: + # # This row is multiplayer-only; single-player leaves opponent_energy_balls at -1. + # names.insert(3, "Opponent Energy Balls") + # values.insert(3, str(opponent_energy_balls)) if state == 0: title_label.text = "RESULT" From f07151349fecde9081cac5bb1eb26de670bca026 Mon Sep 17 00:00:00 2001 From: prairie2022 Date: Sat, 18 Jul 2026 06:10:14 +0800 Subject: [PATCH 4/5] feat: set bgm by phase --- Scripts/audio.gd | 2 ++ Scripts/demo_renderer.gd | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Scripts/audio.gd b/Scripts/audio.gd index 07fb44c6..a86eac3a 100644 --- a/Scripts/audio.gd +++ b/Scripts/audio.gd @@ -213,6 +213,8 @@ func set_phase_bgm(phase: int) -> void: set_bgm(BGM.GAMEPLAY_PHASE_4) 5: set_bgm(BGM.GAMEPLAY_PHASE_5) + _: + set_bgm(BGM.NONE) func _play_random_bgm_track(player: AudioStreamPlayer) -> void: diff --git a/Scripts/demo_renderer.gd b/Scripts/demo_renderer.gd index 6d61c1f5..b3c4367e 100644 --- a/Scripts/demo_renderer.gd +++ b/Scripts/demo_renderer.gd @@ -31,6 +31,7 @@ var _player_a: Node2D var _player_b: Node2D var _screens: Array = [] var _countdown_triggered: bool = false +var _current_phase: int = -2 var _phase_duration: Array = [] var _max_phase: int = 0 @@ -124,7 +125,10 @@ func _identify_as_demo(nm: Node) -> void: func _on_demo_state_received(combined: Dictionary) -> void: var elapsed: float = combined.get("elapsed_time", 0.0) _update_time_display(elapsed) - _update_phase_display(_compute_phase(elapsed)) + var new_phase: int = _compute_phase(elapsed) + if new_phase != _current_phase: + _current_phase = new_phase + _update_phase_display(_current_phase) if not _countdown_triggered and elapsed < 0.0: _countdown_triggered = true @@ -194,9 +198,12 @@ func _update_phase_display(phase: int) -> void: if not phase_label: return phase_label.text = "Phase %d" % phase + Audio.set_phase_bgm(phase) func _compute_phase(time: float) -> int: + if time <= 0: + return -1 for i in range(_max_phase): if time >= _phase_duration[i]: time -= _phase_duration[i] From 374fbde72ee13ddad0f0dbaed61fd990ffe5f973 Mon Sep 17 00:00:00 2001 From: prairie2022 Date: Sat, 18 Jul 2026 06:39:07 +0800 Subject: [PATCH 5/5] feat: add sfx synchronization --- Scenes/demo.tscn | 1 - Scripts/audio.gd | 4 ++++ Scripts/demo_renderer.gd | 7 +++++++ Scripts/demo_result_screen.gd | 1 + Scripts/network/state_serializer.gd | 3 +++ 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Scenes/demo.tscn b/Scenes/demo.tscn index db5de05a..a2073f7a 100644 --- a/Scenes/demo.tscn +++ b/Scenes/demo.tscn @@ -11,7 +11,6 @@ [ext_resource type="Texture2D" uid="uid://dle4xt8upfg42" path="res://Shapes/Square.svg" id="4_qdju7"] [ext_resource type="Script" uid="uid://d2y578q176xkm" path="res://Scripts/high_stage.gd" id="5_high_stage"] [ext_resource type="PackedScene" uid="uid://dao1hqwdldnlw" path="res://Scenes/demo_result_screen.tscn" id="6_a1i4p"] -[ext_resource type="Texture2D" uid="uid://f5ertr28h6kq" path="res://Shapes/feather.svg" id="6_feather"] [ext_resource type="Script" uid="uid://cxd17lrphypsv" path="res://Scripts/game_camera.gd" id="7_camera"] [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_f2jw5"] diff --git a/Scripts/audio.gd b/Scripts/audio.gd index a86eac3a..5b8a9909 100644 --- a/Scripts/audio.gd +++ b/Scripts/audio.gd @@ -66,6 +66,9 @@ enum BGM { @export var sfx_pool_size := 8 @export var bgm_fade_out_time := 0.3125 +# sfx queue +var queued_sfx: Array[int] = [] + # the audio collection var _sfx_streams: Dictionary = {} var _bgm_playlists: Dictionary = {} @@ -131,6 +134,7 @@ func set_bgm(bgm: BGM) -> void: func play_sfx(sfx: SFX) -> AudioStreamPlayer: + queued_sfx.append(sfx as int) var stream := _sfx_streams.get(SFX.find_key(sfx)) as AudioStream if stream == null: return diff --git a/Scripts/demo_renderer.gd b/Scripts/demo_renderer.gd index b3c4367e..75277ae8 100644 --- a/Scripts/demo_renderer.gd +++ b/Scripts/demo_renderer.gd @@ -37,6 +37,7 @@ var _max_phase: int = 0 func _ready() -> void: + Audio.process_mode = Node.PROCESS_MODE_ALWAYS var game_data := GameData.new() _phase_duration = game_data.data.get("game_manager", {}).get("phase_duration", []) _max_phase = game_data.data.get("game_manager", {}).get("max_phase", _phase_duration.size()) @@ -133,6 +134,7 @@ func _on_demo_state_received(combined: Dictionary) -> void: if not _countdown_triggered and elapsed < 0.0: _countdown_triggered = true if pregame_countdown and pregame_countdown.has_method("play_countdown"): + Audio.play_sfx(Audio.SFX.PREGAME_COUNTDOWN) pregame_countdown.play_countdown() var screens: Array = combined.get("screens", []) @@ -180,6 +182,11 @@ func _apply_screen(screen: Dictionary, screen_data: Dictionary) -> void: _update_energy_hud(screen, energy, max_energy) _update_health_hud(screen, skin_id, max_health) _refresh_health_display(screen, health) + var queued_sfx = screen_data.get("queued_sfx", []) + for sfx_id in queued_sfx: + var sfx: Audio.SFX = sfx_id as Audio.SFX + if sfx != Audio.SFX.PREGAME_COUNTDOWN: + Audio.play_sfx(sfx) ## Recursively disables game logic callbacks on [param node] and its children. diff --git a/Scripts/demo_result_screen.gd b/Scripts/demo_result_screen.gd index 443d7156..a9434e48 100644 --- a/Scripts/demo_result_screen.gd +++ b/Scripts/demo_result_screen.gd @@ -173,6 +173,7 @@ func show_demo_results( health_icon.modulate.a = 1.0 health_icon_b.modulate.a = 1.0 + Audio.stop_all_sfx() Audio.set_bgm(Audio.BGM.RESULT_SCREEN) _fade_in(3.0) diff --git a/Scripts/network/state_serializer.gd b/Scripts/network/state_serializer.gd index d073ed33..008e0e98 100644 --- a/Scripts/network/state_serializer.gd +++ b/Scripts/network/state_serializer.gd @@ -61,6 +61,8 @@ func _collect_state() -> Dictionary: var player_node: Node = ( game_manager.player if game_manager and "player" in game_manager else null ) + var queued_sfx := Audio.queued_sfx if Audio else [] + Audio.queued_sfx = [] return { "peer_id": multiplayer.get_unique_id(), "tick": Engine.get_physics_frames(), @@ -68,6 +70,7 @@ func _collect_state() -> Dictionary: "max_energy_cap": _collect_max_energy_cap(), "traps": _serialize_traps(), "energy_balls": _serialize_energy_balls(), + "queued_sfx": queued_sfx }