0Pricing
Learn Rust Coding · 课时

ECS 思维方式

实体、组件和系统。

ECS 思维方式 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 4 节课。

ECS 解决的问题

Bevy 构建于实体组件系统(ECS)模式之上。它不使用深层继承层次结构,而是将行为组合自一组小型、彼此独立的数据。

这种面向数据的设计让内存布局更适合缓存,也使引擎几乎无需额外成本就能在多个 CPU 核心之间并行处理工作。

实体只是 ID

实体不过是一个轻量级标识符,也就是一个代际索引。它不拥有任何数据,也不会自行执行任何行为。

您可以把它想象成数据库行中的键。附加到该键上的组件赋予实体含义,例如“Player”或“Bullet”。

// An Entity is a tiny handle
struct Entity {
    index: u32,
    generation: u32,
}

组件是纯数据

组件是派生自 Component 的普通 Rust 结构体。它们携带状态,但不包含逻辑。

请让组件保持小巧且职责单一。位置、速度和生命值应当是三个独立的组件,而不是放在一个庞大的结构体中。

use bevy::prelude::*;

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

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

系统承载逻辑

系统是操作组件的普通函数,所有游戏逻辑都在这里实现。

Bevy 会检查每个系统的参数,以确定它访问哪些数据,然后安排彼此不冲突的系统并行运行。

fn move_system(mut query: Query<(&mut Position, &Velocity)>) {
    for (mut pos, vel) in &mut query {
        pos.x += vel.x;
        pos.y += vel.y;
    }
}

查询:请求数据

Query 以声明方式请求拥有特定组件集合的实体。Bevy 只会返回匹配的实体。

您可以使用 &T 请求共享访问,或使用 &mut T 请求独占访问。这些借用信息会驱动并行调度器。

// Entities with BOTH Position and Velocity
fn report(query: Query<(&Position, &Velocity)>) {
    for (pos, vel) in &query {
        info!("at {},{} moving {},{}", pos.x, pos.y, vel.x, vel.y);
    }
}

筛选查询

Query 的第二个类型参数是筛选器。使用 With 和 Without 可以缩小结果范围,同时无需借用该组件的数据。

这非常适合用于标签组件,也就是用于标记实体角色的空结构体。

#[derive(Component)]
struct Player;

fn player_only(query: Query<&Position, With<Player>>) {
    for pos in &query {
        info!("player at {},{}", pos.x, pos.y);
    }
}

资源:全局状态

有些数据对于整个游戏都是唯一的,例如分数、经过的时间或游戏设置。这些数据应当作为资源存在,而不是组件。

在系统中,使用 Res<T> 进行只读访问,或使用 ResMut<T> 进行写入访问。

#[derive(Resource)]
struct Score(u32);

fn show_score(score: Res<Score>) {
    info!("Score: {}", score.0);
}

应用构建器

所有内容都在 App 中连接起来。您可以添加插件、插入资源,并针对某个调度注册系统。

DefaultPlugins 提供窗口、渲染、输入和时间功能,让您能够专注于游戏玩法。

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .insert_resource(Score(0))
        .add_systems(Update, show_score)
        .run();
}

调度:启动与更新

系统在调度中运行。应用启动时,Startup 只运行一次,非常适合生成游戏世界。

Update 每帧运行,移动、输入和逻辑都应放在这里。Bevy 还提供 FixedUpdate,用于执行确定性的物理步骤。

App::new()
    .add_plugins(DefaultPlugins)
    .add_systems(Startup, setup)
    .add_systems(Update, move_system)
    .run();

组合为何更具优势

想要一个会飞且可以中毒的敌人吗?只需为它附加 Flying 和 Poisoned 组件即可。不需要新建类,也不需要继承链。

行为取决于哪些系统匹配哪些组件组合,并由此自然产生。这样添加功能更简单,重构成本也更低。

// Same systems, new combinations
commands.spawn((Position{x:0.0,y:0.0}, Velocity{x:1.0,y:0.0}, Flying, Poisoned));

无需额外成本的并行化

由于每个系统都会声明自己的数据访问方式,Bevy 的调度器能够知道哪些系统彼此冲突。不冲突的系统会自动在不同线程上运行。

您编写的代码看起来像单线程代码,而引擎会从借用声明中提取并行性。不需要锁,也不需要手动管理线程。

快速检查

测试您对 ECS 中各角色的理解。

回顾:ECS 思维方式

实体是 ID,组件是数据,系统是逻辑,资源是全局状态。App 通过调度将它们连接起来。

通过组合小型组件,并让系统匹配这些组件,您可以构建灵活、可并行且缓存友好的游戏。接下来,我们将生成实体并让它们移动。

常见问题解答

「ECS 思维方式」课时是免费的吗?

是的 — 「ECS 思维方式」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 4 节课。

「ECS 思维方式」这节课中我会学到什么?

实体、组件和系统。 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Learn Rust Coding 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「ECS 思维方式」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Learn Rust Coding 课中编写并运行代码吗?

能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. ECS 思维方式
  2. 创建并移动实体
  3. 处理输入和时间
  4. 碰撞和游戏状态
← 返回 Learn Rust Coding