Voidloam 回合制卡牌战斗框架拆解
Voidloam 是一个 Godot 4.7.2 mono 加 C# 的回合制卡牌战斗项目,中文界面,角色、卡牌与 Buff 等内容全部放在 assets/defaults/ 的 JSON 里,C# 只定义结构与结算规则,外层再套一局横版远征。
Voidloam 是一个 Godot 4.7.2(.NET / mono)加 C# 的回合制卡牌战斗项目,界面为中文。核心是三人小队对敌方阵容的卡牌战斗:每人一副独立卡组,全队共享行动点与道具。外层是一局横版远征,带 roguelike 性质:随机区域、由手工房间模板拼出的关卡、跑图遇怪、跨战斗保留血量与成长。仓库地址是 https://github.com/Hgnim/Voidloam。
数据与代码的分工
这个项目最鲜明的取向,是游戏内容与代码的分离。角色、敌人、卡牌、Buff、道具、状态牌、关卡、房间、区域、法则与升级曲线,全部放在 assets/defaults/ 的 JSON 里;C# 只定义结构、读写与结算规则。内容随仓库走,导出时会打进包里。编辑器在开发者模式下写这里,普通模式写玩家存档 user://roster/。
游戏内容都在 assets/defaults/ 的 JSON 里,C# 只定义结构、读写与结算规则。
技术栈上,引擎是 Godot 4.7.2 stable mono(.NET 版),C# 使用 Godot.NET.Sdk/4.7.2、目标框架 net8.0、RootNamespace = CardBattle,程序集名为 CardBattleFramework,并且 project.godot 里的 dotnet/project/assembly_name 必须与之一致。分辨率为 1280x720,使用 canvas_items 拉伸,主场景是 res://scenes/main_menu.tscn,自动加载 GameState 与 Sfx。
回合与战斗规则
TurnManager 每回合固定走 DRAW、MAIN、END 三个阶段。行动队列按方成块:一方全部单位行动完,才换另一方;速度既决定先手方,也决定队内出手顺序。轮到某个角色时,切换到他的牌堆并抽起手牌,默认 5 张且可按角色配置,手牌上限 12,回合结束弃掉剩余手牌。行动点上限按出战人数取值:1 人 5 点、2 人 8 点、3 人 10 点。
一些边界规则同样由数据与结算层共同约束:skills.json 的 cards 进抽牌堆,customSkills 不进牌堆,点指令盘的 SKILL 使用,可以带冷却与前置条件;状态牌(例如「熔断」)不可打出,进销毁堆,不参与洗牌;道具全队每回合限用一件,不消耗行动点,用完立刻结束当前角色的行动。攻击、防御、力量、易伤、虚弱等按百分比结算,最终伤害取整一次,百分比伤害无视防御。敌人 AI 也是数据驱动的:每个敌人一组招式,每条带权重、冷却、触发条件与目标选择器。
中文效果 DSL
卡牌、技能与 Buff 的效果写成一行一条的中文文本,由 src/core/CustomSkill.cs 里的 SkillDsl 解析。README 给出的真实例子包括「伤害 12」「伤害 12 两段」「对全体敌人 伤害 6」与「自身 施加 力量 2」。指令包括伤害、真实伤害、百分比伤害、格挡、治疗、力量、易伤、虚弱、眩晕、反击、净化、驱散、抽牌、行动点、暴击、免伤、吸血、塞牌、引爆与消耗。
行首可以带目标词,例如自身、对全体敌人、对全队或对全场,也可以用「对最低血量」这类相对目标;还可以用按层加 Buff 名的方式,把数值乘上自身该 Buff 的层数。认不出的行只记录警告并跳过,不影响其余效果。
远征与关卡生成
一局远征的状态在 RunState,对外接口集中在 RunDirector。run.json 的 regions 定义每层的难度缩放、法则、敌人池与数量、物件数量、掉落品质权重以及去向列表。关卡生成由 LevelGenerator 完成:从房间库 rooms.json 里选模板、按图式拼接、在连接段铺平台,生成后自证从入口到出口连通。LevelReach 的 JumpModel 是跳跃手感与生成约束的唯一来源。
存档策略值得单独一提:一局一个文件,写在 user://run/slots/<id>.json 里,而且只存种子;进图时按种子重新生成同一张关卡,再用打掉的怪与开过的物件记账对账。这样存档很小,地图又能稳定复现。
立绘与 moc3 解析
运行时有两套立绘实现,由数据里的模型路径决定。Live2D Cubism Core 位于 src/live2d/,由 native/Live2DCubismCore.dll 驱动,模型目录放 assets/live2d/<模型>/;Inochi2D 位于 src/inochi/,模型是 .inp 与 .inx 单文件,放在 assets/inochi/,包含呼吸、眨眼、表情、动作与物理链条。模型下拉框会把两边的模型都列出来,Live2D 模型可以烘成 .inp。
src/live2d/Moc3Reader.cs、Moc3Keyforms.cs 与 Moc3Evaluator.cs 构成了一套不依赖 Cubism Core 的 moc3 解析与求值实现。不过 README 也明确说明:烘焙链路目前仍使用 Core 采样,去 Cubism Core 化尚未完成。
编辑器与命令行开发参数
从主菜单「编辑器」进入,共 10 页:人物编辑、地图场景、卡牌编辑、配队、Buff 库、敌人编辑、战斗背景、关卡、远征与房间。编辑器会话统一以项目默认值 assets/defaults/ 为数据源,既不读玩家存档,也不写回玩家存档。
开发参数写在 -- 之后,常用的包括:
--autoplay自动打完一整场战斗,--shot=<秒>等指定秒数后截图并退出;--devmode开发者模式,改动写进项目默认值,不碰玩家存档;--stage=<id>与--boss用指定关卡开一场战斗;--run-seed=<种子>与--newrun指定远征种子或强制开新局;--gen-seeds=<N>批量生成远征关卡并验证连通性;--damagetest、--cursetest与--cardtest分别做伤害、诅咒与卡牌特性的自检。
dotnet build
$godot = 'D:\Godot_v4.7.2-stable_mono_win64\Godot_v4.7.2-stable_mono_win64_console.exe'
& $godot --path .
& $godot --path . res://scenes/overworld.tscn
& $godot --path . res://scenes/battle.tscn
& $godot --path . res://scenes/editor_hub.tscn出包同样只有两条脚本:
dotnet build
pwsh tools/build_game.ps1
pwsh tools/export.ps1边界与现状
README 对边界说得很清楚:去 Cubism Core 化尚未完成,运行时保留 Live2D 路径,把 Live2D 模型烘成 .inp 也仍用 Core 采样;关卡生成算法一旦改动,同一颗种子会长出不同的地图,需要同步提升 RunState.LevelGenVersion。导出时 include_filter 要包含 native/、assets/live2d/、assets/inochi/ 与 assets/defaults/,原生 DLL 要放在 exe 旁边,读文件要走 FileAccess,因为 System.IO 读不到 pck 里的内容。
项目源码在 https://github.com/Hgnim/Voidloam,想验证上述设计可以直接对着代码读。
