用途
bevy-genre-rts 是一个 Bevy 0.20 的 RTS 类型路由技能,目标是在 ECS 架构下统一处理即时战略游戏的选择、移动指令和控制编组三类核心逻辑。它本身是一个"薄路由",实际的领域实现分散在多个 Bevy 技能中,由它负责调度与整合。当项目需要处理选择(selection)、指令(orders)和编组(groups)时加载此技能。
ECS 结构与主要能力
该技能把 RTS 玩法数据落在两个位置上:
- 组件(Component):承载每个实体上的类型标记与数据,例如选中状态、移动指令。此技能不引入新的引擎类型。
- 资源(Resource):持有整个运行范围内共享的计数器(分数、波次索引、随机种子等),通过 bevy-data-resources 实现。
系统在 Update 或来自 bevy-master 的固定时间步上读取这些组件;当后续系统必须看到前一步结果时,用 .chain() 排序。游戏模式切换通过 bevy-state-machines 处理,不自行发明类型插件。
核心能力示例:
- 选择:Selected 标记当前组;点击选择通过由其他系统填充的指针资源完成,半径内的单位获得 Selected。
- 移动指令:MoveOrder 记录目标点,行军系统在指令写入后执行。
- 控制编组:数字键把选中实体存入资源,再次按键清除 Selected 并恢复该编组。
使用方式
示例采用 Bevy 0.20,依赖声明为:
[package]
name = "rts"
version = "0.1.0"
edition = "2021"
[dependencies]
bevy = "0.20"
选择标记与移动指令均以组件表示:
#[derive(Component)]
struct Selected;
#[derive(Component)]
struct MoveOrder {
target: Vec3,
}
下达移动指令与执行行军通过 .chain() 在 FixedUpdate 中排序:
fn issue_move(keys: Res<ButtonInput<KeyCode>>, mut units: Query<&mut MoveOrder, With<Selected>>) {
if !keys.just_pressed(KeyCode::KeyM) {
return;
}
for mut order in &mut units {
order.target = Vec3::new(12.0, 0.0, 6.0);
}
}
fn march(time: Res<Time<Fixed>>, mut units: Query<(&MoveOrder, &mut Transform)>) {
let dt = time.delta_secs();
for (order, mut transform) in &mut units {
let delta = order.target - transform.translation;
let step = 6.0 * dt;
if delta.length() <= step {
transform.translation = order.target;
} else {
transform.translation += delta.normalize_or_zero() * step;
}
}
}
pub struct OrderPlugin;
impl Plugin for OrderPlugin {
fn build(&self, app: &mut App) {
app.add_systems(FixedUpdate, (issue_move, march).chain());
}
}
控制编组以一个资源持有成员实体列表,数字键用于绑定与恢复:
#[derive(Resource, Default)]
struct ControlGroup {
members: Vec<Entity>,
}
#[derive(Component)]
struct Selected;
fn bind_group(
keys: Res<ButtonInput<KeyCode>>,
selected: Query<Entity, With<Selected>>,
mut group: ResMut<ControlGroup>,
mut commands: Commands,
) {
if keys.just_pressed(KeyCode::Digit1) && keys.pressed(KeyCode::ControlLeft) {
group.members.clear();
for entity in &selected {
group.members.push(entity);
}
return;
}
if keys.just_pressed(KeyCode::Digit1) {
for entity in &selected {
commands.entity(entity).remove::<Selected>();
}
for entity in group.members.clone() {
commands.entity(entity).insert(Selected);
}
}
}
点击选择基于指针资源与半径判定:
#[derive(Resource)]
struct PointerWorld(Vec3);
#[derive(Component)]
struct Selectable;
#[derive(Component)]
struct Selected;
fn click_select(
buttons: Res<ButtonInput<MouseButton>>,
pointer: Res<PointerWorld>,
mut commands: Commands,
units: Query<(Entity, &Transform), With<Selectable>>,
selected: Query<Entity, With<Selected>>,
) {
if !buttons.just_pressed(MouseButton::Left) {
return;
}
for entity in &selected {
commands.entity(entity).remove::<Selected>();
}
for (entity, transform) in &units {
if transform.translation.distance(pointer.0) < 1.5 {
commands.entity(entity).insert(Selected);
}
}
}
fn spawn_units(mut commands: Commands) {
commands.insert_resource(PointerWorld(Vec3::ZERO));
for index in 0..4 {
commands.spawn((
Selectable,
MoveOrder {
target: Vec3::new(index as f32 * 2.0, 0.0, 0.0),
},
Transform::from_xyz(index as f32 * 2.0, 0.0, 0.0),
));
}
}
路由关系
- bevy-input-handling:选择点击。
- bevy-ai-navigation:移动指令与导航(寻路保留在此)。
- bevy-combat-system:攻击。
- bevy-economy-system:成本。
适用场景
- 需要在 Bevy 0.20 下搭建 RTS 选择、编组、移动指令与行军逻辑的项目。
- 希望以纯 ECS 方式(组件 + 资源 + 调度排序)组织 RTS 数据的项目。
限制与约束
- 目标版本为 Bevy 0.20+。文档 URL 不固定到 /0.20.0/,链接保持在最新版,版本目标只在正文中说明一次。
- 不要从两个无序系统中可变查询同一组件;因为除非用 .chain() 排序,调度会并行运行系统。
- 不在此引入物理、导航、网络或 XR crate;只命名有文档的 Bevy crate 与模块。
- Bevy 代码中不使用场景树类型,保持惯用 ECS,只使用有文档的 Bevy API。
- 不发明类型 API;不在此挑选物理或网络 crate。
- 关于事件与观察者(消息/观察者)的 API 属于 bevy-events-messaging 负责的范畴,本技能不新建事件类型。
- 编组指令方式为:每个单位上挂 Selected 与 MoveOrder,在同一系统中行军;不要把阵型发明为引擎单例。
相关技能
- 前置:bevy-master(ECS 所有权与调度)、bevy-ecs-composition(生成与查询形态)。
- 补充:bevy-input-handling、bevy-ai-navigation、bevy-combat-system、bevy-economy-system。
- 下游/消费方:无,此路由不拥有第二实现。
- 主路由:bevy-master。