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 反馈 — 无需本地设置。