2D开发

概述

学习目标

  • 掌握精灵图集的使用
  • 学会创建精灵动画
  • 了解 2D 文本渲染
  • 掌握透明度的使用
  • 了解后处理效果(泛光)
  • 理解 2D 相机控制(视口到世界坐标转换)
  • 掌握像素完美渲染

前置知识要求

  • 2D 基础
  • ECS 基础
  • 资源管理基础

核心概念

什么是 2D 开发?

2D 开发是在二维平面上创建游戏和应用。Bevy 提供了强大的 2D 渲染系统,支持精灵、动画、文本、后处理等功能。

为什么需要 2D 开发?

  1. 游戏开发:大多数 2D 游戏需要 2D 开发
  2. UI 开发:用户界面通常使用 2D 渲染
  3. 性能优化:2D 渲染比 3D 渲染更高效
  4. 简单性:2D 开发通常比 3D 开发更简单

2D 开发的核心组件

Bevy 2D 开发系统包含以下核心组件:

  • Sprite:精灵,用于显示图像
  • TextureAtlas:纹理图集,用于管理多个精灵
  • Animation:动画,用于创建精灵动画
  • Text2d:2D 文本,用于显示文本
  • Camera2d:2D 相机,用于控制视图
  • Bloom:泛光效果,用于后处理

基础用法

精灵图集

使用精灵图集管理多个精灵。

源代码文件bevy/examples/2d/texture_atlas.rs

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
use bevy::{asset::LoadedFolder, image::ImageSampler, prelude::*};

fn main() {
App::new()
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
.add_systems(Startup, setup)
.run();
}

fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
mut textures: ResMut<Assets<Image>>,
) {
// 从文件夹加载多个单独的精灵
let loaded_folder = asset_server.load_folder("textures/rpg");

// 创建纹理图集
let (texture_atlas, sources, texture) = create_texture_atlas(
loaded_folder,
Some(UVec2::new(6, 6)), // 填充
Some(ImageSampler::nearest()), // 采样方式
&mut textures,
);
let atlas_handle = texture_atlases.add(texture_atlas);

// 使用图集中的精灵
commands.spawn((
Sprite {
texture_atlas: Some(atlas_handle),
..default()
},
Transform::from_xyz(0.0, 0.0, 0.0),
));
}

关键要点

  • 使用 TextureAtlasLayout 创建纹理图集
  • 可以从文件夹加载多个精灵
  • 可以设置填充和采样方式
  • 使用 Spritetexture_atlas 属性使用图集

说明
精灵图集允许将多个精灵打包到一个纹理中,减少绘制调用和提高性能。

精灵动画

创建精灵动画。

源代码文件bevy/examples/2d/sprite_animation.rs

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
use bevy::prelude::*;
use std::time::Duration;

fn main() {
App::new()
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
.add_systems(Startup, setup)
.add_systems(Update, execute_animations)
.run();
}

#[derive(Component)]
struct AnimationConfig {
first_sprite_index: usize,
last_sprite_index: usize,
fps: u8,
frame_timer: Timer,
}

impl AnimationConfig {
fn new(first: usize, last: usize, fps: u8) -> Self {
Self {
first_sprite_index: first,
last_sprite_index: last,
fps,
frame_timer: Timer::new(Duration::from_secs_f32(1.0 / (fps as f32)), TimerMode::Repeating),
}
}
}

// 这个系统循环遍历 `TextureAtlas` 中的所有精灵,从 `first_sprite_index` 到 `last_sprite_index`
fn execute_animations(time: Res<Time>, mut query: Query<(&mut AnimationConfig, &mut Sprite)>) {
for (mut config, mut sprite) in &mut query {
// 跟踪当前精灵已显示的时间
config.frame_timer.tick(time.delta());

// 如果已显示用户定义的时间(fps)...
if config.frame_timer.just_finished() {
if let Some(atlas) = &mut sprite.texture_atlas {
if atlas.index == config.last_sprite_index {
// ...并且是最后一帧,则回到第一帧
atlas.index = config.first_sprite_index;
} else {
// ...并且不是最后一帧,则移动到下一帧
atlas.index += 1;
}
}
}
}
}

关键要点

  • 使用 AnimationConfig 配置动画
  • 使用 Timer 控制动画帧率
  • 通过更新 Spritetexture_atlas.index 来切换帧
  • 可以设置动画的起始帧和结束帧

说明
精灵动画通过在不同帧之间切换来创建动画效果。通过控制帧切换的时间,可以创建流畅的动画。

2D 文本渲染

在 2D 场景中渲染文本。

源代码文件bevy/examples/2d/text2d.rs

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use bevy::prelude::*;

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, (animate_translation, animate_rotation, animate_scale))
.run();
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let font = asset_server.load("fonts/FiraSans-Bold.ttf");
let text_font = TextFont {
font: font.clone(),
font_size: 50.0,
..default()
};

commands.spawn(Camera2d);

// 演示变换
commands.spawn((
Text2d::new(" translation "),
text_font.clone(),
TextLayout::new_with_justify(Justify::Center),
TextBackgroundColor(Color::BLACK.with_alpha(0.5)),
Text2dShadow::default(),
Transform::from_xyz(0.0, 0.0, 0.0),
));

// 演示文本换行
let box_size = Vec2::new(300.0, 200.0);
commands.spawn((
Sprite::from_color(Color::srgb(0.25, 0.25, 0.55), box_size),
Transform::from_translation(Vec3::new(0.0, -250.0, 0.0)),
children![(
Text2d::new("this text wraps in the box\n(Unicode linebreaks)"),
TextFont {
font,
font_size: 35.0,
..default()
},
TextLayout::new(Justify::Left, LineBreak::WordBoundary),
// 在矩形中换行文本
TextBounds::from(box_size),
// 确保文本绘制在框的上方
Transform::from_translation(Vec3::Z),
Text2dShadow::default(),
)],
));
}

关键要点

  • 使用 Text2d 在 2D 场景中渲染文本
  • 使用 TextFont 设置字体和大小
  • 使用 TextLayout 设置文本布局和对齐
  • 使用 TextBounds 设置文本边界和换行
  • 使用 Text2dShadow 添加文本阴影

说明
2D 文本渲染允许在 2D 场景中显示文本。与 UI 文本不同,2D 文本是场景的一部分,可以应用变换、动画等效果。

透明度

使用透明度创建半透明效果。

源代码文件bevy/examples/2d/transparency_2d.rs

关键信息

  • 使用 Color::srgba() 创建带透明度的颜色
  • 使用 AlphaMode 控制透明度模式
  • AlphaMode::Blend 用于半透明对象
  • AlphaMode::Mask 用于带透明度的纹理
  • 透明对象需要正确的渲染顺序

说明
透明度是 2D 渲染中的重要特性。Bevy 支持多种透明度模式,可以创建玻璃、水、烟雾等效果。

后处理效果(泛光)

使用泛光效果增强渲染效果。

源代码文件bevy/examples/2d/bloom_2d.rs

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
use bevy::{
core_pipeline::tonemapping::{DebandDither, Tonemapping},
post_process::bloom::{Bloom, BloomCompositeMode},
prelude::*,
};

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, update_bloom_settings)
.run();
}

fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
asset_server: Res<AssetServer>,
) {
commands.spawn((
Camera2d,
Camera {
clear_color: ClearColorConfig::Custom(Color::BLACK),
..default()
},
Tonemapping::TonyMcMapface, // 使用色调映射器
Bloom::default(), // 启用泛光效果
DebandDither::Enabled, // 可选:泛光会导致渐变,导致条带
));

// 精灵
commands.spawn(Sprite {
image: asset_server.load("branding/bevy_bird_dark.png"),
color: Color::srgb(5.0, 5.0, 5.0), // 在暗环境中放置明亮的东西以看到效果
custom_size: Some(Vec2::splat(160.0)),
..default()
});
}

关键要点

  • 使用 Bloom 组件添加泛光效果
  • 使用 Tonemapping 进行色调映射
  • 使用 DebandDither 减少条带
  • 泛光效果在暗环境中更明显

说明
泛光效果可以在明亮区域周围创建光晕效果。这对于创建发光效果、增强视觉冲击力非常有用。

2D 相机控制(视口到世界坐标转换)

将视口坐标转换为世界坐标。

源代码文件bevy/examples/2d/2d_viewport_to_world.rs

关键信息

  • 使用 Cameraviewport_to_world() 方法
  • 可以将屏幕坐标转换为世界坐标
  • 适合处理鼠标点击、触摸输入等
  • 需要考虑相机的变换和投影

说明
视口到世界坐标转换允许将屏幕坐标转换为游戏世界坐标。这对于处理鼠标点击、触摸输入等交互非常有用。

像素完美渲染

实现像素完美渲染。

源代码文件bevy/examples/2d/pixel_grid_snap.rs

关键信息

  • 使用 ImagePlugin::default_nearest() 禁用纹理过滤
  • 使用像素对齐确保精灵对齐到像素网格
  • 适合像素艺术风格的游戏
  • 可以避免模糊和抗锯齿

说明
像素完美渲染确保精灵对齐到像素网格,避免模糊和抗锯齿。这对于像素艺术风格的游戏非常重要。

进阶用法

高级动画

创建复杂的动画效果。

关键信息

  • 可以创建多个动画轨道
  • 可以混合不同的动画
  • 可以使用动画事件
  • 可以控制动画的播放速度

说明
高级动画允许创建复杂的动画效果。可以组合多个动画、控制播放速度、响应动画事件等。

性能优化

优化 2D 渲染性能。

关键信息

  • 使用精灵图集减少绘制调用
  • 使用批处理优化渲染
  • 使用剔除减少渲染对象
  • 合理使用透明度

说明
性能优化对于 2D 游戏非常重要。通过使用精灵图集、批处理、剔除等技术,可以显著提高渲染性能。

实际应用

在游戏开发中的应用场景

2D 开发在游戏开发中有广泛的应用:

  1. 2D 游戏:创建 2D 平台游戏、RPG、策略游戏等
  2. UI 开发:创建游戏 UI 和 HUD
  3. 粒子效果:创建粒子效果和特效
  4. 菜单系统:创建游戏菜单和界面

常见问题

问题 1:如何优化精灵动画性能?

解决方案:使用精灵图集、批处理、剔除等技术来优化精灵动画性能。

问题 2:如何处理透明对象?

解决方案:透明对象需要正确的渲染顺序。Bevy 会自动处理透明对象的排序。

问题 3:如何实现像素完美渲染?

解决方案:使用 ImagePlugin::default_nearest() 禁用纹理过滤,并确保精灵对齐到像素网格。

性能考虑

  1. 精灵图集:使用精灵图集减少绘制调用
  2. 批处理:使用批处理优化渲染
  3. 剔除:使用剔除减少渲染对象
  4. 透明度:合理使用透明度以减少性能开销

相关资源

相关源代码文件

  • bevy/examples/2d/texture_atlas.rs - 精灵图集示例
  • bevy/examples/2d/sprite_animation.rs - 精灵动画示例
  • bevy/examples/2d/text2d.rs - 2D 文本渲染示例
  • bevy/examples/2d/transparency_2d.rs - 透明度示例
  • bevy/examples/2d/bloom_2d.rs - 泛光效果示例
  • bevy/examples/2d/2d_viewport_to_world.rs - 视口到世界坐标转换示例
  • bevy/examples/2d/pixel_grid_snap.rs - 像素完美渲染示例

官方文档链接

进一步学习建议

  • 学习动画系统,了解如何创建更复杂的动画
  • 学习 UI 系统,了解如何创建用户界面
  • 学习性能优化,了解如何优化 2D 渲染性能

索引返回上级目录