用途
本技能是 Bevy 中格斗类型的路由器。领域内的具体工作由下方列出的 Bevy 技能承担,本文件只负责给出格斗玩法在 ECS 中的数据形状与路由关系。它面向本地对战:帧标记、作为数据的判定框,以及一个回合状态。回滚网络代码不在范围内。
主要能力
- 定义格斗类型在 ECS 中的基本形状:组件保存每个实体的种类标记,且是纯数据;本文件不命名新的引擎类型。
- 资源保存全局计数器(分数、波次索引、随机种子),通过 bevy-data-resources 处理。
- 系统在 Update 或来自 bevy-master 的固定时间步上读取这些组件;当后一个系统必须看到前一个系统的结果时,用 .chain() 排序。
- 游戏模式切换走 bevy-state-machines。
使用方式
依赖声明为 bevy = "0.20"。
示例中每个格斗角色保存帧索引、优势帧和生命值,回合时钟是一个资源。输入、帧推进和打击结算共用 Fighter,因此在固定步上串联。
#[derive(Component)]
struct Fighter {
frame: u16,
advantage: i16,
health: i32,
}
#[derive(Component)]
struct Hitbox {
active: bool,
damage: i32,
startup: u16,
active_until: u16,
}
#[derive(Resource)]
struct RoundClock {
frames_left: u32,
}
fn boot(mut commands: Commands) {
commands.insert_resource(RoundClock { frames_left: 60 * 99 });
commands.spawn((
Fighter {
frame: 0,
advantage: 0,
health: 10000,
},
Hitbox {
active: false,
damage: 400,
startup: 4,
active_until: 8,
},
));
}
fn open_hitbox(mut fighters: Query<(&Fighter, &mut Hitbox)>) {
for (fighter, mut hitbox) in &mut fighters {
hitbox.active = fighter.frame >= hitbox.startup && fighter.frame < hitbox.active_until;
}
}
fn advance_frames(mut fighters: Query<&mut Fighter>, mut round: ResMut<RoundClock>) {
for mut fighter in &mut fighters {
fighter.frame = fighter.frame.saturating_add(1);
}
round.frames_left = round.frames_left.saturating_sub(1);
}
fn apply_hits(hitboxes: Query<(Entity, &Hitbox)>, mut fighters: Query<(Entity, &mut Fighter)>) {
let damage: i32 = hitboxes
.iter()
.filter(|(_, box_)| box_.active)
.map(|(_, box_)| box_.damage)
.sum();
if damage == 0 {
return;
}
for (entity, mut fighter) in &mut fighters {
if hitboxes.iter().any(|(src, box_)| box_.active && src == entity) {
continue;
}
fighter.health -= damage;
fighter.advantage = -12;
}
}
fn install(app: &mut App) {
app.add_systems(Startup, boot).add_systems(
FixedUpdate,
(open_hitbox, advance_frames, apply_hits).chain(),
);
}
当回合时钟或任一生命值归零时回合结束,该系统只读取 Fighter 和 RoundClock:
#[derive(Component)]
struct Fighter {
frame: u16,
advantage: i16,
health: i32,
}
#[derive(Resource)]
struct RoundClock {
frames_left: u32,
}
fn round_over(round: Res<RoundClock>, fighters: Query<&Fighter>) -> bool {
round.frames_left == 0 || fighters.iter().any(|fighter| fighter.health <= 0)
}
路由
- bevy-state-machines - 回合与角色模式。
- bevy-combat-system - 打击结算。
- bevy-animation - 动作片段。
- bevy-input-handling - 逐帧输入。
范围
本地帧数据是一个 Fighter 组件(帧索引、优势帧、生命值)加一个 RoundClock 资源。Bevy 没有专门的格斗游戏类型;上面的示例就是数据本身。
专家知识要点
目标:Bevy 0.20+。
核心 ECS 类型:Component、Resource、Query、Commands、Startup、Update、Fixed / FixedMain(bevy::time)、.chain()、Plugin、DefaultPlugins、MinimalPlugins。消息与观察者属于所有权槽位,其 API 见 bevy-events-messaging。除非用 .chain() 对冲突的系统排序,否则系统并行运行。
状态归谁所有:
| 部分 | 所有者 | 谁可修改 | 调度 |
|---|---|---|---|
| 单个实体上的数据 | Component | 通过 Query 的一个系统 | Update 或 FixedMain |
| 整个应用的一个值 | Resource | 一个系统 | Startup 插入,之后由读取它的调度 |
| 生成 | Commands | 执行生成的系统 | 初始世界用 Startup;运行时生成用后续调度 |
| 不能竞态的顺序 | .chain() | 仅被串联的系统 | 同一调度 |
| 插件边界 | Plugin | build 注册系统与资源 | 应用运行之前 |
借用规则:两个系统若都要可变查询同一组件,必须排序(.chain())或拆分,使只有一个写入;无关系统保持并行。这是 ECS 页面的规则,不是对 system-set API 的猜测。
决策表:
| 如果你需要 | 这样做 | 不要 |
|---|---|---|
| 每实体数据 | Component + Query | 一个由所有实体共享的可变数据块 |
| 应用级配置或时钟 | Resource | 把值复制到每个实体上 |
| 稳定的模拟步长 | FixedMain 与 Fixed 时钟 | 把模拟绑在原始帧 Update |
| 启动生成 | Startup 中的 Commands | 从渲染系统生成 |
| 非共享状态的跨系统通知 | bevy-events-messaging 中的消息或观察者槽位 | 在本文件里发明新事件类型 |
| 文档集之外的 API | 阅读官方 Bevy 页面 | 编造的 crate 或 API |
所有权表详见 references/ecs-ownership.md。
禁止事项
- 不要在文档 URL 中固定 /0.20.0/。原因:链接保持在最新版本;0.20 目标在正文中说明一次。
- 不要从两个无序系统可变查询同一组件。原因:除非 .chain() 排序,调度会并行运行系统。
- 不要在此发明物理、导航、网络或 XR crate。原因:本技能只命名有文档记录的 Bevy crate 与模块。
- 不要回滚或网络代码 crate。原因:Bevy 代码保持惯用 ECS,只使用有文档记录的 Bevy API。
- 不要发明格斗类型 API。原因:同上。
- 不要在此挑选物理或网络 crate。原因:同上。
参考
- bevy-master 上的库固定版本保持 0.20.0。官方页面保持在无版本站点上。
- 官方文档:Assets(官方资源目录,未选择第三方 crate)、Examples(最新分支上的示例树)、ECS(Component、系统、Query、Startup、Update 和 .chain())、Plugins(Plugin、DefaultPlugins、MinimalPlugins 和 add_plugins)。
相关技能
前置:bevy-master(ECS 所有权与调度)、bevy-ecs-composition(生成与查询形状)。
互补:bevy-state-machines(回合与角色模式)、bevy-combat-system(打击结算)、bevy-animation(动作片段)、bevy-input-handling(逐帧输入)。
下游/消费者:无。此路由器不拥有第二个实现。
主技能:bevy-master(Bevy 路由器)。