用途
本技能用于在 Bevy 引擎中实现角色能力(ability)系统,处理能力的授予、冷却与消耗。当某个角色需要授予、冷却或消耗一项能力时加载本技能。战斗结算不属于本技能范围,仍由 bevy-combat-system 负责。
主要能力
- 能力定义:通过一个 Resource 目录(catalog)加施法者身上的组件行来表示。
- 冷却:在 FixedUpdate 中使用 Time<Fixed>::delta_secs 递减剩余冷却时间。
- 施放:在冷却与充能门槛通过后,通过 MessageWriter<CastAccepted> 发出消息。
- 充能:冷却结束且未达上限时恢复充能次数。
- 全局冷却:共享锁放在 Resource 中,由单一系统持有。
- 状态效果叠加:作为组件列表在 FixedUpdate 中逐帧推进。
ECS 结构
- 组件:施法者身上的能力 id、充能次数、剩余冷却时间。
- 资源:全局范围的表存放在 Resource 中(参见 bevy-data-resources)。
- 系统:在 Update 或固定时间步上修改这些组件;当伤害必须先于死亡结算时使用 .chain()。
- 消息:一次性事实(命中、拾取、任务推进)通过 bevy-events-messaging 传递;本文件不新增事件类型名称。
使用方式
示例依赖:
[package]
name = "abilities"
version = "0.1.0"
edition = "2021"
[dependencies]
bevy = "0.20"
冷却与充能共享施法者,在 FixedUpdate 上先推进再接受施放:
#[derive(Component)]
struct Cooldown {
remaining: f32,
duration: f32,
}
#[derive(Component)]
struct Charges {
current: u32,
max: u32,
}
#[derive(Message)]
struct CastAccepted {
caster: Entity,
}
fn tick_cooldowns(time: Res<Time<Fixed>>, mut query: Query<&mut Cooldown>) {
let dt = time.delta_secs();
for mut cooldown in &mut query {
cooldown.remaining = (cooldown.remaining - dt).max(0.0);
}
}
fn try_cast(
mut casters: Query<(Entity, &mut Cooldown, &mut Charges)>,
mut casts: MessageWriter<CastAccepted>,
) {
for (entity, mut cooldown, mut charges) in &mut casters {
if cooldown.remaining > 0.0 || charges.current == 0 {
continue;
}
charges.current -= 1;
cooldown.remaining = cooldown.duration;
casts.write(CastAccepted { caster: entity });
}
}
fn recharge(time: Res<Time<Fixed>>, mut casters: Query<(&Cooldown, &mut Charges)>) {
let dt = time.delta_secs();
for (cooldown, mut charges) in &mut casters {
if cooldown.remaining <= 0.0 && charges.current < charges.max && dt > 0.0 {
charges.current += 1;
}
}
}
pub struct AbilityPlugin;
impl Plugin for AbilityPlugin {
fn build(&self, app: &mut App) {
app.add_message::<CastAccepted>()
.add_systems(FixedUpdate, (tick_cooldowns, try_cast, recharge).chain());
}
}
目录是一个资源,实时冷却保留在实体上:
#[derive(Clone, Copy)]
struct AbilityDef {
id: u32,
cooldown: f32,
cost: u32,
}
#[derive(Resource)]
struct AbilityCatalog {
rows: Vec<AbilityDef>,
}
fn lookup(catalog: &AbilityCatalog, id: u32) -> Option<&AbilityDef> {
catalog.rows.iter().find(|row| row.id == id)
}
#[derive(Component)]
struct Cooldown {
remaining: f32,
duration: f32,
}
#[derive(Component)]
struct Charges {
current: u32,
max: u32,
}
fn spawn_caster(mut commands: Commands, catalog: Res<AbilityCatalog>) {
let def = lookup(&catalog, 1);
let duration = def.map(|row| row.cooldown).unwrap_or(0.5);
commands.spawn((
Cooldown {
remaining: 0.0,
duration,
},
Charges { current: 2, max: 2 },
));
}
共享锁放在资源中,由单一系统持有:
#[derive(Message)]
struct CastAccepted {
caster: Entity,
}
#[derive(Resource)]
struct GlobalCooldown {
remaining: f32,
}
fn tick_gcd(time: Res<Time<Fixed>>, mut gcd: ResMut<GlobalCooldown>) {
gcd.remaining = (gcd.remaining - time.delta_secs()).max(0.0);
}
fn arm_gcd(mut gcd: ResMut<GlobalCooldown>, mut casts: MessageReader<CastAccepted>) {
for _cast in casts.read() {
gcd.remaining = gcd.remaining.max(0.4);
}
}
在添加 tick_gcd 与 arm_gcd 的同一插件中,用 add_message 注册 CastAccepted。
状态归属
| 部分 | 归属 | 谁可修改 | 调度 |
|---|---|---|---|
| 单个实体上的数据 | Component | 一个系统通过 Query | Update 或 FixedMain |
| 整个应用的一个值 | Resource | 一个系统 | Startup 插入,之后由读取它的调度 |
| 生成 | Commands | 生成系统 | 初始世界用 Startup;运行时生成用之后的调度 |
| 不可竞态的顺序 | .chain() | 仅被链式连接的系统 | 同一调度 |
| 插件边界 | Plugin | build 注册系统与资源 | 应用运行前 |
借用规则:两个都可变查询同一组件的系统必须排序(.chain())或拆分,使只有一个写入。无关系统保持并行。
决策指引
| 如果你需要 | 这样做 | 不要 |
|---|---|---|
| 每实体数据 | Component + Query | 把值存在实体之外 |
| 应用级配置或时钟 | Resource | 把值复制到每个实体 |
| 稳定模拟步长 | FixedMain 与 Fixed 时钟 | 把模拟绑定到原始帧 Update |
| 启动生成 | Startup 中的 Commands | 从渲染系统生成 |
| 非共享状态的跨系统通知 | bevy-events-messaging 中的 Message 或 observer 槽位 | 在本文件中发明新事件类型 |
| 文档集之外的 API | 先查官方文档 | 编造的 crate 或 API |
适用场景
- 需要为角色实现冷却、充能、能力目录的游戏项目。
- 使用 Bevy 0.20+ 与 ECS 架构的项目。
- 需要全局冷却或状态效果叠加的能力系统。
限制与禁止事项
- 不要在文档 URL 中固定 /0.20.0/;链接保持最新,0.20 目标只在正文中说明一次。
- 不要从两个未排序的系统可变查询同一组件。
- 不要在此发明物理、导航、网络或 XR crate。
- 不要把冷却存储在进程级全局静态中。
- 不要使用编造的 API 或未命名的第三方 crate 作为求解方案。
相关技能
前置:bevy-master(枢纽与调度)、bevy-ecs-composition(组件与系统)、bevy-combat-system(命中结算)、bevy-input-handling(施放输入)、bevy-data-resources(表与定义)、bevy-events-messaging(一次性事实)。
补充:bevy-state-machines(模式标志)。
下游/消费者:暂无。
主技能:bevy-master(Bevy 路由)。