Latest commit 07ed1d0

use bevy::{prelude::*, reflect::TypeRegistry, utils::Duration};

/// 从文件加载和保存场景
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .register_type::<ComponentA>()
        .register_type::<ComponentB>()
        //.add_startup_system(保存场景)
        .add_startup_system(保存场景.exclusive_system())
        .add_startup_system(加载场景)
        .add_startup_system(infotext_system)
        .add_system(日志)
        .run();
}

// 注册的组件必须实现'Reflect'和'FromWorld'特型。
// “Reflect”特型支持序列化、反序列化和动态属性访问。
// `Reflect`启用一系列很酷的行为,查看 'Reflect.rs'。
// “FromWorld”特型决定了加载组件时如何构造组件
// 对于简单的用例,可以只实现'Default'特型(它会自动实现FromResources)
// 最简单的注册组件只需要以下两个派生:
#[derive(Component, Reflect, Default)]
#[reflect(Component)] // TODO
struct ComponentA {
    pub x: f32,
    pub y: f32,
}

// 某些组件具有无法(或不应)写入场景文件的字段,可以用#[reflect(ignore)]属性来忽略,
// 这通常也是`FromWorld`特型发挥作用的地方
// `FromWorld`允许在构建组件时访问应用程序当前的ECS`资源`
struct ComponentB {
    pub value: String,
    #[reflect(ignore)]
    pub _time_since_startup: Duration,
}

impl FromWorld for ComponentB {
    fn from_world(world: &mut World) -> Self {
        let time = world.get_reource::<Time>().duration();
        ComponentB {
            _time_since_startup: time.time_since_startup(),
            value: "Default Value".to_string(),
        }
    }
}

fn 加载场景(asset_server: Res<AssetServer>, mut scene_spawner: ResMut<SceneSpawner>) {
    // 像其他资源一样加载场景
    let scene_handle: Handle<DynamicScene> = asset_server.load("scene/load_scene_example.scn.ron");

    // SceneSpawner能生成场景:“生成”一个场景就是在World中生成这个场景的新实例,拥有新的实体ID
    // 这样保证了不会覆盖原有的实体
    scene_spawner.spawn_dynamic(scene_handle);

    // AssetServer监视资产的变化
    // 作用是在修改场景的文件时,在游戏中自动重新加载场景
    asset_server.watch_for_changes().unwrap();
}

// 这个系统记录World中所有的ComponentA
// 尝试在load_scene_example.scn中更改ComponentA,会立即在控制台中看到更改
fn 日志(query: Query<(Entity, &ComponentA), Changed<ComponentA>>) {
    for (entity, component_a) in query.iter() {
        info!("  Entity({})", entity.id());
        info!(
            "  ComponentA:{{x: {} y: {}}}\n",
            component_a.x, component_a.y
        );
    }
}

fn 保存场景(world: &mut World) {
    // 可以从任何ECS世界创建场景
    // 可以为场景创建一个新世界,也可以使用当前世界
    let mut scene_world = World::new();
    let mut component_b = ComponentB::from_world(world);
    component_b.value = "hello".to_string();
    scene_world.spawn().insert_bundle((
        component_b,
        ComponentA { x: 1.0, y: 2.0 },
        Transform::identity(),
    ));
    scene_world
        .spawn()
        .insert_bundle((ComponentA { x: 3.0, y: 4.0 },));

    // TypeRegistry资源包含有关所有已注册类型(包括组件)的信息,用于构造场景
    let type_registry = world.get_resource::<TypeRegistry>().unwrap();
    let scene = DynamicScene::from_world(&scene_world, type_registry);

    // 场景可以按如下方式序列化:
    info!("{}", scene.serialize_ron(type_registry).unwrap());

    // TODO: save scene
}

// 这仅对UI中的信息消息是必需的
// 有关独立文本的示例,查看examples/ui/text.rs
fn infotext_system(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn_bundle(UiCameraBundle::default());
    commands.spawn_bundle(TextBundle {
        style: Style {
            align_self: AlignSelf::FlexEnd,
            ..Default::default()
        },
        text: Text::with_section(
            "这个窗口没有东西显示!检查控制台输出!",
            TextStyle {
                font: asset_server.load("fonts/xxx.ttf"),
                font_size: 50.0,
                color: Color::WHITE,
            },
            Default::default()
        ),
        ..Default::default()
    });
}