6个版本
0.1.5 | 2024年7月21日 |
---|---|
0.1.4 | 2024年7月5日 |
0.1.3 | 2024年5月20日 |
0.1.1 | 2024年3月25日 |
#582 in 游戏开发
303 每月下载量
35KB
244 行
👁️ Moonshine View
为Bevy和Moonshine保存系统设计的通用模型/视图框架。
概述
Moonshine保存系统是故意设计来鼓励用户将持久化游戏状态(模型)与其美学元素(视图)分开。这提供了明确的关注点分离,并在保存框架文档中详细解释了各种好处。
这种方法的缺点是它增加了开发者必须维护的额外复杂性。通常,这涉及手动删除/生成与已保存实体相关联的视图,并通过系统与游戏状态同步。
此crate旨在通过提供更通用、更易用的解决方案来同步游戏视图与游戏状态,从而减少一些这种复杂性。
用法
可视化组件
根据定义,如果可以使用BuildView
为它构建视图,则Component
是可视化的。
Entity
是可视觉化的,如果它至少有一个实现了BuildView
的组件。
use bevy::prelude::*;
use moonshine_core::prelude::*;
use moonshine_view::prelude::*;
#[derive(Component)]
struct Bird;
impl BuildView for Bird {
fn build(world: &World, object: Object<Self>, view: &mut ViewCommands<Self>) {
let asset_server = world.resource::<AssetServer>();
// ...
for child in object.children() {
// ...
}
}
}
// Remember to register viewable types:
let mut app = App::new();
app.register_viewable::<Bird>();
您还可以定义一个Kind
为可视觉化的
use bevy::prelude::*;
use moonshine_core::prelude::*;
use moonshine_view::prelude::*;
#[derive(Component)]
struct Bird;
#[derive(Component)]
struct Monkey;
struct Creature;
impl Kind for Creature {
type Filter = Or<(With<Bird>, With<Monkey>)>;
}
impl BuildView for Creature {
fn build(world: &World, object: Object<Self>, view: &mut ViewCommands<Self>) {
// All creatures look the same!
}
}
// Remember to register viewable types:
let mut app = App::new();
app.register_viewable::<Creature>();
当您想为多种实体的相同视图定义相同的视图时,这很有用。
您甚至可以定义多态视图。
use bevy::prelude::*;
use moonshine_core::prelude::*;
use moonshine_view::prelude::*;
#[derive(Component)]
struct Bird;
#[derive(Component)]
struct Monkey;
struct Creature;
impl Kind for Creature {
type Filter = Or<(With<Bird>, With<Monkey>)>;
}
impl BuildView<Creature> for Bird {
fn build(world: &World, object: Object<Creature>, view: &mut ViewCommands<Creature>) {
// Birds look different, but they're still creatures!
}
}
impl BuildView<Creature> for Monkey {
fn build(world: &World, object: Object<Creature>, view: &mut ViewCommands<Creature>) {
// Monkeys look different, but they're still creatures!
}
}
// Polymorphic views are registered slightly differently:
let mut app = App::new();
app.register_view::<Creature, Bird>()
.register_view::<Creature, Monkey>();
当您想为多种实体的多种类型构建相同视图的不同版本时,这很有用。
可视觉化 ⇄ 视图
当可视觉化实体生成时,会生成一个视图实体。
视图实体是一种至少包含一个 View<T>
组件的实体。每个 View<T>
都通过 Viewable<T>
与其模型实体相关联。
当一个 Viewable<T>
被销毁,或者它不再是 Kind
类型 T
的实例时,与之关联的视图实体也会与之一起销毁。
一起,Viewable<T>
和 View<T>
构成了游戏状态和游戏视图之间的双向链接。
同步
在运行时,通常需要根据视图状态更新视图状态。例如,如果实体的位置发生变化,其视图的位置也应该发生变化。
为了解决这个问题,可以考虑使用一个系统,该系统根据最新的视图状态更新视图(“推送”)或从视图查询视图状态(“拉取”)。
首选“推送”方法,因为它通常会导致每个更新周期迭代次数更少。
use bevy::prelude::*;
use moonshine_core::prelude::*;
use moonshine_view::prelude::*;
#[derive(Component)]
struct Bird;
impl BuildView for Bird {
fn build(world: &World, object: Object<Self>, view: &mut ViewCommands<Self>) {
// ...
}
}
// Update view from viewable, if needed (preferred)
fn view_bird_changed(query: Query<(&Bird, &Viewable<Bird>), Changed<Bird>>) {
for (bird, model) in query.iter() {
let view = model.view();
// ...
}
}
// Query model from view constantly (typically less efficient)
fn view_bird(views: Query<&View<Bird>>, query: Query<&Bird, Changed<Bird>>) {
for view in views.iter() {
let viewable = view.viewable();
if let Ok(bird) = query.get(viewable.entity()) {
// ...
}
}
}
根视图实体自动标记为 Unload
。
这意味着每当加载新的游戏状态时,整个视图实体层次结构都会被销毁。
未类型化视图实体
由于视图系统使用 Kind
来保证类型安全,因此无法通过组件访问特定视图实体的视图。
相反,您可以通过使用 Viewables
资源来查询与实体关联的所有视图。
use bevy::prelude::*;
use moonshine_view::prelude::*;
fn update_views_generic(viewables: Res<Viewables>) {
for viewable_entity in viewables.iter() {
for view_entity in viewables.views(viewable_entity) {
// ...
}
}
}
示例
有关完整使用示例,请参阅 shapes.rs。
支持
请 提交问题,报告任何错误、疑问或建议。
您也可以在官方 Bevy Discord 服务器上联系我,ID 为 @Zeenobit。
依赖项
~16–50MB
~857K SLoC