SuperAPI AI 工具集

bevy-genre-sandbox

编程与开发

查看项目

更新于 10-16 06:08

技能介绍

用途

Bevy Sandbox(薄路由)是一个类型路由技能,用于处理玩家建造实体的放置(place)、移除(remove)与保存(save)。它本身不实现领域逻辑,而是将具体工作路由到其他 Bevy 技能。

主要能力

  • 放置单元格:按下按键时生成带有类型 id 的 PlacedCell 组件。
  • 编辑单元格:通过 .chain() 先执行 paint 再执行 remove,例如 x = 0 处 kind 1 变为 kind 2,kind 0 则被 despawn。
  • 构建快照:将 PlacedCell 查询结果映射为 serde 可序列化的 CellRecord 记录,存入 BuildSnapshot 资源,实现构建的往返(round-trip)。

ECS 结构

  • 组件(Component)以纯数据保存每实体的类型标记,本文件不命名新的引擎类型。
  • 资源(Resource)通过 bevy-data-resources 保存运行期计数器(分数、波次索引、种子)。
  • 系统在 Update 或来自 bevy-master 的固定时间步读取组件;当后续系统需要看到结果时,用 .chain() 排序。
  • 游戏模式变更通过 bevy-state-machines 处理;本文件仅注册放置、编辑和构建快照。

路由

  • bevy-3d-world-building:道具。
  • bevy-inventory-system:建造部件。
  • bevy-save-load:世界持久化。
  • bevy-input-handling:放置。

范围

已放置的单元格是一个带有网格坐标和类型 id 的组件。道具、库存和文件持久化保留在上述链接的技能中。

依赖

[dependencies]
bevy = "0.20"
serde = { version = "1", features = ["derive"] }

代码示例

放置单元格:

#[derive(Component, Clone, Copy)]
struct PlacedCell {
    x: i32,
    y: i32,
    z: i32,
    kind: u16,
}

fn place_cell(keys: Res<ButtonInput<KeyCode>>, mut commands: Commands) {
    if keys.just_pressed(KeyCode::KeyP) {
        commands.spawn((
            PlacedCell {
                x: 0,
                y: 0,
                z: 0,
                kind: 1,
            },
            Transform::from_xyz(0.0, 0.0, 0.0),
        ));
    }
}

pub struct PlacePlugin;

impl Plugin for PlacePlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(Update, place_cell);
    }
}

编辑单元格:

#[derive(Component, Clone, Copy)]
struct PlacedCell {
    x: i32,
    y: i32,
    z: i32,
    kind: u16,
}

fn remove_empty(mut commands: Commands, cells: Query<(Entity, &PlacedCell)>) {
    for (entity, cell) in &cells {
        if cell.kind == 0 {
            commands.entity(entity).despawn();
        }
    }
}

fn paint_neighbor(mut cells: Query<&mut PlacedCell>) {
    for mut cell in &mut cells {
        if cell.x == 0 && cell.kind == 1 {
            cell.kind = 2;
        }
    }
}

pub struct EditPlugin;

impl Plugin for EditPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(Update, (paint_neighbor, remove_empty).chain());
    }
}

构建快照:

use serde::{Deserialize, Serialize};

#[derive(Component)]
struct PlacedCell {
    x: i32,
    y: i32,
    z: i32,
    kind: u16,
}

#[derive(Serialize, Deserialize, Clone, Default)]
struct CellRecord {
    x: i32,
    y: i32,
    z: i32,
    kind: u16,
}

#[derive(Resource, Default)]
struct BuildSnapshot(Vec<CellRecord>);

fn snapshot(cells: Query<&PlacedCell>, mut saved: ResMut<BuildSnapshot>) {
    saved.0 = cells
        .iter()
        .map(|cell| CellRecord {
            x: cell.x,
            y: cell.y,
            z: cell.z,
            kind: cell.kind,
        })
        .collect();
}

pub struct SnapshotPlugin;

impl Plugin for SnapshotPlugin {
    fn build(&self, app: &mut App) {
        app.init_resource::<BuildSnapshot>()
            .add_systems(Update, snapshot);
    }
}

fn main() {
    App::new()
        .add_plugins(MinimalPlugins)
        .add_plugins(SnapshotPlugin)
        .run();
}

专家知识要点

目标:Bevy 0.20+。

核心 ECS 类型:Component、Resource、Query、Commands、Startup、Update、Fixed / FixedMain(bevy::time)、.chain()、Plugin、DefaultPlugins、MinimalPlugins。消息与观察者属于所有权槽位,其 API 见 bevy-events-messaging。除非 .chain() 对冲突系统排序,否则系统并行运行。

状态所有权:

  • 单个实体上的数据:组件,由一个系统通过 Query 修改,运行于 Update 或 FixedMain。
  • 整个应用的一个值:资源,由一个系统修改,Startup 插入,随后由读取它的调度使用。
  • 生成:Commands,由生成系统负责,Startup 用于初始世界,后续调度用于运行时生成。
  • 不可竞争的排序:.chain(),仅作用于被链式连接的系统,同一调度内。
  • 插件边界:Plugin,build 注册系统与资源,在应用运行前。

借用规则:两个都可变查询同一组件的系统必须排序(.chain())或拆分,使只有一个写入。无关系统保持并行。

决策表:

  • 需要每实体数据:用组件 + Query,不要用所有实体共享的一个可变块。
  • 需要应用级配置或时钟:用资源,不要把值复制到每个实体。
  • 需要稳定模拟步:用 FixedMain 和 Fixed 时钟,不要把模拟绑定到原始帧 Update。
  • 需要 Startup 生成:在 Startup 中用 Commands,不要从渲染系统生成。
  • 需要跨系统通知而非共享状态:用 bevy-events-messaging 中的消息或观察者槽位,不要在本文件发明新事件类型。
  • 行为已由关联领域技能拥有:保持本路由仅含组件和资源,不要在本文件重复实现。

加载 references/ecs-ownership.md 查看所有权表。

禁止事项

  • 不要在文档 URL 中固定 /0.20.0/。原因:链接保持最新;0.20 目标在正文中说明一次。
  • 不要从两个无序系统可变查询同一组件。原因:除非 .chain() 排序,调度会并行运行系统。
  • 不要在此发明物理、导航、网络或 XR crate。原因:本技能只命名有文档的 Bevy crate 和模块。
  • 不要在同一无序对中 paint 单元格并 despawn 它。原因:两者都触及 PlacedCell 数据,因此 paint 需通过 .chain() 在 remove 之前运行。
  • 不要发明类型 API。原因:Bevy 代码保持惯用 ECS,仅使用有文档的 Bevy API。
  • 不要在此选择物理或网络 crate。原因:Bevy 代码保持惯用 ECS,仅使用有文档的 Bevy API。

参考

bevy-master 上的库固定为 0.20.0。官方页面保持在无版本站点。

官方文档:

  • Assets - 官方资产目录。未选择第三方 crate。
  • Examples - 最新分支上的示例树。
  • ECS - Component、systems、Query、Startup、Update 和 .chain()。
  • Plugins - Plugin、DefaultPlugins、MinimalPlugins 和 add_plugins。

相关技能

前置:

  • bevy-master - ECS 所有权与调度。
  • bevy-ecs-composition - 生成与查询形态。

补充:

  • bevy-3d-world-building - 道具。
  • bevy-inventory-system - 建造部件。
  • bevy-save-load - 世界持久化。
  • bevy-input-handling - 放置。

下游 / 消费者:无。本路由不拥有第二实现。

主技能:bevy-master - Bevy 路由。