131 lines
4.9 KiB
GDScript
131 lines
4.9 KiB
GDScript
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||
## 悬停预承诺呈现域件(BoardView 拆件——单一变化原因=悬停反馈语义):
|
||
## 三语义光标、目标格边框、BFS 路径预览、chord 双击首遇锚的唯一承载(自 board_view 收编 11 函数族)。
|
||
## 无 class_name(类名缓存面纪律)——经宿主 board_view preload 引用;构造=引用束注入
|
||
## (cells/minesweeper/diggable 共享引用+格命中换算/壳级光标写入/hover_forbidden 与 chord 发射注入 Callable——
|
||
## 输入经宿主三入站口委托,禁反向持宿主引用);_r0 出生展开区成员留宿主。
|
||
extends RefCounted
|
||
|
||
const COL_HL_TARGET := UiKit.GOLD # 悬停目标格边框(金)
|
||
const COL_SEAL := UiKit.SEAL_BLACK # 封印黑(与宿主 :658 双侧服役——各自 alias UiKit 单源)
|
||
const CURSOR_DIG := Input.CURSOR_CROSS # 挖——镐形自绘纹理载体
|
||
const CURSOR_MOVE_SEM := Input.CURSOR_ARROW # 移动——箭头(命名避开 Control.CURSOR_MOVE 原生成员遮蔽)
|
||
const CHORD_WINDOW_MS := 350
|
||
|
||
var _cells := {} # 共享引用(宿主容器同对象——rebuild 只 clear 不重绑)
|
||
var _minesweeper = null # 排雷玩法 只读查询引用(宿主 rebuild 重绑时同拍回写本成员)
|
||
var _diggable := {} # 共享引用(可挖域——呼吸微光作用集同源)
|
||
var _cb_cell_at: Callable # 格命中换算(宿主 _cell_at——整图公式单点留宿主)
|
||
var _cb_cursor: Callable # 壳级光标写入(宿主 mouse_default_cursor_shape 单点)
|
||
var _cb_forbidden: Callable # hover_forbidden 信号发射(首遇 toast 去重归组合根)
|
||
var _cb_chord: Callable # chord_attempted 信号发射(chord 肌肉记忆提示锚)
|
||
var _hover := Vector2i(-9, -9)
|
||
var _last_click := {"cell": Vector2i(-9, -9), "ms": -100000}
|
||
|
||
|
||
func _init(bundle: Dictionary) -> void:
|
||
_cells = bundle["cells"]
|
||
_minesweeper = bundle["minesweeper"]
|
||
_diggable = bundle["diggable"]
|
||
_cb_cell_at = bundle["cell_at"]
|
||
_cb_cursor = bundle["cursor"]
|
||
_cb_forbidden = bundle["forbidden"]
|
||
_cb_chord = bundle["chord"]
|
||
|
||
|
||
func _hover_at(pos: Vector2) -> void:
|
||
var c: Vector2i = _cb_cell_at.call(pos)
|
||
if c.x < 0:
|
||
if _hover.x >= 0:
|
||
_on_cell_unhover(_hover)
|
||
elif c != _hover:
|
||
if _hover.x >= 0:
|
||
_on_cell_unhover(_hover)
|
||
_on_cell_hover(c)
|
||
|
||
|
||
func _on_shell_mouse_exited() -> void:
|
||
if _hover.x >= 0:
|
||
_on_cell_unhover(_hover)
|
||
|
||
|
||
# chord 肌肉记忆首遇锚:同格双左击快开尝试(350ms 窗)——每 run 一次提示由组合根去重
|
||
func _detect_chord(c: Vector2i) -> void:
|
||
var now := Time.get_ticks_msec()
|
||
if _last_click.cell == c and now - int(_last_click.ms) <= CHORD_WINDOW_MS:
|
||
_cb_chord.call(c)
|
||
_last_click.ms = -100000
|
||
return
|
||
_last_click = {"cell": c, "ms": now}
|
||
|
||
|
||
func _on_cell_hover(c: Vector2i) -> void:
|
||
_hover = c
|
||
_apply_hover_visuals(c)
|
||
|
||
|
||
func _on_cell_unhover(c: Vector2i) -> void:
|
||
if _hover == c:
|
||
_hover = Vector2i(-9, -9)
|
||
_clear_hover_visuals(c)
|
||
|
||
|
||
func _refresh_hover_after_paint() -> void:
|
||
# 状态随 refresh 变化后光标/边框语义需重算(悬停格四格态可能已变)
|
||
if _hover.x >= 0 and _cells.has(_hover):
|
||
_apply_hover_visuals(_hover)
|
||
|
||
|
||
func _apply_hover_visuals(c: Vector2i) -> void:
|
||
if _minesweeper == null or not _cells.has(c):
|
||
return
|
||
_clear_hover_visuals(c)
|
||
var u: Node2D = _cells[c]
|
||
var revealed: bool = _minesweeper.is_revealed(c)
|
||
var seal: bool = _minesweeper.has_seal(c)
|
||
var adjacent: bool = _diggable.has(c)
|
||
if revealed:
|
||
u.face.hl_visible = true
|
||
u.face.hl_color = COL_HL_TARGET # 移动目标格边框(金)
|
||
_set_cursor_shape(c, CURSOR_MOVE_SEM)
|
||
_show_path_preview(c)
|
||
elif adjacent:
|
||
u.face.hl_visible = true
|
||
u.face.hl_color = COL_HL_TARGET # 挖掘目标格边框(相邻封印格同此——左键直接挖)
|
||
_set_cursor_shape(c, CURSOR_DIG)
|
||
elif seal:
|
||
u.face.hl_visible = true
|
||
u.face.hl_color = COL_SEAL # 已承诺封印标记(封印黑;无交互可供)
|
||
_set_cursor_shape(c, Input.CURSOR_FORBIDDEN)
|
||
else:
|
||
u.face.hl_visible = true
|
||
u.face.hl_color = UiKit.RED_FORBID # 不可及域灰禁框(禁止光标+首遇 toast 双通道)
|
||
_set_cursor_shape(c, Input.CURSOR_FORBIDDEN)
|
||
_cb_forbidden.call(c)
|
||
|
||
|
||
func _clear_hover_visuals(c: Vector2i) -> void:
|
||
if not _cells.has(c):
|
||
return
|
||
_cells[c].face.hl_visible = false
|
||
_hide_path_preview()
|
||
|
||
|
||
func _set_cursor_shape(c: Vector2i, shape: int) -> void:
|
||
_cb_cursor.call(shape) # 壳级光标(悬停格语义决定——单格悬停恒一)
|
||
|
||
|
||
func _show_path_preview(c: Vector2i) -> void:
|
||
# 合法性指示:悬停已开格 → BFS 路径蓝细线点迹(compute_move_path 只读面)
|
||
if _minesweeper == null:
|
||
return
|
||
var path: Array[Variant] = _minesweeper.compute_move_path(c)
|
||
for pc in path:
|
||
if _cells.has(pc):
|
||
_cells[pc].face.dot_visible = true
|
||
|
||
|
||
func _hide_path_preview() -> void:
|
||
for c in _cells:
|
||
_cells[c].face.dot_visible = false
|