bevy-ecs-expert

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Bevy ECS Expert

Bevy ECS 专家指南

Overview

概述

A guide to building high-performance game logic using Bevy's data-oriented ECS architecture. Learn how to structure systems, optimize queries, manage resources, and leverage parallel execution.
本指南介绍如何使用Bevy的面向数据的ECS架构构建高性能游戏逻辑。学习如何构建系统、优化查询、管理资源并利用并行执行。

When to Use This Skill

何时使用该技能

  • Use when developing games with the Bevy engine in Rust.
  • Use when designing game systems that need to run in parallel.
  • Use when optimizing game performance by minimizing cache misses.
  • Use when refactoring object-oriented logic into data-oriented ECS patterns.
  • 在使用Rust语言的Bevy引擎开发游戏时使用。
  • 在设计需要并行运行的游戏系统时使用。
  • 在通过减少缓存未命中来优化游戏性能时使用。
  • 在将面向对象逻辑重构为面向数据的ECS模式时使用。

Step-by-Step Guide

分步指南

1. Defining Components

1. 定义组件

Use simple structs for data. Derive
Component
and
Reflect
.
rust
#[derive(Component, Reflect, Default)]
#[reflect(Component)]
struct Velocity {
    x: f32,
    y: f32,
}

#[derive(Component)]
struct Player;
使用简单结构体存储数据,派生
Component
Reflect
trait。
rust
#[derive(Component, Reflect, Default)]
#[reflect(Component)]
struct Velocity {
    x: f32,
    y: f32,
}

#[derive(Component)]
struct Player;

2. Writing Systems

2. 编写系统

Systems are regular Rust functions that query components.
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_seconds();
        transform.translation.y += velocity.y * time.delta_seconds();
    }
}
系统是普通的Rust函数,用于查询组件。
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_seconds();
        transform.translation.y += velocity.y * time.delta_seconds();
    }
}

3. Managing Resources

3. 管理资源

Use
Resource
for global data (score, game state).
rust
#[derive(Resource)]
struct GameState {
    score: u32,
}

fn score_system(mut game_state: ResMut<GameState>) {
    game_state.score += 10;
}
使用
Resource
存储全局数据(如分数、游戏状态)。
rust
#[derive(Resource)]
struct GameState {
    score: u32,
}

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

4. Scheduling Systems

4. 调度系统

Add systems to the
App
builder, defining execution order if needed.
rust
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .init_resource::<GameState>()
        .add_systems(Update, (movement_system, score_system).chain())
        .run();
}
将系统添加到
App
构建器中,必要时定义执行顺序。
rust
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .init_resource::<GameState>()
        .add_systems(Update, (movement_system, score_system).chain())
        .run();
}

Examples

示例

Example 1: Spawning Entities with Require Component

示例1:生成包含必填组件的实体

rust
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")), 
    ));
}
rust
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")), 
    ));
}

Example 2: Query Filters

示例2:查询过滤器

Use
With
and
Without
to filter entities efficiently.
rust
fn enemy_behavior(
    query: Query<&Transform, (With<Enemy>, Without<Dead>)>,
) {
    for transform in &query {
        // Only active enemies processed here
    }
}
使用
With
Without
高效过滤实体。
rust
fn enemy_behavior(
    query: Query<&Transform, (With<Enemy>, Without<Dead>)>,
) {
    for transform in &query {
        // 仅处理活跃敌人
    }
}

Best Practices

最佳实践

  • Do: Use
    Query
    filters (
    With
    ,
    Without
    ,
    Changed
    ) to reduce iteration count.
  • Do: Prefer
    Res
    over
    ResMut
    when read-only access is sufficient to allow parallel execution.
  • Do: Use
    Bundle
    to spawn complex entities atomically.
  • Don't: Store heavy logic inside Components; keep them as pure data.
  • Don't: Use
    RefCell
    or interior mutability inside components; let the ECS handle borrowing.
  • 推荐: 使用
    Query
    过滤器(
    With
    Without
    Changed
    )减少迭代次数。
  • 推荐: 当仅需要只读访问时,优先使用
    Res
    而非
    ResMut
    ,以支持并行执行。
  • 推荐: 使用
    Bundle
    原子化生成复杂实体。
  • 避免: 在组件中存储复杂逻辑;组件应仅作为纯数据容器。
  • 避免: 在组件内部使用
    RefCell
    或内部可变性;让ECS处理借用逻辑。

Troubleshooting

故障排除

Problem: System panic with "Conflict" error. Solution: You are likely trying to access the same component mutably in two systems running in parallel. Use
.chain()
to order them or split the logic.
问题: 系统因“Conflict”错误崩溃。 解决方案: 你可能尝试在两个并行运行的系统中可变访问同一组件。使用
.chain()
指定执行顺序,或拆分逻辑。