From 064b225e0b8a19fd08955f1d764ef17ec1f907a1 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Wed, 22 Jul 2026 12:08:15 +0800 Subject: [PATCH 1/5] =?UTF-8?q?docs(designer):=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E8=AE=A1=E5=88=92=20=E2=80=94=20=E8=A1=8C=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=99=A8=E6=88=90=E5=91=98=E5=8F=98=E9=87=8F=E4=B8=8D=E6=A0=87?= =?UTF-8?q?=E6=B3=A8=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plans/2026-07-22-designer-tuple-list-editor.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs_dev/plans/2026-07-22-designer-tuple-list-editor.md b/docs_dev/plans/2026-07-22-designer-tuple-list-editor.md index 6021b27..edc0506 100644 --- a/docs_dev/plans/2026-07-22-designer-tuple-list-editor.md +++ b/docs_dev/plans/2026-07-22-designer-tuple-list-editor.md @@ -114,7 +114,7 @@ git commit -m "feat(designer): 新增整数元组列表行编辑器组件" (4 处 Edit,精确匹配,保留 TAB 缩进。) -- [ ] **Step 1: 成员变量类型** +- [ ] **Step 1: 成员变量类型(改为不标注,动态派发 setup/get_values)** old: ```gdscript @@ -122,7 +122,7 @@ var _edges: TextEdit ``` new: ```gdscript -var _edges: Control +var _edges ``` - [ ] **Step 2: `_ready()` —— edges 文本框换行编辑器** @@ -191,18 +191,18 @@ git commit -m "feat(designer): Core 电路边改行编辑器(去 JSON)" **Files:** - Modify: `addons/game_designer/balance_tab.gd` -- [ ] **Step 1: 成员变量类型** +- [ ] **Step 1: 成员变量类型(改为不标注,动态派发 setup/get_values)** old: ```gdscript - var _aether: TextEdit +var _aether: TextEdit ``` new: ```gdscript - var _aether: Control +var _aether ``` -(注意:该 `var` 声明位于文件顶部成员区,缩进为单 TAB;按文件实际缩进匹配。) +(注意:`_aether` 成员声明在文件顶部成员区,无前导缩进;`balance_tab.gd` 的 `var _aether: TextEdit` 在第 15 行左右,顶格。) - [ ] **Step 2: `_ready()` —— aether 文本框换行编辑器** @@ -331,6 +331,6 @@ Expected: `BALANCE FAILS=0 []`(5 行 [[1,0],[5,3],[10,8],[15,14],[20,20]]) **占位符扫描:** 无 TBD/TODO;每步含完整代码或精确命令。✅ -**类型/命名一致性:** `_edges`/`_aether` 由 TextEdit→Control(Task 2/3 定义,Task 4 回读用 `tab._edges`/`tab._aether`);`setup`/`set_values`/`get_values`(Task 1 定义,Task 2/3/4 调用一致);行数据模型 `Array[Array]` 全程一致。✅ +**类型/命名一致性:** `_edges`/`_aether` 由 `TextEdit` 改为**不标注**(动态派发 setup/get_values,避免 Control 无此方法的编译错;Task 4 回读用 `tab._edges`/`tab._aether`);`setup`/`set_values`/`get_values`(Task 1 定义,Task 2/3/4 调用一致);行数据模型 `Array[Array]` 全程一致。✅ **已知取舍:** LINEAR/MATRIX 法杖应用后仍会写 `edges:[]`(既有行为,非本次引入);回读把「空数组 == 缺 edges 键」按 size 0 视为等价。 From 0d6d511c862bed90b3c7d67e8c64b0e8d2143d33 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Wed, 22 Jul 2026 12:09:47 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat(designer):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=95=B4=E6=95=B0=E5=85=83=E7=BB=84=E5=88=97=E8=A1=A8=E8=A1=8C?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=99=A8=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/game_designer/tuple_list_editor.gd | 68 +++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 addons/game_designer/tuple_list_editor.gd diff --git a/addons/game_designer/tuple_list_editor.gd b/addons/game_designer/tuple_list_editor.gd new file mode 100644 index 0000000..88e7245 --- /dev/null +++ b/addons/game_designer/tuple_list_editor.gd @@ -0,0 +1,68 @@ +## 整数元组列表编辑器(@tool)— 每行 N 个 SpinBox + 🗑 删行,底部 ➕ 加行。 +## 用于 Core edges(from/to)、balance aether_thresholds(波次/碎片)等可变长小整数元组列表。 +## 数据模型:Array[Array](行数组);调用方负责与自身 JSON 结构互转。 +@tool +extends VBoxContainer + +var _cols: Array = [] # [{label,min,max,step,int,default}] +var _rows_box: VBoxContainer +var _add_label: String = "➕ 加行" + +func setup(col_specs: Array, add_label: String = "➕ 加行") -> void: + _cols = col_specs + _add_label = add_label + _rows_box = VBoxContainer.new() + add_child(_rows_box) + var add_btn := Button.new() + add_btn.text = _add_label + add_btn.pressed.connect(_on_add) + add_child(add_btn) + +func set_values(rows: Array) -> void: + if _rows_box == null: + return + for c in _rows_box.get_children(): + _rows_box.remove_child(c) + c.free() + for r in rows: + _add_row(r) + +func get_values() -> Array: + var out: Array = [] + if _rows_box == null: + return out + for h in _rows_box.get_children(): + var row: Array = [] + var ci := 0 + for ch in h.get_children(): + if ch is SpinBox: + var v: float = (ch as SpinBox).value + var is_int: bool = bool(_cols[ci].get("int", true)) if ci < _cols.size() else true + row.append(int(v) if is_int else v) + ci += 1 + out.append(row) + return out + +func _on_add() -> void: + _add_row([]) + +func _add_row(vals: Array) -> void: + var h := HBoxContainer.new() + for i in _cols.size(): + var c: Dictionary = _cols[i] + var lbl := String(c.get("label", "")) + if lbl != "": + var l := Label.new(); l.text = lbl + h.add_child(l) + var sp := SpinBox.new() + sp.min_value = c.get("min", 0) + sp.max_value = c.get("max", 100000) + sp.step = c.get("step", 1) + sp.value = float(vals[i]) if i < vals.size() else float(c.get("default", c.get("min", 0))) + sp.size_flags_horizontal = Control.SIZE_EXPAND_FILL + h.add_child(sp) + var del := Button.new() + del.text = "🗑" + del.pressed.connect(func(): _rows_box.remove_child(h); h.queue_free()) + h.add_child(del) + _rows_box.add_child(h) From 3b4a5f674c0204963039f1d38b02f72808e15d4b Mon Sep 17 00:00:00 2001 From: Joywayer Date: Wed, 22 Jul 2026 12:15:19 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat(designer):=20Core=20=E7=94=B5=E8=B7=AF?= =?UTF-8?q?=E8=BE=B9=E6=94=B9=E8=A1=8C=E7=BC=96=E8=BE=91=E5=99=A8=EF=BC=88?= =?UTF-8?q?=E5=8E=BB=20JSON=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/game_designer/core_tab.gd | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/addons/game_designer/core_tab.gd b/addons/game_designer/core_tab.gd index 640fc32..698a07c 100644 --- a/addons/game_designer/core_tab.gd +++ b/addons/game_designer/core_tab.gd @@ -22,7 +22,7 @@ var _mana_leech: SpinBox var _feat: OptionButton var _rows: SpinBox var _cols: SpinBox -var _edges: TextEdit +var _edges var _status: Label func _ready() -> void: @@ -49,9 +49,11 @@ func _ready() -> void: _rows = _row("矩阵行(MATRIX)", UI.spin(1, 8, 1, 1)) _cols = _row("矩阵列(MATRIX)", UI.spin(1, 16, 1, 5)) add_child(Label.new()) - var el := Label.new(); el.text = "电路边(CIRCUIT,JSON)"; add_child(el) - _edges = TextEdit.new(); _edges.custom_minimum_size = Vector2(0, 50) - _edges.placeholder_text = '[{"from":0,"to":1},{"from":0,"to":2}]' + var el := Label.new(); el.text = "电路边(CIRCUIT,from → to)"; add_child(el) + _edges = preload("res://addons/game_designer/tuple_list_editor.gd").new() + _edges.setup([ + {"label": "from", "min": 0, "max": 63, "step": 1, "int": true}, + {"label": "→ to", "min": 0, "max": 63, "step": 1, "int": true}], "➕ 加边") add_child(_edges) add_child(HSeparator.new()) var srow := HBoxContainer.new(); add_child(srow) @@ -93,15 +95,18 @@ func _on_select(idx: int) -> void: _feat.selected = int(d.get("feature_tags", 0)) _rows.value = float(d.get("grid_rows", 1)) _cols.value = float(d.get("grid_cols", 5)) - _edges.text = JSON.stringify(d.get("edges", [])) + var erows := [] + for e in d.get("edges", []): + erows.append([int(e.get("from", 0)), int(e.get("to", 0))]) + _edges.set_values(erows) func _on_apply() -> void: var cid: String = _id.text.strip_edges() if cid == "": UI.set_status(_status, "✗ ID 不能为空", true); return - var edges = JSON.parse_string(_edges.text) if _edges.text.strip_edges() != "" else [] - if not (edges is Array): - edges = [] + var edges := [] + for r in _edges.get_values(): + edges.append({"from": r[0], "to": r[1]}) if _cur != "" and _cur != cid and _data.has(_cur): _data.erase(_cur) _data[cid] = { From 04b678167895b5b3402095c459c806dc45c015ca Mon Sep 17 00:00:00 2001 From: Joywayer Date: Wed, 22 Jul 2026 12:17:33 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat(designer):=20=E5=B9=B3=E8=A1=A1?= =?UTF-8?q?=E7=A2=8E=E7=89=87=E9=98=88=E5=80=BC=E6=94=B9=E8=A1=8C=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=99=A8=EF=BC=88=E5=8E=BB=20JSON=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/game_designer/balance_tab.gd | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/addons/game_designer/balance_tab.gd b/addons/game_designer/balance_tab.gd index ae941aa..ef49423 100644 --- a/addons/game_designer/balance_tab.gd +++ b/addons/game_designer/balance_tab.gd @@ -12,7 +12,7 @@ var _data: Dictionary = {} var _mult_spins: Dictionary = {} # key → [SpinBox ×3] var _miniboss: SpinBox var _boss: SpinBox -var _aether: TextEdit +var _aether var _status: Label func _ready() -> void: @@ -46,10 +46,13 @@ func _ready() -> void: _boss = UI.spin(1, 999999, 10, float(bhp.get("5", 1800))) h2.add_child(_boss) add_child(HSeparator.new()) - var al := Label.new(); al.text = "碎片奖励阈值 aether_thresholds(JSON [[波次,碎片],...])"; add_child(al) - _aether = TextEdit.new(); _aether.custom_minimum_size = Vector2(0, 50) - _aether.text = JSON.stringify(_data.get("aether_thresholds", [[1, 0], [5, 3], [10, 8], [15, 14], [20, 20]])) + var al := Label.new(); al.text = "碎片奖励阈值 aether_thresholds(波次 → 碎片)"; add_child(al) + _aether = preload("res://addons/game_designer/tuple_list_editor.gd").new() + _aether.setup([ + {"label": "波次", "min": 1, "max": 9999, "step": 1, "int": true}, + {"label": "碎片", "min": 0, "max": 9999, "step": 1, "int": true}], "➕ 加行") add_child(_aether) + _aether.set_values(_data.get("aether_thresholds", [[1, 0], [5, 3], [10, 8], [15, 14], [20, 20]])) add_child(UI.btn("💾 保存 balance.json", _save)) _status = UI.status_label(); add_child(_status) @@ -62,9 +65,7 @@ func _save() -> void: for key in MULT_KEYS: var spins: Array = _mult_spins[key] mults[key] = [spins[0].value, spins[1].value, spins[2].value] - var thresholds = JSON.parse_string(_aether.text) if _aether.text.strip_edges() != "" else [] - if not (thresholds is Array): - thresholds = [] + var thresholds = _aether.get_values() var out := { "difficulty_mults": mults, "boss_hp": {"4": _miniboss.value, "5": _boss.value}, From 3b36c6e20a505a2ed99e06618bbce6bf23271f8d Mon Sep 17 00:00:00 2001 From: Joywayer Date: Wed, 22 Jul 2026 12:27:24 +0800 Subject: [PATCH 5/5] =?UTF-8?q?chore(designer):=20=E8=BF=BD=E8=B8=AA=20tup?= =?UTF-8?q?le=5Flist=5Feditor.gd.uid=EF=BC=88=E4=B8=8E=E5=85=B6=E5=AE=83?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E4=B8=80=E8=87=B4=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/game_designer/tuple_list_editor.gd.uid | 1 + 1 file changed, 1 insertion(+) create mode 100644 addons/game_designer/tuple_list_editor.gd.uid diff --git a/addons/game_designer/tuple_list_editor.gd.uid b/addons/game_designer/tuple_list_editor.gd.uid new file mode 100644 index 0000000..4e1bb89 --- /dev/null +++ b/addons/game_designer/tuple_list_editor.gd.uid @@ -0,0 +1 @@ +uid://c2bkt1s3rrk24