mcpField
B
bevy-ecs-expert

bevy-ecs-expert

github.com/sickn33开发48.7k169 次安装今天更新
代码仓库

关于 bevy-ecs-expert

面向 Rust 游戏开发者的 Bevy ECS 指南,涵盖数据导向的游戏逻辑、系统调度、查询和资源管理,并介绍查询筛选与并行执行等性能考量。

主要功能

  1. 01定义纯数据组件
  2. 02使用查询编写系统
  3. 03管理全局资源
  4. 04调度并排列系统
  5. 05筛选实体查询
  6. 06解决查询冲突

适用场景

  1. 01使用 Bevy ECS 组织游戏逻辑
  2. 02并行运行可兼容的系统
  3. 03优化实体迭代
  4. 04重构面向对象游戏逻辑

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill bevy-ecs-expert

安装后在 Claude Code 中输入/bevy-ecs-expert确认已加载。

详细介绍

Bevy ECS 专家

概述

本指南介绍如何使用 Bevy 面向数据的 ECS 架构构建高性能游戏逻辑。了解如何构建系统、优化查询、管理资源并利用并行执行。

何时使用此技能

  • 使用 Bevy 引擎和 Rust 开发游戏时。
  • 设计需要并行运行的游戏系统时。
  • 通过减少缓存未命中来优化游戏性能时。
  • 将面向对象逻辑重构为面向数据的 ECS 模式时。

分步指南

1. 定义组件

使用简单的结构体存储数据。导入 bevy::prelude::*;只有在需要反射或检查时才添加 Reflect。以下代码片段是不同的替代方案,不要在同一作用域中重复定义 Player/Velocity。

#[derive(Component, Reflect, Default)]
#[reflect(Component)]
struct Velocity {
    x: f32,
    y: f32,
}

#[derive(Component)]
struct Player;
2. 编写系统

系统是用于查询组件的常规 Rust 函数。

fn movement_system(
    time: Res<Time>,
    mut query: Query<(&mut Transform, &Velocity), With<Player>>,
) {
    for (mut transform, velocity) in &mut query {
        transform.translation.x += velocity.x * time.delta_secs();
        transform.translation.y += velocity.y * time.delta_secs();
    }
}
3. 管理资源

使用 Resource 存储全局数据(分数、游戏状态)。

#[derive(Resource, Default)]
struct GameState {
    score: u32,
}

fn score_system(mut game_state: ResMut<GameState>) {
    game_state.score += 10;
}

示例中的 score_system 会在每次 Update 时递增分数;若要实现有意义的计分,应使用游戏事件或显式计时器,而不要让人误以为分数行为与帧率无关。

4. 调度系统

将系统添加到 App 构建器中,并在需要时定义执行顺序。

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .init_resource::<GameState>()
        .add_systems(Update, (movement_system, score_system).chain())
        .run();
}

示例

示例 1:生成带有必需组件的实体
use bevy::prelude::*;

#[derive(Component, Reflect, Default)]
#[require(Velocity, Sprite)]
struct Player;

#[derive(Component, Default)]
struct Velocity {
    x: f32,
    y: f32,
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn((
        Player,
        Velocity { x: 10.0, y: 0.0 },
        Sprite::from_image(asset_server.load("player.png")), 
    ));
}
示例 2:查询过滤器

使用 With 和 Without 高效筛选实体。

fn enemy_behavior(
    query: Query<&Transform, (With<Enemy>, Without<Dead>)>,
) {
    for transform in &query {
        // Only active enemies processed here
    }
}

最佳实践

  • ✅ 建议: 使用 Query 过滤器(With、Without、Changed)减少遍历数量。
  • ✅ 建议: 只读访问足够时,优先使用 Res 而非 ResMut,以便并行执行。
  • ✅ 建议: 使用 Bundle 原子化地生成复杂实体。
  • ❌ 避免: 在组件中存储繁重的逻辑;组件应保持为纯数据。
  • ❌ 避免: 在组件中使用 RefCell 或内部可变性;优先使用常规 ECS 借用。任何内部可变性设计仍须满足有效的 Send/Sync,并有明确的同步理由。

故障排除

问题: 系统因 “Conflict” 错误而崩溃。
解决方案: 调度器通常会对存在冲突的系统排序。Bevy B0001 通常涉及单个系统内不兼容的查询;请酌情使用互斥的 With/Without 过滤器或 ParamSet。将两个系统串联起来无法解决单个系统内的参数冲突。参阅 Bevy B0001。

限制

  • 固定项目使用的 Bevy 版本,并查阅其迁移/API 指南。当前示例使用 delta_secs 和必需组件;较旧的 Bevy 版本可能有所不同。Enemy/Dead 是应用自有的组件标记,player.png 是应用资源,并非随附文件。本文未声称进行过引擎编译或性能基准测试。
  • 请勿将输出视为特定环境验证、测试或专家审查的替代品。
  • 如果缺少必要的输入、权限、安全边界或成功标准,请暂停并请求澄清。

评论

支持 Markdown