初次提交
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
# 02 内容创作指南 (Content Authoring)
|
||||
|
||||
> 策划和程序共同维护的内容文件。所有数值修改无需改架构代码,只改指定位置。
|
||||
|
||||
> ⭐ **策划/美术优先用可视化工具**:[07 游戏设计器](07_game_designer.md) 提供编辑器内一站式面板(法术/敌人/波次/Core/平衡),表单填数值即可,**无需写代码**。本文的代码方式适合需要复杂自定义逻辑的程序员,或了解底层数据结构。
|
||||
|
||||
---
|
||||
|
||||
## A. 添加/修改法术
|
||||
|
||||
> 💡 **策划优先用可视化工具**:[06 法术编辑器](06_spell_editor.md) 提供编辑器内表单,无需写代码即可新增/编辑法术(保存到 `data/spells.json`)。下面的代码方式适合需要复杂逻辑的程序员。
|
||||
|
||||
### 法术定义位置
|
||||
|
||||
- **数据驱动(推荐)**:`res://data/spells.json`(由法术编辑器维护,启动时由 `SpellRegistry` 加载,优先级最高)
|
||||
- **硬编码(程序)**:`scripts/autoloads/wand_preset.gd`(向后兼容回退)
|
||||
|
||||
### 步骤:添加一个新 ACTION 法术
|
||||
|
||||
**1. 在 `wand_preset.gd` 添加工厂函数**
|
||||
|
||||
```gdscript
|
||||
func make_frost_bolt() -> SpellNode:
|
||||
var n := SpellNode.new()
|
||||
n.id = "action_frost_bolt" # 全局唯一 ID
|
||||
n.type = SpellNode.SpellType.ACTION
|
||||
n.display_name = "SPELL_FROST_BOLT_NAME" # tr() 键(见本地化指南)
|
||||
n.description = "SPELL_FROST_BOLT_DESC"
|
||||
n.element_tags = ["tag:ice"] # 共鸣系统用的元素标签
|
||||
n.meta = {
|
||||
"base_damage": 5.0, # 基础伤害
|
||||
"speed": 380.0, # 弹速 (px/s)
|
||||
"lifetime": 4.0, # 存活时间 (s)
|
||||
"radius": 7.0, # 弹体半径 (px)
|
||||
"damage_type": 0, # 0=通用 (DamageType.NORMAL)
|
||||
"apply_status_id": StatusID.FREEZE, # 命中施加状态(可选)
|
||||
"shop_cost": 22, # 商店价格
|
||||
}
|
||||
return n
|
||||
```
|
||||
|
||||
**2. 注册到 `make_spell_by_id` 和 `get_all_spell_ids`**
|
||||
|
||||
```gdscript
|
||||
func make_spell_by_id(spell_id: String) -> SpellNode:
|
||||
match spell_id:
|
||||
# ... 已有法术 ...
|
||||
"action_frost_bolt": return make_frost_bolt() # 新增
|
||||
_: push_warning(...)
|
||||
|
||||
func get_all_spell_ids() -> Array:
|
||||
return [
|
||||
# ... 已有 ...
|
||||
"action_frost_bolt", # 新增到列表末尾(商店会自动抽取)
|
||||
]
|
||||
```
|
||||
|
||||
**3. 在 `translations/*.po` 四个文件中添加翻译键**(见本地化指南)
|
||||
|
||||
---
|
||||
|
||||
### 支持的法术类型
|
||||
|
||||
| `SpellNode.SpellType` | 说明 | meta 必填键 |
|
||||
|:---|:---|:---|
|
||||
| `ACTION` | 发射弹道 | `base_damage`, `speed`, `lifetime`, `radius` |
|
||||
| `ACTION`(zone) | 地面效果 | `action_kind:"zone"`, `radius`, `status_id`, `duration`, `tick_interval` |
|
||||
| `ACTION`(summon) | 召唤物 | `action_kind:"summon"`, `lifetime`, `range`, `fire_interval`, `base_damage` |
|
||||
| `MODIFIER` | 修改施法参数 | 至少一个:`damage_add`, `damage_mult`, `spread_add`, `speed_mult`, `multicast` |
|
||||
| `TRIGGER` | 命中触发子弹 | `base_damage`, `speed`, `lifetime`, `radius`(触发物自身弹道参数) |
|
||||
| `LOGIC` | 条件/循环 | `logic_op`(见下表)|
|
||||
|
||||
### LOGIC meta 参数
|
||||
|
||||
| `logic_op` | 额外 meta | 效果 |
|
||||
|:---|:---|:---|
|
||||
| `"every_n_shots"` | `n:int`, `reg:0-3` | 每 N 次施法触发 |
|
||||
| `"if_hp_below"` | `threshold:float(0-1)` | HP < 阈值时触发 |
|
||||
| `"if_enemy_nearby"` | `range:float` | 范围内有敌时触发 |
|
||||
| `"loop"` | `count:int(1-16)` | 后续法术重复 N 次 |
|
||||
|
||||
---
|
||||
|
||||
## B. 修改波次配置
|
||||
|
||||
### 波次配置位置
|
||||
|
||||
`scripts/autoloads/wave_manager.gd` → `WAVE_CONFIG: Array`(数组索引 0 = Wave 1)
|
||||
|
||||
### 配置字段说明
|
||||
|
||||
```gdscript
|
||||
{"count": 20, "hp": 15.0, "type": 0, "elite": 0, "gold": 10, "xp": 20, "boss": -1}
|
||||
# count : 本波生成的杂兵数量
|
||||
# hp : 杂兵基础血量(受难度乘子影响)
|
||||
# type : 敌人原型(见下方原型表)
|
||||
# elite : W15+ 带 NavigationAgent2D 寻路的精英数量
|
||||
# gold : 波次结算奖励金币
|
||||
# xp : 波次结算奖励 XP
|
||||
# boss : -1=无;4=Mini Boss;5=Final Boss
|
||||
```
|
||||
|
||||
### 敌人原型(`EnemyManager.Type`)
|
||||
|
||||
| 值 | 名称 | 速度 | 护甲 | 颜色 | 大小 |
|
||||
|:---|:---|:---|:---|:---|:---|
|
||||
| 0 | BASIC | 80 | 0 | 红 | 14px |
|
||||
| 1 | FAST | 140 | 0 | 黄 | 11px |
|
||||
| 2 | ARMORED | 60 | 5 | 灰 | 16px |
|
||||
| 3 | ELITE | 90 | 3 | 橙 | 22px |
|
||||
| 4 | MINIBOSS | 55 | 8 | 品红 | 48px |
|
||||
| 5 | BOSS | 45 | 14 | 深红 | 76px |
|
||||
|
||||
### 示例:修改 W8 Mini Boss 血量
|
||||
|
||||
```gdscript
|
||||
# wave_manager.gd line ~50
|
||||
{"count": 12, "hp": 30.0, "type": 0, "elite": 0, "gold": 80, "xp": 120, "boss": 4},
|
||||
# ↑ boss:4 → _BOSS_HP[4] = 450.0 控制 Boss 血量
|
||||
|
||||
# 修改 Boss 血量,找到下面这行:
|
||||
const _BOSS_HP: Dictionary = {4: 450.0, 5: 1800.0}
|
||||
# 改成你想要的数值
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## C. 修改敌人原型数值
|
||||
|
||||
`scripts/autoloads/enemy_manager.gd` 顶部常量:
|
||||
|
||||
```gdscript
|
||||
const _SPEED: Dictionary = {0: 80.0, 1: 140.0, 2: 60.0, 3: 90.0, 4: 55.0, 5: 45.0}
|
||||
const _ARMOR: Dictionary = {0: 0.0, 1: 0.0, 2: 5.0, 3: 3.0, 4: 8.0, 5: 14.0}
|
||||
```
|
||||
|
||||
直接修改对应值即可,无需改其他代码。
|
||||
|
||||
---
|
||||
|
||||
## D. 修改难度乘子
|
||||
|
||||
`scripts/autoloads/settings_manager.gd`:
|
||||
|
||||
```gdscript
|
||||
func enemy_hp_mult() -> float: return [0.7, 1.0, 1.0][difficulty]
|
||||
func player_dmg_taken_mult()-> float: return [0.7, 1.0, 1.0][difficulty]
|
||||
func wave_count_mult() -> float: return [1.0, 1.0, 1.2][difficulty]
|
||||
func boss_hp_mult() -> float: return [1.0, 1.0, 1.3][difficulty]
|
||||
# 数组格式:[初学者, 标准, 挑战]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## E. 添加共鸣配方
|
||||
|
||||
`scripts/domain/spell_system/spell_evaluator.gd` → `_ready()` → `_resonance_recipes`:
|
||||
|
||||
```gdscript
|
||||
_resonance_recipes = [
|
||||
{
|
||||
"id": "plasma_storm", # 配方 ID
|
||||
"pattern": ["tag:water", "tag:lightning"], # 元素标签组合
|
||||
"match": "adjacent", # "adjacent"=相邻;"anywhere_in_deck"=任意位置
|
||||
"result_spell_id":"action_plasma_storm", # 产物法术 id(须在 WandPreset 中注册)
|
||||
"consume_inputs": true, # true=消耗原始法术插槽
|
||||
},
|
||||
# 新增配方直接追加到这里
|
||||
{
|
||||
"id": "ice_nova",
|
||||
"pattern": ["tag:ice", "tag:water"],
|
||||
"match": "adjacent",
|
||||
"result_spell_id":"action_ice_nova",
|
||||
"consume_inputs": false, # false=原法术保留,额外注入产物
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
> **注意**:产物法术必须同时在 `WandPreset.make_spell_by_id()` 中注册,才能被 `SpellRegistry` 识别。
|
||||
|
||||
---
|
||||
|
||||
## F. 添加/修改状态效果
|
||||
|
||||
### 现有状态 ID(`scripts/autoloads/status_id.gd`)
|
||||
|
||||
```gdscript
|
||||
const BURN = 1 # 燃烧 DoT(火系)
|
||||
const FREEZE = 2 # 冻结(硬控)
|
||||
const POISON = 3 # 中毒(可叠层 DoT)
|
||||
const WET = 4 # 潮湿
|
||||
const OILY = 5 # 油腻
|
||||
const STUN = 6 # 麻痹
|
||||
const COMBO_MARK = 7
|
||||
const VULNERABILITY = 8
|
||||
# 新增从 9 开始递增
|
||||
```
|
||||
|
||||
### 状态数值定义(`.tres` 资源,目前占位代码生成)
|
||||
|
||||
当前 `StatusRegistry` 在 `_ready()` 扫描 `res://resources/status_types/` 目录。若不存在资源文件,会尝试从 `WandPreset` 或内置回退。添加新状态的完整流程:
|
||||
|
||||
1. 在 `status_id.gd` 追加常量(从 9 起)
|
||||
2. 在 `StatusTypeDef` 对象中配置 tick_interval / stack_mode / max_stacks
|
||||
3. 在状态数值生效的 `can_catalyze` 字段填写对应状态 ID 列表
|
||||
4. 在四个 `.po` 文件中添加 `STATUS_新状态_NAME` 等翻译键
|
||||
|
||||
---
|
||||
|
||||
## G. 添加 Core(法杖类型)
|
||||
|
||||
```gdscript
|
||||
# wand_preset.gd 中添加:
|
||||
func make_staff_long() -> CoreDefinition:
|
||||
var c := CoreDefinition.new()
|
||||
c.id = "staff_long"
|
||||
c.display_name = "CORE_STAFF_LONG_NAME" # tr() 键
|
||||
c.slot_count = 10 # 插槽数
|
||||
c.topology = CoreDefinition.Topology.LINEAR
|
||||
c.cpu_limit = 10
|
||||
c.cast_interval = 0.7
|
||||
return c
|
||||
```
|
||||
|
||||
然后在 `CombatManager._CORE_ROSTER` 中追加 `"staff_long"`,以及在 `_make_core_by_id()` 和 `_default_deck_for()` 中添加对应分支。
|
||||
|
||||
---
|
||||
|
||||
## H. 调试技巧
|
||||
|
||||
### 在运行中检查任意系统状态
|
||||
|
||||
利用 MCP 游戏脚本执行器(或 Godot 调试器表达式):
|
||||
|
||||
```gdscript
|
||||
# 查看当前法术 VM 编译结果
|
||||
var ids = []
|
||||
for nd in SpellEvaluator._equipped_compiled.nodes: ids.append(nd.id)
|
||||
print(ids)
|
||||
|
||||
# 立即杀死所有敌人(测试波次结算)
|
||||
for i in range(EnemyManager.get_active_count()-1, -1, -1):
|
||||
var eid = EnemyManager._slot_entity_map.get(i, -1)
|
||||
if eid >= 0: EnemyManager.apply_damage(eid, 99999.0, -1, false)
|
||||
|
||||
# 给玩家大量金币
|
||||
PlayerStats.gain_gold(9999)
|
||||
```
|
||||
Reference in New Issue
Block a user