加载模块记录

基础依赖

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
    }
}

// 加载界面UI标记组件
#[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| {
            // Raven Engine Logo
            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()
                },
            ));

            // Loading 文本
            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>>,
) {
    // 移除所有加载界面UI
    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!("清理加载界面完成");
}