Skip to content

敌人预设系统文档

概述

本项目实现了类似 LuaSTG 的敌人预设系统(style system),通过预先定义的配置文件快速创建具有特定外观和行为的敌人。这个系统将外观配置行为编写解耦,让内容创作更加高效。

核心概念

三种预设类型

  1. 敌人预设(Enemy Presets)

    • 定义敌人的外观、生命值、得分等基础属性
    • 类似 LuaSTG 的 style 参数(1-18数字ID)
    • 示例:fairy_red, orb_blue, ghost_fire_red
  2. 行为预设(Behavior Presets)

    • 定义敌人的行动模式(进场-射击-离开等)
    • 可复用的行为流程
    • 示例:rush_in_shoot_leave, side_pass_shoot, dive_attack
  3. 攻击预设(Attack Presets)

    • 定义弹幕发射模式
    • 可组合的攻击方式
    • 示例:burst_8way, aimed_3shot, spiral_dense

使用方式

方式1: 预设 + 自定义行为(最灵活)

python
from src.game.stage.preset_enemy import PresetEnemy

class CustomRedFairy(PresetEnemy):
    preset_id = "fairy_red"  # 指定预设ID

    async def run(self):
        # 自定义行为逻辑
        await self.move_to(self.x, 0.3, duration=60)

        # 使用预设的默认参数
        self.fire_circle(
            count=8,
            speed=self.defaults['move_speed'],
            bullet_type=self.defaults['bullet_type'],
            color=self.defaults['bullet_color']
        )

        await self.wait(60)
        await self.move_to(self.x, -0.2, duration=60)

优点:完全自定义行为,同时享受预设的外观配置 适用场景:需要独特行为的敌人

方式2: 预设 + 行为预设(最简单)

python
from src.game.stage.preset_enemy import PresetEnemy

class AutoRedFairy(PresetEnemy):
    preset_id = "fairy_red"
    behavior_preset = "rush_in_shoot_leave"
    # 无需写 run() 方法!

优点:一行代码创建敌人,零行为代码 适用场景:标准的杂兵敌人

方式3: 动态创建(最适合编辑器)

python
from src.game.stage.preset_enemy import create_preset_enemy

# 在编辑器中根据用户选择动态创建
EnemyClass = create_preset_enemy(
    preset_id="fairy_blue",
    behavior="side_pass_shoot",
    overrides={"hp": 50, "score": 200}  # 可选:覆盖默认值
)

enemy = EnemyClass()

优点:运行时动态创建,适合编辑器/工具使用 适用场景:可视化编辑器、关卡生成器

配置文件结构

配置文件位置:assets/configs/enemy_presets.json

敌人预设示例

json
{
  "fairy_red": {
    "name": "红色妖精",
    "sprite": "enemy_fairy_red",
    "hp": 30,
    "score": 100,
    "hitbox_radius": 0.02,
    "drop": "power_small",
    "defaults": {
      "bullet_type": "ball_s",
      "bullet_color": "red",
      "move_speed": 2.0,
      "fire_rate": 20
    }
  }
}

行为预设示例

json
{
  "rush_in_shoot_leave": {
    "name": "冲入-射击-离开",
    "description": "从屏幕顶部飞入,停顿射击,然后飞出",
    "phases": [
      {"action": "move_to", "params": {"target": "y=0.3", "duration": 60}},
      {"action": "shoot_burst", "params": {"count": 3, "interval": 20}},
      {"action": "move_to", "params": {"target": "y=-0.2", "duration": 60}}
    ]
  }
}

工具脚本

列出所有预设

bash
python tools/enemy/list_presets.py

输出:

==============================================================
  可用的敌人预设
==============================================================
  • fairy_red           → 红色妖精 (HP:30, 得分:100)
  • fairy_blue          → 蓝色妖精 (HP:30, 得分:100)
  • orb_red             → 红色幽灵球 (HP:50, 得分:200)
  ...

==============================================================
  可用的行为预设
==============================================================
  • rush_in_shoot_leave → 冲入-射击-离开
    从屏幕顶部飞入,停顿射击,然后飞出
  • side_pass_shoot     → 横向掠过射击
    从侧面横向飞过,边移动边射击
  ...

查看预设详情

bash
python tools/enemy/list_presets.py --detail fairy_red

导出为编辑器JSON

bash
python tools/enemy/list_presets.py --export editor_presets.json

生成的JSON可直接用于编辑器UI的下拉菜单。

生成使用代码

bash
python tools/enemy/list_presets.py --usage fairy_red --behavior rush_in_shoot_leave

自动生成可复制粘贴的示例代码。

预设属性说明

敌人预设属性

属性类型说明示例
namestring友好名称"红色妖精"
spritestring精灵ID"enemy_fairy_red"
hpint生命值30
scoreint击破得分100
hitbox_radiusfloat碰撞半径0.02
dropstring掉落物品"power_small"
defaultsobject默认参数见下表

defaults 对象

属性说明示例
bullet_type弹幕类型"ball_s"
bullet_color弹幕颜色"red"
move_speed移动速度2.0
fire_rate射击间隔(帧)20

行为预设阶段动作

动作参数说明
move_totarget, duration移动到目标位置
move_lineardx, dy, duration线性移动
move_circleradius, duration, center圆形移动
shoot_burstcount, interval连发弹幕
shoot_continuouscount, interval持续射击
shoot_patternpattern, count发射弹幕模式
waitduration等待帧数

可用的预设列表

敌人预设

ID名称HP得分特点
fairy_red红色妖精30100基础杂兵
fairy_blue蓝色妖精30100基础杂兵
fairy_green绿色妖精35150稍强杂兵
orb_red红色幽灵球50200中型敌人
orb_blue蓝色幽灵球50200中型敌人
ghost_fire_red红色火焰幽灵80300强敌
ghost_fire_blue蓝色火焰幽灵80300强敌
kedama_pink粉色毛玉2050快速小型敌人

行为预设

ID名称描述
rush_in_shoot_leave冲入-射击-离开最经典的杂兵模式
side_pass_shoot横向掠过射击从侧面横向飞过
circle_strafe环绕射击以圆形路径移动
dive_attack俯冲攻击快速俯冲到底部
ambush_retreat突袭-撤退快速飞入后撤退

编辑器集成建议

UI 组件设计

敌人创建器界面示意图

数据流

性能和最佳实践

✅ 推荐做法

  1. 复用预设:为常见敌人类型创建预设,避免重复代码
  2. 组合优于继承:使用行为预设组合而非深度继承
  3. 预加载配置:在游戏启动时加载预设文件,而非每次创建敌人时加载
  4. 命名规范:预设ID使用 snake_case,类名使用 PascalCase

❌ 避免做法

  1. 过度抽象:不要为每个细微差别都创建新预设
  2. 硬编码配置:避免在代码中硬编码敌人属性
  3. 循环依赖:行为预设不应相互引用

扩展和自定义

添加新的敌人预设

  1. 编辑 assets/configs/enemy_presets.json
  2. presets 节添加新条目
  3. 运行 python tools/enemy/list_presets.py 验证

添加新的行为预设

  1. 编辑 assets/configs/enemy_presets.json
  2. behavior_presets 节添加新条目
  3. 如需新动作类型,在 PresetEnemy._execute_behavior_preset() 中添加处理逻辑

创建自定义动作

python
# 在 PresetEnemy 类中添加新方法
async def _execute_my_custom_action(self, params: Dict[str, Any]):
    """自定义动作"""
    # 实现你的动作逻辑
    pass

# 然后在 _execute_behavior_preset() 中注册
elif action == 'my_custom_action':
    await self._execute_my_custom_action(params)

与 LuaSTG 的对比

特性LuaSTG本项目
预设标识数字ID (1-18)字符串ID ("fairy_red")
配置存储Lua代码JSON文件
行为定义手写任务函数预设+类方法
动态创建✓ 支持
编辑器友好✓ 高度友好
类型安全✓ Python类型提示

示例代码

完整示例请查看:

  • game_content/stages/stage1/enemies/preset_examples.py

故障排除

问题:找不到预设

错误ValueError: 未找到预设: xxx

解决

  1. 确认 assets/configs/enemy_presets.json 存在
  2. 运行 python tools/enemy/list_presets.py 查看可用预设
  3. 检查预设ID拼写

问题:行为预设不执行

原因:子类覆盖了 run() 方法

解决

python
# 错误 ❌
class MyEnemy(PresetEnemy):
    preset_id = "fairy_red"
    behavior_preset = "rush_in_shoot_leave"

    async def run(self):  # 这会覆盖默认行为!
        pass

# 正确 ✅
class MyEnemy(PresetEnemy):
    preset_id = "fairy_red"
    behavior_preset = "rush_in_shoot_leave"
    # 不要覆盖 run(),让基类处理

Released under the MIT License.