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() }); }