68 lines
3.0 KiB
GDScript
68 lines
3.0 KiB
GDScript
## 营地场景布局表 schema(camp_scene_layout.tres):10 层贴图矩形/命中矩形/门洞缺口/围墙带包络/顶栏禁区。
|
||
## 坐标数值唯一事实源=数据行本表——视图、探针、单测一律读表取值,禁另写坐标字面量。
|
||
class_name CampSceneLayoutTable
|
||
extends Resource
|
||
|
||
@export var canvas := Vector2(1280, 800) # 终稿画布(工程档同幅面)
|
||
@export var hud_band_h := 48 # 顶栏禁区高度(命中不侵)
|
||
@export var gate_gap := Vector2i(520, 760) # 门洞缺口 x 范围(透出背景层小路,禁填死)
|
||
@export var wall_band := Rect2(0, 240, 1280, 70) # 围墙带包络(门柱顶 240—桩底 310;围墙贴图须落在其内)
|
||
@export var layers: Array[CampSceneLayerSpec] = []
|
||
|
||
|
||
## 加载期 fail-fast 校验(ConfigDB 装载即查,问题非空=数据致命)。
|
||
## 校验面按件拆分:层身份与贴图矩形/命中区边界/命中区互斥/围墙带包络。
|
||
func validate() -> Array[String]:
|
||
var problems: Array[String] = []
|
||
var clickables: Array[CampSceneLayerSpec] = _collect_clickables(problems)
|
||
_check_hotspot_bounds(clickables, problems)
|
||
_check_hotspot_disjoint(clickables, problems)
|
||
_check_wall_band(problems)
|
||
return problems
|
||
|
||
|
||
func _collect_clickables(problems: Array[String]) -> Array[CampSceneLayerSpec]:
|
||
var seen: Dictionary[StringName, bool] = {}
|
||
var clickables: Array[CampSceneLayerSpec] = []
|
||
for layer in layers:
|
||
if layer.key == &"":
|
||
problems.append("层键为空")
|
||
continue
|
||
if seen.has(layer.key):
|
||
problems.append("层键重复: %s" % layer.key)
|
||
seen[layer.key] = true
|
||
if _out_of_canvas(layer.texture_rect):
|
||
problems.append("贴图矩形越画面: %s %s" % [layer.key, layer.texture_rect])
|
||
if layer.is_clickable():
|
||
if layer.hotspot_key == &"":
|
||
problems.append("可点层缺命中键: %s" % layer.key)
|
||
clickables.append(layer)
|
||
elif layer.hotspot_key != &"":
|
||
problems.append("不可点层带命中键: %s" % layer.key)
|
||
return clickables
|
||
|
||
|
||
func _check_hotspot_bounds(clickables: Array[CampSceneLayerSpec], problems: Array[String]) -> void:
|
||
for h in clickables:
|
||
if h.hotspot.position.x < 0.0 or h.hotspot.position.y < hud_band_h \
|
||
or _out_of_canvas(h.hotspot):
|
||
problems.append("命中区越画面或侵顶栏禁区: %s %s" % [h.key, h.hotspot])
|
||
|
||
|
||
func _check_hotspot_disjoint(clickables: Array[CampSceneLayerSpec], problems: Array[String]) -> void:
|
||
for i in clickables.size():
|
||
for j in range(i + 1, clickables.size()):
|
||
if clickables[i].hotspot.intersects(clickables[j].hotspot):
|
||
problems.append("命中区相交: %s × %s" % [clickables[i].key, clickables[j].key])
|
||
|
||
|
||
func _check_wall_band(problems: Array[String]) -> void:
|
||
for layer in layers:
|
||
if layer.key == &"wall" and not wall_band.encloses(layer.texture_rect):
|
||
problems.append("围墙贴图越围墙带包络: %s" % layer.texture_rect)
|
||
|
||
|
||
func _out_of_canvas(rect: Rect2) -> bool:
|
||
return rect.position.x < 0.0 or rect.position.y < 0.0 \
|
||
or rect.end.x > canvas.x or rect.end.y > canvas.y
|