#view #save #bevy #game-state #model-view-controller

moonshine-view

为Bevy设计的通用模型/视图框架

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 游戏开发

Download history 186/week @ 2024-05-04 2/week @ 2024-05-11 206/week @ 2024-05-18 9/week @ 2024-05-25 1/week @ 2024-06-08 128/week @ 2024-06-29 20/week @ 2024-07-06 1/week @ 2024-07-13 139/week @ 2024-07-20 32/week @ 2024-07-27

303 每月下载量

MIT 许可证

35KB
244

👁️ Moonshine View

crates.io downloads docs.rs license stars

为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