feat: Add new visual effects, player and lobby scenes, and a special tiles manager.

This commit is contained in:
2026-03-17 18:04:57 +08:00
parent efdd8f4969
commit 05d9617f84
22 changed files with 5385 additions and 7 deletions
+52
View File
@@ -153,6 +153,17 @@ var _is_highlighting: bool = false
@onready var character_gatot: Node3D = $Gatot
@onready var character_oldpop: Node3D = $Oldpop
# Skill initiator VFX
@onready var vfx_skill_freeze: AnimatedSprite3D = $skill_freeze
@onready var vfx_skill_ghost: AnimatedSprite3D = $skill_ghost
@onready var vfx_skill_speed: AnimatedSprite3D = $skill_speed
@onready var vfx_skill_wall: AnimatedSprite3D = $skill_wall
# Knock / receiver VFX
@onready var vfx_attack_top: AnimatedSprite3D = $attack_mode_top
@onready var vfx_attack_bot: AnimatedSprite3D = $attack_mode_bot
@onready var vfx_stunned: AnimatedSprite3D = $receiver_skill_stunned
var _selected_character: String = "Masbro"
var selected_character: String:
get: return _selected_character
@@ -500,6 +511,22 @@ func sync_special_animation() -> void:
"""Sync special ability animation across network."""
play_special_animation()
# =============================================================================
# Skill VFX
# =============================================================================
@rpc("any_peer", "call_local", "reliable")
func play_skill_vfx(node_name: String) -> void:
"""Show, play, and auto-hide a skill AnimatedSprite3D by node name.
Called on all peers so everyone sees the initiator's VFX."""
var vfx: AnimatedSprite3D = get_node_or_null(node_name)
if not vfx:
return
vfx.visible = true
vfx.play()
await vfx.animation_finished
vfx.visible = false
# =============================================================================
# Screen Shake
# =============================================================================
@@ -738,6 +765,9 @@ func apply_stagger(duration: float = 1.5):
is_frozen = true
_apply_tint_recursive(self , Color.BLUE) # Visual feedback
# Play knock VFX sequence on the receiver
_play_knock_vfx()
# Set immunity (3 seconds as requested)
immunity_timer = 3.0
@@ -762,6 +792,28 @@ func apply_stagger(duration: float = 1.5):
else:
_apply_tint_recursive(self , Color.WHITE) # Remove tint
func _play_knock_vfx() -> void:
"""Plays the three knock receiver VFX in sequence: top -> bot -> stunned.
Each hides itself once its animation finishes."""
# 1. attack_mode_top
if vfx_attack_top:
vfx_attack_top.visible = true
vfx_attack_top.play()
await vfx_attack_top.animation_finished
vfx_attack_top.visible = false
# 2. attack_mode_bot
if vfx_attack_bot:
vfx_attack_bot.visible = true
vfx_attack_bot.play()
await vfx_attack_bot.animation_finished
vfx_attack_bot.visible = false
# 3. receiver_skill_stunned
if vfx_stunned:
vfx_stunned.visible = true
vfx_stunned.play()
await vfx_stunned.animation_finished
vfx_stunned.visible = false
@rpc("any_peer", "call_local", "reliable")
func sync_stop_freeze(enabled: bool):
# Security: Only allow server (peer 1) or local calls (peer 0)