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

192 lines
10 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:CellUnit——BoardView SubViewport 世界内逐格渲染件(Node2D)。
# 固定叠层序(ADR-0006 Decision 4):砖面底 < 变异纹带 < 数字/徽章 < 旗 < 焦点高亮——本批全部程序化
# _draw 等价平移现行占位视觉;每层留 texture 槽位(art-bible §8.2 格面 32×32 暂定档——终稿 1:1 换入,
# 本批不实现纹理加载)。无 class_name(类名缓存面纪律——BoardView 经 preload 使用)。
# 字体:font 槽位缺省 = ThemeDB.fallback_font(与旧 Button 缺省主题字体同源);注入挂点归
# BoardView.set_world_font(SubViewport 内主题不自动继承主场景,Phase B 复用面)。
# 行为等价(缺陷①回归约束):格件常驻定长、逐格重绘由 BoardView 驱动,本类零游戏状态——渲染数据
# 全部由 BoardView 每次 paint 写入(bg_sb/glyph/badge),呼吸微光由 BoardView 就地改 bg_sb 边框。
extends Node2D
var cell := Vector2i.ZERO # 板坐标(诊断观测面)
var edge := 46.0: # 格边长(BoardView.set_cell_area 单点驱动)
set(v):
edge = v
queue_redraw()
var bg_sb: StyleBoxFlat = null # 格底 StyleBox(BoardView 每次 paint 重建;呼吸微光就地改边框)
# ── 接触带微光绘制面(2026-09-26 批:可挖域微光自"墙格整框"改"英雄格周界空间侧"——art-bible §3.2 v2.8;
# 仅英雄格单元承载,BoardView.refresh 按可挖域写边/角码、_process 逐拍更新呼吸色)──
var contact_bands: Array = [] # 正交接触边码 0=N/1=S/2=W/3=E(该侧整条边)
var contact_corners: Array = [] # 斜向共享角码 0=NW/1=NE/2=SW/3=SE(角点+两侧各半条边)
var contact_col := Color(0, 0, 0, 0) # 当前呼吸色(alpha 0 = 不画)
var plate := false # 数字色牌开关(BoardView paint 按已开格 glyph 写入——原则二)
var outline_sides: Array = [] # 墙格地面朝向描边码 0=N/1=S/2=W/3=E(轮廓加强批——程序侧结构件)
var glyph := "": # 文字位——数字/雷/旗/人/?(现行视觉旗与数字互斥,同位承载)
set(v):
glyph = v
queue_redraw()
var glyph_color := UiKit.INK: # 文字色(墨族/雷朱/旗朱/小人蓝)
set(v):
glyph_color = v
queue_redraw()
var badge_glyph := "": # 奖励徽章文字(右下角金——旗之下、变异纹之上、不进数字区)
set(v):
badge_glyph = v
queue_redraw()
var dot_visible := false: # BFS 路径预览点迹(中心 6×6 小人蓝——旧 ColorRect 等价)
set(v):
dot_visible = v
queue_redraw()
var hl_visible := false: # 焦点高亮(悬停态边框覆盖层)
set(v):
hl_visible = v
queue_redraw()
var hl_color := UiKit.GOLD: # 高亮色(金目标/旗朱/禁入灰禁红)
set(v):
hl_color = v
queue_redraw()
var font: Font = null # 字体槽位(null = ThemeDB.fallback_font——BoardView.set_world_font 注入)
var bevel := 0.0: # 顶面倒角强度(0=关——立体原型批 2026-09-24;档位 0/0.35/0.6/1.0)
set(v):
bevel = v
queue_redraw()
# ── 素材槽位(本批全 null = 程序化占位服役;art-bible §8.2 格面 32×32 暂定档)──
var tex_base: Texture2D = null # ① 砖面底
var tex_mutation: Texture2D = null # ② 变异纹带
var tex_glyph: Texture2D = null # ③ 数字
var tex_badge: Texture2D = null # ③' 徽章
var tex_flag: Texture2D = null # ④ 旗
func _draw() -> void:
var rect := Rect2(Vector2.ZERO, Vector2(edge, edge))
# ① 砖面底(占位 = StyleBoxFlat:格底色 + 暗化描边 + 3px 圆角——旧 Button normal 样式等价;
# 呼吸微光/主角蓝框由 BoardView 改 bg_sb 后触发重绘)
if tex_base != null:
draw_texture_rect(tex_base, rect, false)
# 轮廓加强(2026-09-26 用户反馈「轮廓线不明显」):墙格地面朝向边补 2px 深墨线(§8.5 结构归程序——
# 素材 1px 墨线在 45/36px 非整数缩放下视觉衰减,程序线保底;墙-墙内界不画,保墙群内聚;
# 坐标推导:各边内贴 2px 矩形,相邻边矩形全长相交=周界闭合)
if not outline_sides.is_empty():
var ow := 2.0
var oc := Color8(30, 24, 18)
for b in outline_sides:
var or_ := Rect2()
match int(b):
0: or_ = Rect2(0, 0, edge, ow)
1: or_ = Rect2(0, edge - ow, edge, ow)
2: or_ = Rect2(0, 0, ow, edge)
3: or_ = Rect2(edge - ow, 0, ow, edge)
draw_rect(or_, oc, true)
# 瓦片态描边覆盖层(高墙瓦片接线批 2026-09-26):tex_base 在位时 BoardView 传入的 bg_sb
# 已降级为「透明底 + 描边」载体——呼吸微光/主角蓝框画在瓦片之上(art-bible §1.2 叠层序
# 不变:底 < 纹带 < 数字 < 旗 < 焦点高亮);素材缺位回退走 elif 程序化原样,零观感变化
if bg_sb != null:
draw_style_box(bg_sb, rect)
# 接触带微光(英雄格周界空间侧——正交邻墙=整条边;斜向=共享角点+两侧各半条边;光不进墙格):
# 带宽 4px 贴格边内侧(坐标推导:N=[0,0,edge,4] S=[0,edge-4,edge,4] W=[0,0,4,edge] E=[edge-4,0,4,edge];
# 半条边=沿邻边自角点起 edge/2;角点圆 r=6 贴角点圆心,近白芯 r=2.5 提亮)
if contact_col.a > 0.0:
var band := 4.0
var half := edge * 0.5
for b in contact_bands:
var r := Rect2()
match int(b):
0: r = Rect2(0, 0, edge, band)
1: r = Rect2(0, edge - band, edge, band)
2: r = Rect2(0, 0, band, edge)
3: r = Rect2(edge - band, 0, band, edge)
draw_rect(r, contact_col, true)
for cc in contact_corners:
var pt := Vector2.ZERO
match int(cc):
0: pt = Vector2(0, 0)
1: pt = Vector2(edge, 0)
2: pt = Vector2(0, edge)
3: pt = Vector2(edge, edge)
draw_circle(pt, 6.0, contact_col)
draw_circle(pt, 2.5, Color(1, 1, 1, minf(1.0, contact_col.a * 0.95)))
# 半条边:角点沿两条邻边各延伸 edge/2(坐标推导:横带沿 N/S 自角点向板心侧 half;
# NW/SE 半带 x=y=角点坐标,NE/SE 半带自 edge-half 收进——正交整边时重叠同色无害)
if int(cc) == 0 or int(cc) == 1:
# N 侧横带:NW 自 x=0、NE 自 x=edge-half
draw_rect(Rect2(pt.x if int(cc) == 0 else pt.x - half, 0.0, half, band), contact_col, true)
if int(cc) == 2 or int(cc) == 3:
# S 侧横带:SW 自 x=0、SE 自 x=edge-half
draw_rect(Rect2(pt.x if int(cc) == 2 else pt.x - half, edge - band, half, band), contact_col, true)
if int(cc) == 0 or int(cc) == 2:
# W 侧竖带:NW 自 y=0、SW 自 y=edge-half
draw_rect(Rect2(0.0, pt.y if int(cc) == 0 else pt.y - half, band, half), contact_col, true)
if int(cc) == 1 or int(cc) == 3:
# E 侧竖带:NE 自 y=0、SE 自 y=edge-half
draw_rect(Rect2(edge - band, pt.y if int(cc) == 1 else pt.y - half, band, half), contact_col, true)
elif bg_sb != null:
draw_style_box(bg_sb, rect)
# 顶面倒角(立体原型批:光源左上——上/左内沿受光 2px、下/右内沿背光 2px;内缩 2px 让
# 呼吸微光/主角蓝边框保持最外沿可见;强度随档位)
if bevel > 0.0:
var base: Color = bg_sb.bg_color
var lit: Color = base.lightened(0.22 * bevel)
var dark: Color = base.darkened(0.22 * bevel)
var t := 2.0
draw_rect(Rect2(t, t, edge - t * 2.0, t), lit, true)
draw_rect(Rect2(t, t, t, edge - t * 2.0), lit, true)
draw_rect(Rect2(t, edge - t * 2.0, edge - t * 2.0, t), dark, true)
draw_rect(Rect2(edge - t * 2.0, t, t, edge - t * 2.0), dark, true)
# ② 变异纹带(占位批次无程序化纹带——槽位先行,终稿换入即用)
if tex_mutation != null:
draw_texture_rect(tex_mutation, rect, false)
# ③ 数字/徽章(数字 ≥ 格高 50% 墨族对格底 ≥4.5:1;徽章右下角金,遮蔽态 = "?")
if glyph != "":
# 数字色牌(原则二:数字一律垫素色直角牌——对比由牌墨承载,可读不依赖格底;暗地面瓦片批的
# 可读性修复 2026-09-26。牌尺寸 0.66/0.68 格边居中——字形 ≥0.5 格边在牌内留白 ≥1px;
# 旗=未开格不垫牌(旗朱在墙瓦片上已可读))
if plate:
var pw := edge * 0.66
var ph := edge * 0.68
var pr := Rect2((edge - pw) * 0.5, (edge - ph) * 0.5, pw, ph)
draw_rect(pr, UiKit.DIGIT_PLATE, true)
draw_rect(pr, UiKit.DIGIT_PLATE_EDGE, false, 1.0)
if tex_glyph != null:
draw_texture_rect(tex_glyph, rect, false)
else:
_draw_glyph(glyph, glyph_color, maxi(14, int(edge * 0.5)))
if badge_glyph != "":
if tex_badge != null:
draw_texture_rect(tex_badge, rect, false)
else:
_draw_badge(badge_glyph)
# ④ 旗(现行视觉旗文字在 ③ 文字位承载——独立槽位留给终稿旗图)
if tex_flag != null:
draw_texture_rect(tex_flag, rect, false)
# ⑤ 路径点迹 + 焦点高亮(悬停态覆盖层,不参与命中)
if dot_visible:
var ds := 6.0
draw_rect(Rect2(Vector2((edge - ds) * 0.5, (edge - ds) * 0.5), Vector2(ds, ds)), UiKit.HERO_BLUE, true)
if hl_visible:
# 悬停高亮减淡(2026-09-26 用户反馈:金框太明显——绘制时 55% alpha,hl_color 属性与探针断言面不动)
draw_rect(Rect2(1, 1, edge - 2.0, edge - 2.0), Color(hl_color, 0.55), false, 2.0) # 2px 内描边(旧 hl Panel 等价)
# 文字位绘制:水平居中 + 垂直居中(基线 = (格高 − 字高)/2 + 上伸部——旧 Button 居中对齐等价)
func _draw_glyph(g: String, col: Color, fs: int) -> void:
var f := font if font != null else ThemeDB.fallback_font
if f == null:
return
var asc := f.get_ascent(fs)
var desc := f.get_descent(fs)
draw_string(f, Vector2(0.0, (edge - (asc + desc)) * 0.5 + asc), g,
HORIZONTAL_ALIGNMENT_CENTER, edge, fs, col)
# 徽章绘制:右下角金(旧 Label BOTTOM_RIGHT 锚点等价——文字贴角内缩 2–3px)
func _draw_badge(g: String) -> void:
var f := font if font != null else ThemeDB.fallback_font
if f == null:
return
var fs := maxi(10, int(edge * 0.28))
var sz := f.get_string_size(g, HORIZONTAL_ALIGNMENT_LEFT, -1, fs)
draw_string(f, Vector2(edge - sz.x - 2.0, edge - 3.0), g, HORIZONTAL_ALIGNMENT_LEFT, -1, fs, UiKit.GOLD)