feat: Implement the core Stop 'n' Go game mechanic, including its manager, main scene, and associated animation assets.

This commit is contained in:
Yogi Wiguna
2026-03-24 17:50:22 +08:00
parent fc40a00fc2
commit 7ca63fea00
5 changed files with 143 additions and 1485 deletions
+26 -15
View File
@@ -65,13 +65,6 @@ func _setup_hud():
hud_layer.visible = false
add_child(hud_layer)
# Full-screen red tint overlay (below everything else in this layer, but above game)
red_tint_overlay = ColorRect.new()
red_tint_overlay.color = Color(1.0, 0.0, 0.0, 0.25) # Transparent red
red_tint_overlay.set_anchors_preset(Control.PRESET_FULL_RECT) # Cover whole screen
red_tint_overlay.visible = false # Hidden initially
hud_layer.add_child(red_tint_overlay)
# New container for bottom-mid label
var bottom_container = CenterContainer.new()
bottom_container.set_anchors_preset(Control.PRESET_CENTER_BOTTOM)
@@ -100,8 +93,8 @@ func _process(delta):
if multiplayer.is_server():
if current_phase == Phase.GO:
# Spawn all 3 safe zones at once, 3 seconds before STOP
if phase_timer <= 3.0 and spawned_safe_zones == 0:
# Spawn all 3 safe zones at once, 6 seconds before STOP
if phase_timer <= 6.0 and spawned_safe_zones == 0:
print("[StopNGo] GO phase ending soon. Spawning 3 safe zones...")
for i in range(3):
_spawn_dynamic_safe_zone()
@@ -124,10 +117,6 @@ func _on_goal_count_updated(_peer_id: int, _count: int):
var _has_notified_mission_complete: bool = false
func _update_hud_visuals():
# Toggle Red Screen Tint
if red_tint_overlay:
red_tint_overlay.visible = (current_phase == Phase.STOP)
var my_id = multiplayer.get_unique_id()
if mission_label:
var main = get_node_or_null("/root/Main")
@@ -196,9 +185,9 @@ func _update_stop_timer_visuals():
stop_timer_node.visible = true
if current_phase == Phase.GO:
# GO Phase: All dim unless in last 3 seconds
# GO Phase: All dim unless in last 6 seconds (lights up 6, 4, 2s)
for i in range(stop_segments.size()):
var threshold = 3.0 - i
var threshold = 6.0 - (i * 2.0)
if phase_timer <= threshold:
stop_segments[i].add_theme_stylebox_override("panel", lit_style)
else:
@@ -275,6 +264,15 @@ func sync_phase(phase_name: String, duration: float):
activate_client_side()
current_phase = Phase.GO if phase_name == "GO" else Phase.STOP
phase_timer = duration
# Trigger Phase Animations
var main = get_node_or_null("/root/Main")
if main and main.get("vfx_manager"):
if phase_name == "STOP":
if main.vfx_manager.has_method("play_stop_phase"):
main.vfx_manager.play_stop_phase()
elif main.vfx_manager.get("animation_player"):
main.vfx_manager.animation_player.play("stop-phase")
func _setup_arena():
var gridmap = get_parent().get_node_or_null("EnhancedGridMap")
@@ -599,6 +597,19 @@ func _spawn_dynamic_safe_zone():
gridmap.set_cell_item(Vector3i(px, 2, pz), TILE_SAFE)
if can_rpc() and main:
main.rpc("sync_grid_item", px, 2, pz, TILE_SAFE)
# Trigger safe zone appear visual effects on all clients
if can_rpc():
rpc("sync_safe_zone_vfx")
@rpc("authority", "call_local", "reliable")
func sync_safe_zone_vfx():
var main = get_node_or_null("/root/Main")
if main and main.get("vfx_manager"):
if main.vfx_manager.has_method("play_safe_zone_appear"):
main.vfx_manager.play_safe_zone_appear()
elif main.vfx_manager.get("animation_player"):
main.vfx_manager.animation_player.play("safe-zone-appear")
func _is_valid_safe_zone_area(gridmap: Node, start_x: int, start_z: int, width: int, height: int) -> bool:
# Avoid bounds or start/finish cols