Files
gplan-2/game/presentation/views/board_fx_view.gd
T

132 lines
4.7 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VERTICAL SLICE - NOT FOR PRODUCTION
# 实现 GDD:design/ux/battle.md(D 区演出层——清图金粒喷泉+彩纸 3–5s 占位、Boss 紫赤影子爬棋盘
# 一次性占位、完美排雷金光带+横幅占位、标中旗加重弹道占位;全部程序化色板原语,真实美术归 战斗表现)。
# Date: 2026-09-12
# 高内聚边界:纯演出——组合根按核心信号调用 play_*;本类零核心依赖、不自持游戏状态。
class_name BoardFxView
extends Control
const COL_GOLD := UiKit.GOLD
const COL_BOSS := UiKit.BOSS_PURPLE # 紫赤 #8F2F6A
const COL_FLAG := UiKit.FLAG_RED # 旗朱
const CONFETTI_COLS := [UiKit.GOLD, UiKit.FLAG_RED, UiKit.HERO_BLUE, UiKit.WARM]
var _banner: Label
func _init() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
set_anchors_preset(Control.PRESET_FULL_RECT)
_banner = UiKit.label("", 26, true)
_banner.add_theme_color_override("font_color", COL_GOLD)
_banner.set_anchors_preset(Control.PRESET_CENTER_TOP)
_banner.grow_horizontal = Control.GROW_DIRECTION_BOTH
_banner.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
_banner.visible = false
_banner.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(_banner)
# 清图瞬间:金粒喷泉 + 彩纸 3–5s 即收(§2.3 占位)
func play_clear_burst() -> void:
var fountain := CPUParticles2D.new()
fountain.position = size * 0.5
fountain.amount = 90
fountain.lifetime = UiKit.motion(1.6)
fountain.one_shot = true
fountain.explosiveness = 0.2
fountain.direction = Vector2(0, -1)
fountain.spread = 55.0
fountain.initial_velocity_min = 320.0
fountain.initial_velocity_max = 560.0
fountain.gravity = Vector2(0, 700)
fountain.scale_amount_min = 2.0
fountain.scale_amount_max = 4.5
fountain.color = COL_GOLD
fountain.emitting = true
add_child(fountain)
var confetti := CPUParticles2D.new()
confetti.position = Vector2(size.x * 0.5, -8.0)
confetti.amount = 60
confetti.lifetime = UiKit.motion(3.2)
confetti.one_shot = true
confetti.explosiveness = 0.9
confetti.direction = Vector2(0, 1)
confetti.spread = 75.0
confetti.initial_velocity_min = 90.0
confetti.initial_velocity_max = 200.0
confetti.gravity = Vector2(0, 140)
confetti.scale_amount_min = 3.0
confetti.scale_amount_max = 5.0
confetti.color_ramp = _confetti_ramp()
confetti.emitting = true
add_child(confetti)
var tw := create_tween()
tw.tween_interval(UiKit.motion(3.5))
tw.tween_callback(func():
for n in [fountain, confetti]:
if is_instance_valid(n):
n.queue_free())
func _confetti_ramp() -> Gradient:
var g := Gradient.new()
g.set_color(0, CONFETTI_COLS[0])
g.set_color(1, CONFETTI_COLS[1])
return g
# Boss 遭遇:紫赤影子爬过棋盘一次性占位演出(§2.6)
func play_boss_shadow() -> void:
var shadow := ColorRect.new()
shadow.color = Color(COL_BOSS, 0.55)
shadow.size = Vector2(size.x, 56.0)
shadow.position = Vector2(0, -60.0)
shadow.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(shadow)
var tw := shadow.create_tween()
tw.tween_property(shadow, "position:y", size.y, UiKit.motion(1.1)).set_trans(Tween.TRANS_SINE)
tw.tween_property(shadow, "modulate:a", 0.0, UiKit.motion(0.5))
tw.tween_callback(shadow.queue_free)
# 完美排雷:金光带加倍扫射 + 横幅占位(§2.2 最高档)
func play_perfect_sweep() -> void:
for i in 2:
var band := ColorRect.new()
band.color = Color(COL_GOLD, 0.35)
band.size = Vector2(size.x, 14.0 + 10.0 * i)
band.position = Vector2(-size.x, size.y * 0.3 + 40.0 * i)
band.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(band)
var tw := band.create_tween()
tw.tween_property(band, "position:x", size.x + 8.0, UiKit.motion(0.5 + 0.15 * i))
tw.tween_callback(band.queue_free)
_show_banner("完美排雷 ×2")
# 标中旗:旗化暴击弹道加重占位(自棋盘上缘飞向 B 区敌人卡方向——越界即收)
func play_flag_hit_projectile(heavy: bool) -> void:
var shot := ColorRect.new()
var w := 8.0 if heavy else 4.0
shot.color = COL_FLAG
shot.size = Vector2(w, w * 2.2)
shot.position = Vector2(size.x * 0.5, size.y * 0.7)
shot.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(shot)
var tw := shot.create_tween()
tw.tween_property(shot, "position", Vector2(size.x * 0.75, -30.0), UiKit.motion(0.35))
tw.parallel().tween_property(shot, "modulate:a", 0.0, UiKit.motion(0.35))
tw.tween_callback(shot.queue_free)
func _show_banner(text: String) -> void:
_banner.text = text
_banner.visible = true
_banner.modulate.a = 0.0
var tw := create_tween()
tw.tween_property(_banner, "modulate:a", 1.0, UiKit.motion(0.2))
tw.tween_interval(UiKit.motion(1.6))
tw.tween_property(_banner, "modulate:a", 0.0, UiKit.motion(0.4))
tw.tween_callback(func(): _banner.visible = false)