用途
本技能用于在 Bevy 0.20 中实现“收集循环”玩法:玩家或收集者拾取场景中的物体,累计分数,达到配额后触发状态切换(例如进入胜利状态)。当一次运行的核心是“拾取物体并达到某个数量”时,加载本技能。
主要能力
- 可收集物:以标记组件(Component)表示,附带分值。
- 收集者:以标记组件表示。
- 配额:以资源(Resource)保存全局分数与目标配额。
- 拾取检测:通过距离判断(在物理技能提供接触检测之前,重叠检测由使用者自行实现)。
- 每轮每实体只计分一次:由于
Commands::despawn是延迟执行的,同一轮中第二个收集者可能重复计分,因此使用集合记录本轮已拾取的实体。 - 达到配额后写入
NextState,由状态调度在本系统返回后应用状态转换。
使用方式
依赖:
[dependencies]
bevy = "0.20"
核心代码结构(节选自资料):
#[derive(Component)]
struct Collectible {
points: u32,
}
#[derive(Component)]
struct Collector;
#[derive(Resource)]
struct CollectionScore {
points: u32,
quota: u32,
}
#[derive(States, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
enum RunState {
#[default]
Playing,
Won,
}
fn collect_by_distance(
mut commands: Commands,
mut score: ResMut<CollectionScore>,
collectors: Query<&Transform, With<Collector>>,
pickups: Query<(Entity, &Transform, &Collectible)>,
) {
let mut taken = std::collections::HashSet::new();
for collector in &collectors {
for (entity, transform, item) in &pickups {
if taken.contains(&entity) {
continue;
}
let distance = collector.translation.distance(transform.translation);
if distance <= 1.0 {
taken.insert(entity);
score.points += item.points;
commands.entity(entity).despawn();
}
}
}
}
fn reach_quota(score: Res<CollectionScore>, mut next: ResMut<NextState<RunState>>) {
if score.points >= score.quota {
next.set(RunState::Won);
}
}
fn spawn_pickups(mut commands: Commands) {
commands.insert_resource(CollectionScore {
points: 0,
quota: 3,
});
commands.spawn((Collector, Transform::default()));
for index in 0..3 {
commands.spawn((
Collectible { points: 1 },
Transform::from_xyz(index as f32, 0.0, 0.0),
));
}
}
pub struct CollectionPlugin;
impl Plugin for CollectionPlugin {
fn build(&self, app: &mut App) {
app.init_state::<RunState>()
.add_systems(Startup, spawn_pickups)
.add_systems(Update, (collect_by_distance, reach_quota).chain());
}
}
资料还给出了另一种计数写法:
#[derive(Component)]
struct Remaining(u32);
#[derive(Resource, Default)]
struct Quota {
collected: u32,
need: u32,
}
fn tally(mut quota: ResMut<Quota>, mut counters: Query<&mut Remaining>) {
for mut remaining in &mut counters {
if remaining.0 > 0 {
remaining.0 -= 1;
quota.collected += 1;
}
}
}
fn quota_met(quota: Res<Quota>) -> bool {
quota.collected >= quota.need && quota.need > 0
}
适用场景
- 以拾取物品并达到数量为目标的运行(run)。
- 需要全局配额资源与状态切换(如 Playing → Won)的收集类玩法。
限制与注意事项
- 目标版本为 Bevy 0.20+。
- 不要在两个未排序的系统中可变查询同一组件;调度默认并行运行系统,除非用
.chain()排序。 - 不要在同一系统中把
NextState::set视为已生效;状态调度在本系统返回后才执行转换。 - 不要在同一轮中让两个收集者为同一拾取物计分;
despawn是延迟的,实体仍在查询中。 - 不要在本技能中发明物理、导航、网络或 XR crate;本技能只命名有文档的 Bevy crate 与模块。
- 不要在 Bevy 代码中使用 Godot 的节点、资源或信号类型。
- 不要在文档 URL 中固定
/0.20.0/;链接保持指向最新版本,0.20 目标只在正文中说明一次。 - 消息与观察者属于
bevy-events-messaging的职责范围,本文件不新增事件类型名。
相关技能
前置:bevy-master、bevy-ecs-composition、bevy-state-machines、bevy-data-resources、bevy-events-messaging。 互补:bevy-state-machines、godot-game-loop-collection(等效的 Godot 技能)。 主路由:bevy-master。