加载模块记录
基础依赖
bevy = { version = "0.17" }
加载模块
use bevy::prelude::*;
use crate::GameState;
pub struct LoadingPlugin;
#[derive(Resource)]
pub struct FontAssets {
pub default: Handle<Font>,
pub regular: Handle<Font>,
}
#[derive(Resource)]
pub struct ImageAssets {
pub background: Handle<Image>,
pub main_menu: Handle<Image>,
}
#[derive(Resource)]
struct LoadingProgress {
fonts_loaded: bool,
images_loaded: bool,
}
impl LoadingProgress {
fn is_complete(&self) -> bool {
self.fonts_loaded && self.images_loaded
}
}
#[derive(Component)]
struct LoadingUI;
impl Plugin for LoadingPlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(GameState::Loading), (setup_loading_camera, load_assets))
.add_systems(
Update,
(check_assets_loaded, update_loading_display).run_if(in_state(GameState::Loading))
)
.add_systems(OnExit(GameState::Loading), cleanup_loading);
}
}
fn setup_loading_camera(mut commands: Commands) {
println!("进入Loading状态");
commands.spawn(Camera2d);
}
fn load_assets(
mut commands: Commands,
asset_server: Res<AssetServer>,
) {
println!("开始加载资源...");
let font_assets = FontAssets {
default: asset_server.load("fonts/SarasaFixedHC-Regular.ttf"),
regular: asset_server.load("fonts/SarasaFixedHC-Regular.ttf"),
};
let image_assets = ImageAssets {
background: asset_server.load("gui/game3.png"),
main_menu: asset_server.load("gui/main_menu.png"),
};
commands.insert_resource(font_assets);
commands.insert_resource(image_assets);
commands.insert_resource(LoadingProgress {
fonts_loaded: false,
images_loaded: false,
});
create_loading_ui(&mut commands);
}
fn create_loading_ui(commands: &mut Commands) {
commands
.spawn((
LoadingUI,
Node {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
flex_direction: FlexDirection::Column,
..default()
},
BackgroundColor(Color::BLACK),
))
.with_children(|parent| {
parent.spawn((
Text::new("Raven Engine"),
TextFont {
font_size: 64.0,
..default()
},
TextColor(Color::srgb(1.0, 0.8, 0.0)),
Node {
margin: UiRect::bottom(Val::Px(50.0)),
..default()
},
));
parent.spawn((
LoadingUI,
Text::new("Loading..."),
TextFont {
font_size: 32.0,
..default()
},
TextColor(Color::WHITE),
));
});
}
fn check_assets_loaded(
asset_server: Res<AssetServer>,
font_assets: Option<Res<FontAssets>>,
image_assets: Option<Res<ImageAssets>>,
mut loading_progress: ResMut<LoadingProgress>,
mut next_state: ResMut<NextState<GameState>>,
) {
if loading_progress.is_complete() {
return;
}
if !loading_progress.fonts_loaded {
if let Some(fonts) = font_assets.as_ref() {
let default_loaded = matches!(
asset_server.load_state(fonts.default.id()),
bevy::asset::LoadState::Loaded | bevy::asset::LoadState::Failed(_)
);
let regular_loaded = matches!(
asset_server.load_state(fonts.regular.id()),
bevy::asset::LoadState::Loaded | bevy::asset::LoadState::Failed(_)
);
if default_loaded && regular_loaded {
loading_progress.fonts_loaded = true;
println!("字体加载完成");
}
}
}
if !loading_progress.images_loaded {
if let Some(images) = image_assets.as_ref() {
let background_loaded = matches!(
asset_server.load_state(images.background.id()),
bevy::asset::LoadState::Loaded | bevy::asset::LoadState::Failed(_)
);
let main_menu_loaded = matches!(
asset_server.load_state(images.main_menu.id()),
bevy::asset::LoadState::Loaded | bevy::asset::LoadState::Failed(_)
);
if background_loaded && main_menu_loaded {
loading_progress.images_loaded = true;
println!("图片加载完成");
}
}
}
if loading_progress.is_complete() {
println!("所有资源加载完成!切换到菜单状态");
next_state.set(GameState::Menu);
}
}
fn update_loading_display(
mut loading_text_query: Query<&mut Text, With<LoadingUI>>,
time: Res<Time>,
mut timer: Local<Timer>,
) {
if timer.duration().is_zero() {
*timer = Timer::from_seconds(0.5, TimerMode::Repeating);
}
timer.tick(time.delta());
if timer.just_finished() {
for mut text in loading_text_query.iter_mut() {
if text.0.starts_with("Loading") {
let dots_count = text.0.matches('.').count();
let next_dots = match dots_count {
0 => ".",
1 => "..",
2 => "...",
_ => "",
};
text.0 = format!("Loading{}", next_dots);
}
}
}
}
fn cleanup_loading(
mut commands: Commands,
loading_ui_query: Query<Entity, With<LoadingUI>>,
camera_query: Query<Entity, With<Camera>>,
) {
for entity in loading_ui_query.iter() {
commands.entity(entity).despawn();
}
for entity in camera_query.iter() {
commands.entity(entity).despawn();
}
commands.remove_resource::<LoadingProgress>();
println!("清理加载界面完成");
}