代码组织
Bevy 代码组织指南
本指南介绍Bevy引擎中推荐的代码组织方式,帮助您构建可维护、可扩展的游戏项目。
模块 (Module) 组织
Rust模块基础
Rust的模块系统是代码组织的基础,在Bevy项目中尤为重要:
// lib.rs 或 main.rs
mod player;
mod enemy;
mod ui;
mod systems;
mod resources;
// 重新导出常用类型
pub use player::PlayerPlugin;
pub use enemy::EnemyPlugin;
pub use ui::UiPlugin;按功能组织模块
// player/mod.rs
mod components;
mod systems;
mod resources;
pub use components::*;
pub use systems::*;
pub use resources::*;
pub struct PlayerPlugin;
impl Plugin for PlayerPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, systems::spawn_player)
.add_systems(Update, systems::player_movement);
}
}按层级组织模块
// 游戏逻辑层
mod game {
mod player;
mod enemy;
mod combat;
}
// 系统层
mod systems {
mod movement;
mod collision;
mod rendering;
}
// 资源层
mod resources {
mod assets;
mod config;
mod state;
}插件 (Plugin) 系统
插件基础
插件是Bevy中最重要的代码组织方式,将相关功能打包成可重用的单元:
use bevy::prelude::*;
pub struct GamePlugin;
impl Plugin for GamePlugin {
fn build(&self, app: &mut App) {
app
// 添加子插件
.add_plugins((
PlayerPlugin,
EnemyPlugin,
UiPlugin,
))
// 添加资源
.init_resource::<GameState>()
.insert_resource(GameConfig::default())
// 添加事件
.add_event::<PlayerDied>()
.add_event::<EnemySpawned>()
// 添加系统
.add_systems(Startup, setup_game)
.add_systems(Update, game_loop);
}
}条件插件
根据配置或环境决定是否启用插件:
pub struct DebugPlugin;
impl Plugin for DebugPlugin {
fn build(&self, app: &mut App) {
#[cfg(debug_assertions)]
{
app.add_systems(Update, debug_system);
}
}
}
// 或者使用特性标志
#[cfg(feature = "debug")]
pub struct DebugPlugin;
impl Plugin for DebugPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, debug_system);
}
}插件配置
通过配置结构体自定义插件行为:
#[derive(Resource)]
pub struct PlayerConfig {
pub speed: f32,
pub health: f32,
pub spawn_position: Vec3,
}
impl Default for PlayerConfig {
fn default() -> Self {
Self {
speed: 5.0,
health: 100.0,
spawn_position: Vec3::ZERO,
}
}
}
pub struct PlayerPlugin {
config: PlayerConfig,
}
impl PlayerPlugin {
pub fn new(config: PlayerConfig) -> Self {
Self { config }
}
pub fn with_speed(mut self, speed: f32) -> Self {
self.config.speed = speed;
self
}
}
impl Plugin for PlayerPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(self.config.clone())
.add_systems(Startup, spawn_player)
.add_systems(Update, player_movement);
}
}
// 使用
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(PlayerPlugin::new(PlayerConfig {
speed: 10.0,
health: 150.0,
spawn_position: Vec3::new(0.0, 0.0, 0.0),
}))
.run();
}插件依赖管理
pub struct CombatPlugin;
impl Plugin for CombatPlugin {
fn build(&self, app: &mut App) {
// 确保依赖的插件已经添加
if !app.is_plugin_added::<PlayerPlugin>() {
app.add_plugins(PlayerPlugin);
}
app.add_systems(Update, combat_system);
}
}Bundle 组件集合
Bundle基础
Bundle是组件的集合,用于一次性添加多个相关组件:
#[derive(Bundle)]
struct PlayerBundle {
player: Player,
health: Health,
transform: Transform,
sprite: Sprite,
collider: Collider,
}
impl Default for PlayerBundle {
fn default() -> Self {
Self {
player: Player,
health: Health::new(100.0),
transform: Transform::from_xyz(0.0, 0.0, 0.0),
sprite: Sprite::new(Vec2::new(32.0, 32.0)),
collider: Collider::circle(16.0),
}
}
}参数化Bundle
#[derive(Bundle)]
struct PlayerBundle {
player: Player,
health: Health,
transform: Transform,
sprite: Sprite,
collider: Collider,
}
impl PlayerBundle {
pub fn new(position: Vec3, health: f32) -> Self {
Self {
player: Player,
health: Health::new(health),
transform: Transform::from_translation(position),
sprite: Sprite::new(Vec2::new(32.0, 32.0)),
collider: Collider::circle(16.0),
}
}
pub fn with_sprite(mut self, size: Vec2) -> Self {
self.sprite = Sprite::new(size);
self
}
pub fn with_collider(mut self, radius: f32) -> Self {
self.collider = Collider::circle(radius);
self
}
}组合Bundle
#[derive(Bundle)]
struct PhysicsBundle {
transform: Transform,
velocity: Velocity,
collider: Collider,
}
#[derive(Bundle)]
struct RenderBundle {
sprite: Sprite,
material: Handle<ColorMaterial>,
}
#[derive(Bundle)]
struct PlayerBundle {
#[bundle]
physics: PhysicsBundle,
#[bundle]
render: RenderBundle,
player: Player,
health: Health,
}
// 使用
commands.spawn(PlayerBundle {
physics: PhysicsBundle {
transform: Transform::from_xyz(0.0, 0.0, 0.0),
velocity: Velocity::default(),
collider: Collider::circle(16.0),
},
render: RenderBundle {
sprite: Sprite::new(Vec2::new(32.0, 32.0)),
material: materials.add(Color::RED),
},
player: Player,
health: Health::new(100.0),
});动态Bundle
fn spawn_player(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
let mut bundle = PlayerBundle::default();
// 根据配置动态修改
if let Some(texture) = asset_server.get_handle("player.png") {
bundle.sprite = Sprite::new(Vec2::new(64.0, 64.0));
bundle.material = materials.add(ColorMaterial::from(texture));
}
commands.spawn(bundle);
}系统集 (SystemSet)
系统集基础
系统集用于组织和排序相关的系统:
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
enum GameSet {
Input,
Movement,
Combat,
Rendering,
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.configure_sets(Update, (
GameSet::Input,
GameSet::Movement,
GameSet::Combat,
GameSet::Rendering,
).chain())
.add_systems(Update, (
handle_input.in_set(GameSet::Input),
player_movement.in_set(GameSet::Movement),
enemy_movement.in_set(GameSet::Movement),
combat_system.in_set(GameSet::Combat),
render_system.in_set(GameSet::Rendering),
))
.run();
}条件系统集
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
enum GameSet {
Input,
Movement,
Combat,
Rendering,
}
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
enum PauseSet {
Paused,
Unpaused,
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.configure_sets(Update, (
GameSet::Input,
GameSet::Movement,
GameSet::Combat,
GameSet::Rendering,
).chain())
.configure_sets(Update, (
PauseSet::Paused,
PauseSet::Unpaused,
).chain())
.add_systems(Update, (
handle_input.in_set(GameSet::Input),
player_movement.in_set((GameSet::Movement, PauseSet::Unpaused)),
pause_menu.in_set((GameSet::Input, PauseSet::Paused)),
))
.run();
}动态系统集
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
enum GameState {
Menu,
Playing,
Paused,
GameOver,
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_state::<GameState>()
.add_systems(Update, (
menu_system.run_if(in_state(GameState::Menu)),
game_system.run_if(in_state(GameState::Playing)),
pause_system.run_if(in_state(GameState::Paused)),
game_over_system.run_if(in_state(GameState::GameOver)),
))
.run();
}完整的项目结构示例
目录结构
src/
├── main.rs
├── lib.rs
├── game/
│ ├── mod.rs
│ ├── player/
│ │ ├── mod.rs
│ │ ├── components.rs
│ │ ├── systems.rs
│ │ ├── resources.rs
│ │ └── plugin.rs
│ ├── enemy/
│ │ ├── mod.rs
│ │ ├── components.rs
│ │ ├── systems.rs
│ │ └── plugin.rs
│ └── combat/
│ ├── mod.rs
│ ├── components.rs
│ ├── systems.rs
│ └── plugin.rs
├── systems/
│ ├── mod.rs
│ ├── movement.rs
│ ├── collision.rs
│ └── rendering.rs
├── resources/
│ ├── mod.rs
│ ├── assets.rs
│ ├── config.rs
│ └── state.rs
└── ui/
├── mod.rs
├── components.rs
├── systems.rs
└── plugin.rs主入口文件
// main.rs
use bevy::prelude::*;
use game::GamePlugin;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(GamePlugin)
.run();
}游戏模块
// game/mod.rs
mod player;
mod enemy;
mod combat;
pub use player::PlayerPlugin;
pub use enemy::EnemyPlugin;
pub use combat::CombatPlugin;
pub struct GamePlugin;
impl Plugin for GamePlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
PlayerPlugin,
EnemyPlugin,
CombatPlugin,
))
.add_systems(Startup, setup_game)
.add_systems(Update, game_loop);
}
}
fn setup_game(mut commands: Commands) {
// 游戏初始化逻辑
}
fn game_loop() {
// 游戏主循环逻辑
}玩家模块
// game/player/mod.rs
mod components;
mod systems;
mod resources;
pub use components::*;
pub use systems::*;
pub use resources::*;
pub struct PlayerPlugin;
impl Plugin for PlayerPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<PlayerConfig>()
.add_systems(Startup, spawn_player)
.add_systems(Update, (
player_movement,
player_animation,
player_health,
));
}
}
// game/player/components.rs
use bevy::prelude::*;
#[derive(Component)]
pub struct Player;
#[derive(Component)]
pub struct PlayerHealth {
pub current: f32,
pub maximum: f32,
}
#[derive(Bundle)]
pub struct PlayerBundle {
pub player: Player,
pub health: PlayerHealth,
pub transform: Transform,
pub sprite: Sprite,
}
// game/player/systems.rs
use bevy::prelude::*;
use super::components::*;
pub fn spawn_player(mut commands: Commands) {
commands.spawn(PlayerBundle {
player: Player,
health: PlayerHealth {
current: 100.0,
maximum: 100.0,
},
transform: Transform::from_xyz(0.0, 0.0, 0.0),
sprite: Sprite::new(Vec2::new(32.0, 32.0)),
});
}
pub fn player_movement(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut query: Query<&mut Transform, With<Player>>,
) {
for mut transform in &mut query {
if keyboard_input.pressed(KeyCode::KeyW) {
transform.translation.y += 1.0;
}
if keyboard_input.pressed(KeyCode::KeyS) {
transform.translation.y -= 1.0;
}
if keyboard_input.pressed(KeyCode::KeyA) {
transform.translation.x -= 1.0;
}
if keyboard_input.pressed(KeyCode::KeyD) {
transform.translation.x += 1.0;
}
}
}最佳实践
1. 模块组织
- 按功能划分模块,而不是按类型
- 使用清晰的模块层次结构
- 在模块根文件中重新导出常用类型
- 避免过深的模块嵌套
2. 插件设计
- 每个主要功能创建一个插件
- 使用配置结构体自定义插件行为
- 实现插件依赖管理
- 使用条件编译控制插件功能
3. Bundle设计
- 将经常一起使用的组件组合成Bundle
- 提供便捷的构造方法
- 支持参数化配置
- 使用组合模式构建复杂Bundle
4. 系统集管理
- 使用系统集组织相关系统
- 明确定义系统执行顺序
- 使用条件系统集控制执行
- 避免系统集之间的循环依赖
5. 代码组织原则
- 单一职责: 每个模块、插件、系统只负责一个功能
- 开闭原则: 对扩展开放,对修改封闭
- 依赖倒置: 依赖抽象而不是具体实现
- 接口隔离: 提供小而专注的接口
6. 性能考虑
- 合理使用系统集避免不必要的系统执行
- 使用Bundle减少实体创建开销
- 避免在插件初始化时进行复杂计算
- 使用条件系统减少运行时开销
常见模式
1. 功能模块模式
// 每个功能一个模块
mod player {
pub struct PlayerPlugin;
impl Plugin for PlayerPlugin { /* ... */ }
}
mod enemy {
pub struct EnemyPlugin;
impl Plugin for EnemyPlugin { /* ... */ }
}
// 主插件组合所有功能
pub struct GamePlugin;
impl Plugin for GamePlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
player::PlayerPlugin,
enemy::EnemyPlugin,
));
}
}2. 分层架构模式
// 数据层
mod data {
mod components;
mod resources;
}
// 逻辑层
mod logic {
mod systems;
mod events;
}
// 表现层
mod presentation {
mod ui;
mod rendering;
}3. 特性模块模式
// 核心功能
mod core {
pub struct CorePlugin;
}
// 可选功能
#[cfg(feature = "debug")]
mod debug {
pub struct DebugPlugin;
}
#[cfg(feature = "networking")]
mod networking {
pub struct NetworkingPlugin;
}通过合理的代码组织,您可以构建出可维护、可扩展、高性能的Bevy游戏项目。记住,好的代码组织不仅能提高开发效率,还能让团队协作更加顺畅。