用途
本技能用于在 Bevy 引擎中把一款原本按 3D 设计的游戏改为以 2D 方式渲染。适用场景是:3D 设计需要以精灵(sprite)或公告板(billboard)形式呈现。其原则是玩法组件保持不变,渲染组件发生改变。
主要能力
- 绘制:在公告板足够的情况下,把网格与 PBR 材质实体的渲染部分替换为 Sprite。
- 相机:使用来自 bevy-camera-systems 的 Camera2d。
- 灯光:无光照的精灵不需要 3D 灯光实体;不要在玩法代码中保留聚簇光照(clustered-light)的假设。
- 绘制顺序:用一个自行存储的 DrawOrder 组件,再写入 Transform。
使用方式
依赖声明为:
[dependencies]
bevy = "0.20"
玩法组件保留在实体上,移除 3D 渲染组件,插入 Sprite,并以 Camera2d 作为视图。示例代码:
#[derive(Component)]
struct Actor;
#[derive(Component)]
struct DrawOrder(f32);
fn spawn_flat_view(mut commands: Commands) {
commands.spawn(Camera2d);
}
fn present_as_sprites(
mut commands: Commands,
asset_server: Res<AssetServer>,
actors: Query<(Entity, &DrawOrder), With<Actor>>,
) {
let image = asset_server.load("actors/hero.png");
for (entity, order) in &actors {
commands
.entity(entity)
.remove::<Mesh3d>()
.remove::<MeshMaterial3d<StandardMaterial>>()
.insert((
Sprite {
image: image.clone(),
custom_size: Some(Vec2::new(64.0, 64.0)),
..default()
},
Transform::from_xyz(0.0, order.0, 0.0),
));
}
}
新角色也可以直接以扁平方式生成,玩法系统查询的仍是同一个 Actor 组件:
#[derive(Component)]
struct Actor;
fn spawn_sprite_actor(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn((
Actor,
Sprite {
image: asset_server.load("actors/hero.png"),
color: Color::WHITE,
..default()
},
Transform::from_xyz(0.0, 0.0, 0.0),
));
}
fn face_motion(mut actors: Query<(&Transform, &mut Sprite), With<Actor>>) {
for (transform, mut sprite) in &mut actors {
sprite.flip_x = transform.translation.x < 0.0;
}
}
在没有 3D 相机的情况下,依据存储的顺序对精灵排序。较高的 DrawOrder 映射到较高的 Y,使 2D 相机在俯视布局中更晚绘制它:
#[derive(Component)]
struct DrawOrder(f32);
fn apply_draw_order(mut sprites: Query<(&DrawOrder, &mut Transform), With<Sprite>>) {
for (order, mut transform) in &mut sprites {
transform.translation.y = order.0;
}
}
专家知识要点
目标为 Bevy 0.20+。核心 ECS 类型包括:Component、Resource、Query、Commands、Startup、Update、Fixed / FixedMain(bevy::time)、.chain()、Plugin、DefaultPlugins、MinimalPlugins。消息与观察者属于一个所有权槽位,其 API 参见 bevy-events-messaging。除非用 .chain() 对冲突的系统排序,否则系统并行运行。
状态所有权:
- 单个实体上的数据:由 Component 持有,一个系统通过 Query 修改,运行于 Update 或 FixedMain。
- 整个应用的一个值:由 Resource 持有,一个系统修改,在 Startup 插入,随后由读取它的调度使用。
- 生成:由 Commands 负责,生成系统执行;初始世界在 Startup,运行时生成在后续调度。
- 不能竞态的顺序:由 .chain() 约束,仅作用于被链式连接的系统,位于同一调度。
- 插件边界:由 Plugin 负责,build 注册系统与资源,在应用运行前完成。
借用规则:两个系统若都可变查询同一组件,必须排序(.chain())或拆分,使只有一个写入。无关系统保持并行。这是 ECS 页面规则,并非对系统集 API 的猜测。
决策表:
- 需要逐实体数据:用 Component + Query,不要用存放在世界之外的普通结构体。
- 需要应用级配置或时钟:用 Resource,不要把值复制到每个实体。
- 需要稳定的模拟步长:用 FixedMain 与 Fixed 时钟,不要把模拟绑定到原始帧 Update。
- 需要启动时生成:在 Startup 中用 Commands,不要从渲染系统生成。
- 需要非共享状态的跨系统通知:使用 bevy-events-messaging 中的消息或观察者槽位,不要在本文件中新造事件类型。
- 需要文档集之外的 API:先查官方文档,不要使用编造的 crate 或 API。
所有权表可加载 references/ecs-ownership.md。
禁止事项
- 不要在文档 URL 中固定 /0.20.0/。原因:链接保持指向最新版;0.20 目标只在正文中说明一次。
- 不要从两个无序系统可变查询同一组件。原因:除非用 .chain() 排序,调度会并行运行系统。
- 不要在此处编造物理、导航、网络或 XR crate。原因:本技能只命名有文档记录的 Bevy crate 与模块。
- 不要在已变为精灵的实体上残留 Mesh3d 或 MeshMaterial3d。原因:同一实体上的两条渲染路径会争夺同一个 transform。
- 不要使用编造的 API 或未命名的第三方 crate 作为选定求解方案。原因:Bevy 代码保持惯用 ECS,且只使用有文档记录的 Bevy API。
参考
bevy-master 上的库固定版本保持 0.20.0,永久链接保持不带版本。
官方文档:
- Assets - 官方资源目录。未选择第三方 crate。
- Examples - 最新分支上的示例树。
- 2D examples - 精灵与相机示例。
- ECS - Component、systems、Query、Startup、Update 与 .chain()。
- Plugins - Plugin、DefaultPlugins、MinimalPlugins 与 add_plugins。
相关技能:
前置:bevy-master(枢纽与调度)、bevy-ecs-composition(组件与系统)、bevy-camera-systems(Camera2d)、bevy-2d-animation(精灵剪辑)。
互补:bevy-adapt-2d-to-3d(反向适配)。
下游 / 消费者:暂无。
主技能:bevy-master(Bevy 路由)。