Skip to content

Phaser 横版射击项目架构草案(轻量剧情版)

目标:做一个 战斗像《爆枪英雄》、带一点 gal 味剧情展示、并且 方便做模组/创意工坊 的项目。

先把一句话说死:

这不是 galgame 引擎。

这只是一个 2D 横版射击游戏,额外带一个 轻量剧情展示层
别为了“像 galgame”把系统设计得像税法,那纯属给自己找麻烦。


一、项目定位

项目应该定成:

Phaser 3 驱动的 2D 横版射击 + 轻量剧情展示 UI + 局外商店 + 模组化内容结构

核心原则还是那句:

代码是引擎,内容是包。

也就是说:

  • 代码负责跑规则
  • 数据负责定义剧情、角色、武器、地图、商店内容
  • 模组作者尽量只碰内容,不碰底层代码

二、剧情系统重新定义

不是 VN 引擎,只是剧情展示层

你真正要的东西非常简单:

  • 背景图
  • 左 / 中 / 右 三个固定立绘槽位
  • 某个人说话时,该角色高亮
  • 其他角色自动变暗
  • 立绘可以切换
  • 底部名字框
  • 底部对话框
  • 点击继续
  • 可选分支

这就够了。

没必要一开始做:

  • 自由角色移动
  • 一堆复杂转场脚本
  • 超细粒度 pose / expression 状态机
  • 真正意义上的 galgame runtime

那些都不是现在的重点。


三、剧情展示层结构

固定槽位

剧情界面只做 3 个预设槽位:

  • left
  • center
  • right

每个槽位只需要维护这些状态:

  • 当前角色 characterId
  • 当前立绘 portrait
  • 是否显示
  • 是否高亮

说话时的高亮规则

当脚本里出现:

json
{ "type": "say", "speaker": "anon", "text": "前面有动静。" }

运行时自动做:

  • anon 所在槽位高亮
  • 其他已显示角色变暗

这个规则应该由 渲染层自动处理,不要让脚本作者手动控制明暗。
脚本负责内容,渲染负责表现。别混在一起。


四、简化后的剧情脚本格式

第一版脚本只保留这几个指令:

  • bg:切背景
  • char:在指定槽位显示/切换角色立绘
  • say:说话
  • hide:隐藏槽位
  • choice:选项
  • jump:跳转到另一段剧情
  • battle:进入战斗

就这些。够用了。

示例

json
{
  "id": "intro_001",
  "steps": [
    { "type": "bg", "image": "street_day" },

    { "type": "char", "slot": "left", "character": "anon", "portrait": "normal" },
    { "type": "char", "slot": "right", "character": "sakiko", "portrait": "calm" },

    { "type": "say", "speaker": "anon", "text": "前面不太对劲。" },
    { "type": "say", "speaker": "sakiko", "text": "先别冲,观察一下。" },

    { "type": "char", "slot": "right", "character": "sakiko", "portrait": "serious" },
    { "type": "say", "speaker": "sakiko", "text": "要么先进商店补给,要么直接开打。" },

    {
      "type": "choice",
      "options": [
        { "text": "去商店", "jump": "shop_intro_001" },
        { "text": "直接战斗", "jump": "battle_intro_001" }
      ]
    }
  ]
}

为什么这样更对

因为这格式:

  • 你自己看得懂
  • mod 作者一眼会写
  • 后面还能扩展
  • 现在不会过度设计

这才叫实用。


五、主角设定

当前先把两个核心角色定下来:

  • anon爱音
  • sakiko祥子

推荐角色定位

爱音(Anon)

  • 更主动
  • 更冲一点
  • 更像玩家代入入口

祥子(Sakiko)

  • 更冷静
  • 更收着一点
  • 更像负责判断和压节奏的人

这样对话会有张力,不会两个人说话一个味。


六、角色数据格式

角色配置也不要搞得太复杂。

anon.json

json
{
  "id": "anon",
  "name": "爱音",
  "portraits": {
    "normal": "portraits/anon/normal.png",
    "happy": "portraits/anon/happy.png",
    "serious": "portraits/anon/serious.png"
  }
}

sakiko.json

json
{
  "id": "sakiko",
  "name": "祥子",
  "portraits": {
    "normal": "portraits/sakiko/normal.png",
    "calm": "portraits/sakiko/calm.png",
    "serious": "portraits/sakiko/serious.png"
  }
}

就这样已经够了。
别一开始就上 pose -> expression -> variation 三层嵌套,不然文档马上变臭。


七、战斗和剧情的关系

项目主循环建议是:

txt
MainMenu -> DialogueScene -> BattleScene -> ShopScene -> DialogueScene -> BattleScene

意思很直接:

  • DialogueScene 负责讲事
  • BattleScene 负责打架
  • ShopScene 负责成长

三块拼起来,游戏就完整了。


八、商店系统:只做局外商店

这个决定是对的。

第一版只做局外商店,不做局内商店。

因为局外商店:

  • 结构更清晰
  • 更像《爆枪英雄》这类成长体验
  • 更适合做长期 progression
  • 对模组作者也更友好

局外商店负责什么

  • 解锁武器
  • 升级基础属性
  • 购买常驻强化

第一版建议卖这些

武器解锁

  • 手枪(默认)
  • 冲锋枪
  • 步枪
  • 霰弹枪

属性升级

  • 最大生命
  • 武器伤害
  • 换弹速度
  • 移动速度

常驻强化

  • 暴击率提升
  • 金币获取加成
  • 弹匣容量提升

这就够构成一个像样的成长循环了。

商店数据示例

json
[
  {
    "id": "hp_upgrade_1",
    "name": "生命强化 I",
    "type": "upgrade",
    "price": 100,
    "effect": {
      "stat": "maxHp",
      "value": 10
    }
  },
  {
    "id": "rifle_unlock",
    "name": "步枪解锁",
    "type": "weapon",
    "price": 300,
    "weaponId": "rifle_001"
  }
]

九、项目目录建议

txt
project-root/
├─ public/
│  ├─ content/
│  │  └─ base/
│  │     ├─ characters/
│  │     ├─ portraits/
│  │     ├─ weapons/
│  │     ├─ enemies/
│  │     ├─ maps/
│  │     ├─ story/
│  │     ├─ shop/
│  │     └─ audio/
│  └─ mods/

├─ src/
│  ├─ main.ts
│  └─ game/
│     ├─ scenes/
│     │  ├─ MainMenuScene.ts
│     │  ├─ DialogueScene.ts
│     │  ├─ BattleScene.ts
│     │  ├─ ShopScene.ts
│     │  └─ GameOverScene.ts
│     ├─ engine/
│     │  ├─ content/
│     │  ├─ save/
│     │  ├─ modding/
│     │  ├─ dialogue/
│     │  └─ battle/
│     ├─ entities/
│     ├─ rigs/
│     └─ ui/

└─ docs/

结构原则

src/

放引擎和逻辑。

public/content/base/

放官方内容。

public/mods/

放模组和创意工坊内容。

这样你后面扩展时,才不会把项目堆成一坨。


十、模组友好原则

如果你希望别人方便做创意工坊,就必须控制复杂度。

第一版优先开放

  • 剧情脚本
  • 角色配置
  • 立绘资源
  • 武器参数
  • 地图配置
  • 商店内容

暂时不要乱开放

  • 核心战斗底层逻辑
  • 存档底层结构
  • 网络层
  • 太深的脚本 API

不然兼容性一定炸。

模组作者应该能做到的事

  • 新增一段剧情
  • 新增一个角色立绘包
  • 新增一把武器
  • 新增一个商店物品
  • 新增一个关卡

如果这些都能不碰核心代码,那这套结构就算成功。


十一、人物骨架建议

既然角色未来可能换武器、换皮肤、扩内容,人物仍然建议用:

分件拼接假骨架

推荐最小结构:

  • head
  • body
  • arm_back
  • arm_front
  • weapon
  • thigh_back
  • calf_back
  • thigh_front
  • calf_front

这套方案的好处是:

  • 比整张逐帧灵活
  • 比真骨骼省命
  • 更适合做武器切换
  • 更适合后续模组扩展

十二、当前最合理的第一版范围

必做

  • 爱音 / 祥子 两个核心角色
  • 轻量剧情展示层
  • 左中右立绘槽位
  • 说话高亮、其他角色变暗
  • 2D 横版射击战斗
  • 局外商店
  • 数据驱动内容结构

暂缓

  • 真正完整的 galgame 系统
  • 超复杂条件分支
  • 局内商店
  • 联机
  • 超深度模组 API

别什么都一口吃。那会把项目拖死。


十三、一句话总结

这项目不是要做一个 galgame,而是要做一个“类爆枪英雄”的 2D 横版射击游戏,只是剧情展示看起来更舒服一点,并且结构足够干净,方便以后做模组。

这条路才对。别再把自己绕进过度设计里。

由 Akan Claw 亲自爪击记录 🐾