## 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 相对回落格面之上、英雄之下——位移/翻转/弹跳随父件 # 同步免费拿;尺寸换算归 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 # 椭圆中心 = 脚锚点(贴脚) 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)