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

111 lines
6.1 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
# 棋盘 Node2D 迁移批 Phase A 2026-09-23:BoardWorld——棋盘 Node2D 世界根(SubViewport 内
# CellUnit 容器)。职责单点:世界级材质挂点(set_desaturated 去饱和挂此处,CellUnit
# use_parent_material 链下随世界灰化)+ 主题/字体显式注入槽位(SubViewport 不自动继承主场景
# Control 主题——ADR-0006 Negative 项;Phase B 两舞台共用骨架,ADR-0006 Decision 5)。
# 无 class_name(类名缓存面纪律——BoardView 经 preload 使用)。
# 立体原型批 2026-09-24(用户拍板「三档厚度实机对比」):板块伪立体绘制——正俯视纸雕风,
# 顶面方格不变(数字可读性硬指标不受伤),厚度全部画在网格矩形外的正面/右侧悬崖带:
# 正面(背光暗)+右侧(微受光)+列分隔缝(ITB 悬崖列感)+岩层横纹+底部悬浮影(厚档)+
# 顶面接触 AO。零布局/命中改动(悬崖向网格外延展,世界尺寸由 BoardView._update_world_size 加 D)。
extends Node2D
var board_font: Font = null # 字体注入槽位(null = ThemeDB.fallback_font——与旧 Button 缺省主题字体同源)
var hero: Sprite2D = null # 英雄单位精灵(棋盘小人贴图批 2026-09-25——移动实体独立于 CellUnit 格面
# 语义,计划书 §3.A;null = 未创建/随 rebuild 清场,BoardView.refresh 经
# ensure_hero 重建。texture 缺位时 BoardView 不调本方法=字形「人」回退路径)
# 英雄精灵惰性创建(幂等):脚底锚(offset 上移半高——scale.y 弹跳向脚底收敛不悬空)+ z_index=1
# 压格面之上(挥铲特效在 SubViewport 之外恒更上层,满足「格面之上、特效之下」叠序);NEAREST =
# SubViewport 缩放下像素清晰(默认 Linear 会糊);use_parent_material = 随世界去饱和材质灰化
#(结算期与 CellUnit 同口径——基批漏挂,本批补齐)。返回值便于 BoardView 即时落位。
# 脚下椭圆影(2026-09-26 用户裁决走 Godot 组件合成、贴图零改动):径向渐变纹理 ×黑色半透明
# modulate 压扁,挂英雄子件(z_index=-1 相对回落格面之上、英雄之下——位移/翻转/弹跳随父件
# 同步免费拿;尺寸换算归 BoardView.HERO_SHADOW_PX 常量)。纹理 filter 用 LINEAR 保渐变平滑
#(NEAREST 会把渐变打回条带)。
func ensure_hero(tex: Texture2D, shadow_px: Vector2, scale: float) -> Sprite2D:
if hero != null:
return hero
var grad := Gradient.new()
grad.set_color(0, Color(1, 1, 1, 1))
grad.set_color(1, Color(1, 1, 1, 0))
var shadow_tex := GradientTexture2D.new()
shadow_tex.gradient = grad
shadow_tex.width = 64
shadow_tex.height = 64
shadow_tex.fill = GradientTexture2D.FILL_RADIAL
shadow_tex.fill_from = Vector2(0.5, 0.5)
shadow_tex.fill_to = Vector2(0.5, 0.0)
var shadow := Sprite2D.new()
shadow.texture = shadow_tex
shadow.modulate = Color(0, 0, 0, 0.35)
shadow.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR
shadow.scale = shadow_px / (64.0 * scale) # 子件缩放叠父件 scale——目标屏幕尺寸 ÷ (纹理边 × 父档)
shadow.position = Vector2.ZERO # 椭圆中心 = 脚锚点(贴脚——上批 (0,2) 下坠让影子与脚脱开,用户报缺陷)
shadow.z_index = -1 # 相对父件回落:格面(z=0 树序在先)之上、英雄本体之下
shadow.use_parent_material = true # 随英雄链世界去饱和材质
hero = Sprite2D.new()
hero.texture = tex
hero.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
hero.centered = true
hero.offset = Vector2(0.0, -16.0) # 纹理中点上移半高——position = 脚底中点
hero.z_index = 1
hero.use_parent_material = true
add_child(hero)
hero.add_child(shadow)
return hero
# ── 立体悬崖(BoardView.set_cell_area / _update_world_size 单点驱动;厚度定稿 8px=中档 2026-09-24)──
var depth_px := 0.0: # 悬崖厚度(像素;0 = 平面)
set(v):
depth_px = v
queue_redraw()
var slab := Vector2.ZERO: # 网格矩形像素尺寸(不含悬崖外延)
set(v):
slab = v
queue_redraw()
var stride_px := 48.0: # 格步距(cell + SEP——列分隔缝对齐格边界)
set(v):
stride_px = v
queue_redraw()
var cols := 0: # 列数(正面悬崖竖缝数 = cols−1)
set(v):
cols = v
queue_redraw()
var mat := Color8(201, 175, 131) # 材质锚色(掩尘 #C9AF83——侧面由此派生明暗;BoardView 传入)
func _draw() -> void:
if depth_px <= 0.0 or slab == Vector2.ZERO:
return
var w := slab.x
var h := slab.y
var d := depth_px
var front := mat.darkened(0.55) # 正面悬崖(背光)
var right := mat.darkened(0.38) # 右侧悬崖(微受光)
# 正面悬崖带 + 右侧悬崖带
draw_rect(Rect2(0, h, w, d), front, true)
draw_rect(Rect2(w, 0, d, h + d), right, true)
# 正面列分隔竖缝(对齐格边界——ITB 悬崖列感)
for i in range(1, cols):
var x := float(i) * stride_px - 1.0
draw_rect(Rect2(x, h, 2.0, d), front.darkened(0.25), true)
# 岩层横纹(两条微暗横带——碎石层理)
draw_rect(Rect2(0, h + d * 0.38, w, 1.5), front.darkened(0.18), true)
draw_rect(Rect2(0, h + d * 0.72, w, 1.5), front.darkened(0.12), true)
# 悬崖口沿高光(顶面与悬崖交界 1px 亮线——倒角受光)
draw_rect(Rect2(0, h, w, 1.0), mat.lightened(0.18), true)
draw_rect(Rect2(w, 0, 1.0, h), mat.lightened(0.12), true)
# 顶面接触 AO(网格内侧贴边 2px 暗带——顶面陷进阴影的衔接感)
draw_rect(Rect2(0, h - 2.0, w, 2.0), Color(0, 0, 0, 0.18), true)
draw_rect(Rect2(w - 2.0, 0, 2.0, h), Color(0, 0, 0, 0.14), true)
# 底线(悬崖最底 2px 最暗——收边)
draw_rect(Rect2(0, h + d - 2.0, w + d, 2.0), front.darkened(0.35), true)
# 底部悬浮影(中厚档起——悬浮岛离地感;三层渐隐)
if d >= 8.0:
var layers := [Color(0, 0, 0, 0.16), Color(0, 0, 0, 0.10), Color(0, 0, 0, 0.05)]
for i in layers.size():
var sh := 3.0 + float(i) * 3.0
draw_rect(Rect2(sh, h + d + sh * 0.5, w + d - sh * 1.5, float(2 + i)), layers[i], true)