iter47-卡2:卡④(迭代47·营地场景图新建批): 十层素材落地+CampSceneView场景图+layout表fail-fast+四柜台拆解五子界面+大门篝火动线+断言迁移批+审计补差——CampOverlay退役全仓零残留

This commit is contained in:
DKChan committed 2026-11-01 23:44:29 +08:00
1 parent 0761071b37
commit bbeeea77e0
45 files changed
+1614 -822

No files matched your search

@@ -0,0 +1,13 @@
## 营地场景单层规格(camp_scene_layout.tres 行件):层键+贴图矩形+命中矩形+命中键。
## z 序=表内数组序(视图子节点序同源派生);坐标一律终稿画布 1280×800 像素坐标。
class_name CampSceneLayerSpec
extends Resource
@export var key: StringName = &"" # 层键(对齐 UiKit.TEX_CAMP_* 常量后缀)
@export var texture_rect: Rect2 = Rect2() # 贴图矩形(1:1 像素贴图落位)
@export var hotspot: Rect2 = Rect2() # 命中矩形(零矩形=不可点层——bg/wall/tent)
@export var hotspot_key: StringName = &"" # object_pressed 载荷键(可点层必填)
func is_clickable() -> bool:
return hotspot.size.x > 0.0 and hotspot.size.y > 0.0
@@ -0,0 +1 @@
uid://bll8d0s1nmarf
@@ -0,0 +1,67 @@
## 营地场景布局表 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
@@ -0,0 +1 @@
uid://c6p8wyvcc5upp
+82
View File
@@ -0,0 +1,82 @@
[gd_resource type="Resource" script_class="CampSceneLayoutTable" load_steps=13 format=3]
[ext_resource type="Script" path="res://data/schemas/camp_scene_layout_table.gd" id="1"]
[ext_resource type="Script" path="res://data/schemas/camp_scene_layer_spec.gd" id="2"]
[sub_resource type="Resource" id="1"]
script = ExtResource("2")
key = &"bg"
texture_rect = Rect2(0, 0, 1280, 800)
hotspot = Rect2(0, 0, 0, 0)
hotspot_key = &""
[sub_resource type="Resource" id="2"]
script = ExtResource("2")
key = &"wall"
texture_rect = Rect2(0, 261, 1280, 49)
hotspot = Rect2(0, 0, 0, 0)
hotspot_key = &""
[sub_resource type="Resource" id="3"]
script = ExtResource("2")
key = &"board"
texture_rect = Rect2(845, 268, 130, 121)
hotspot = Rect2(845, 268, 130, 140)
hotspot_key = &"board"
[sub_resource type="Resource" id="4"]
script = ExtResource("2")
key = &"gate"
texture_rect = Rect2(520, 250, 240, 211)
hotspot = Rect2(520, 250, 240, 220)
hotspot_key = &"gate"
[sub_resource type="Resource" id="5"]
script = ExtResource("2")
key = &"dummy"
texture_rect = Rect2(340, 520, 120, 180)
hotspot = Rect2(340, 520, 120, 180)
hotspot_key = &"dummy"
[sub_resource type="Resource" id="6"]
script = ExtResource("2")
key = &"forge"
texture_rect = Rect2(40, 467, 240, 193)
hotspot = Rect2(40, 420, 240, 240)
hotspot_key = &"forge"
[sub_resource type="Resource" id="7"]
script = ExtResource("2")
key = &"tent"
texture_rect = Rect2(982, 520, 251, 170)
hotspot = Rect2(0, 0, 0, 0)
hotspot_key = &""
[sub_resource type="Resource" id="8"]
script = ExtResource("2")
key = &"chest"
texture_rect = Rect2(1097, 700, 106, 90)
hotspot = Rect2(1085, 700, 130, 90)
hotspot_key = &"chest"
[sub_resource type="Resource" id="9"]
script = ExtResource("2")
key = &"notebook"
texture_rect = Rect2(818, 704, 100, 66)
hotspot = Rect2(818, 690, 100, 80)
hotspot_key = &"notebook"
[sub_resource type="Resource" id="10"]
script = ExtResource("2")
key = &"campfire"
texture_rect = Rect2(560, 571, 160, 149)
hotspot = Rect2(560, 640, 160, 80)
hotspot_key = &"campfire"
[resource]
script = ExtResource("1")
canvas = Vector2(1280, 800)
hud_band_h = 48
gate_gap = Vector2i(520, 760)
wall_band = Rect2(0, 240, 1280, 70)
layers = [SubResource("1"), SubResource("2"), SubResource("3"), SubResource("4"), SubResource("5"), SubResource("6"), SubResource("7"), SubResource("8"), SubResource("9"), SubResource("10")]