r2-1 瓦片族(排版+素材装载+墨族判据+查表)→ views/tile_palette.gd; r2-2 英雄族(贴图/位移/影/朝向/缩放几何)→ views/hero_sprite.gd(Node2D); r2-3 board_view 改引+直引面换指(terrain_tile_sets_test/ui_contrast_probe), 探针与 main 的组合根直读面经转发属性/常量别名保持零改动。 S13 计数守恒:基线含类变量数/公有方法数两条计数型键,故 board_view 用 13 个转发属性 +2 个组件引用压回原计数(45 变量/27 公有方法);baselined 的 wall_tile_for/ wall_center_tile/digit_ink_mode 以查表/辅助函数重构压回阈值内(非改名保违例), 旧文件级键随函数迁出自然失效——基线文件零改动(用户令:只改代码不改基线)。 验收:terrain_tile_sets_test 19 检查绿(判据读数与迁移前同值);gdstyle 基线外新违规 0; S9/S10 绿;probe_gate --click 全绿(含 ui_input_probe 十八断言/click 走查 0 问题); render_gate 棋盘三图+菜单 golden changed=0.00%;撤销证明:测试改引回退旧址符号 → SCRIPT ERROR(Parse Error: Static function "_normalize_floor_luma()" not found)+ error_scan exit 1,还原后 19 检查复绿、error_scan exit 0。
106 lines
5.3 KiB
GDScript
106 lines
5.3 KiB
GDScript
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||
## BoardWorld——棋盘 Node2D 世界根(SubViewport 内 CellUnit 容器):世界级去饱和材质与字体注入挂点。
|
||
## 无 class_name——使用方经 preload 引用。
|
||
extends Node2D
|
||
|
||
var board_font: Font = null # 字体注入槽位(null = ThemeDB.fallback_font)
|
||
var hero: Sprite2D = null # 英雄单位精灵(移动实体独立于 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 即时落位。
|
||
# 脚下椭圆影(走 Godot 组件合成、贴图零改动):径向渐变纹理 ×黑色半透明
|
||
# modulate 压扁,挂英雄子件(z_index=-1 相对回落格面之上、英雄之下——位移/翻转/弹跳随父件
|
||
# 同步免费拿;尺寸换算归 HeroSprite.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 # 椭圆中心 = 脚锚点(贴脚)
|
||
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
|
||
# 脚底对齐:素材底部 7 行全透明(内容底 = 源 row 24,自中心 16−7.5=8.5px),故 offset.y = −8.5
|
||
# → 内容底恰落 position(脚锚=格底往上 25% 线——头仍越上格沿)
|
||
hero.offset = Vector2(0.0, -8.5) # 纹理中心上移 8.5 源 px——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=中档)──
|
||
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: Color = UiKit.BRICK # 材质锚色(掩尘 #C9AF83 与 UiKit.BRICK 同值;侧面由此派生明暗,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)
|