#bevy-plugin #plugin #dialog #bevy #gamedev #graph-node #directed-graph

已删除 bevy_screenplay

一个用于编写角色台词和行为的 Bevy 插件,包括玩家的选择

0.2.0 2023年8月24日

#51 in #directed-graph

MIT/Apache

52KB
753 代码行

Bevy Screenplay

Bevy 插件提供了一种在游戏中通过 剧本 创建对话和对话的方式。一个 剧本 是一个有向图,其中每个节点都是一个可以发生的 动作。动作通常是演员可以做的事情,例如说台词、进入/退出场景,甚至是玩家可以做出的选择等。

由于最常见的动作是在屏幕上显示文本,最基本的 剧本 是由演员之间对话组成的文本序列,形成一个动作的线性图。

剧本是一个可以附加到实体的 Bevy 组件。这样,您可以拥有多个具有自己剧本的实体,因此每个实体都有自己的对话。或者,如果您想制作类似视觉小说的游戏,您可以在游戏中使用一个单一的剧本。

剧本的核心是一个有向图,其中每个节点都是一个 ActionNode

struct ActionNode {
    /// The kind of action.
    kind: ActionKind,
    /// The text of the action.
    text: Option<String>,
    /// The actors involved in the action.
    actors: Vec<Actor>,
    /// The choices available after the action.
    choices: Option<Vec<Choice>>,
    /// The sound effect associated with the action.
    sound_effect: Option<String>,
}

此结构定义了可以发生的动作。

  • kind 字段定义了动作的类型(说话、进入、退出、选择)。
  • text 字段是要在屏幕上显示的文本。
  • actors 字段是参与动作的演员列表。
  • choices 字段是提供给玩家的可选列表。
  • sound_effect 字段是一个额外的字段,用于指定在动作达到时播放的声音效果。

Actor 结构是一个简单的结构,其中包含演员的名称和在屏幕上显示的资产。

struct Actor {
    /// The name of the character that the actor plays.
    name: String,
    /// An optional asset that represents the actor's appearance or voice.
    asset: Option<String>,
}

如果一个动作定义了一个或多个演员,则可以访问它们以获取要显示的名称(以及资产)和文本。

从 screenplay.ron 文件构建剧本

此插件可以解析 ron 文件以创建 RawScreenplay 资产,然后可以使用这些资产构建 Screenplay 组件。文件必须具有扩展名:screenplay.ron

以下是一个示例

(
    actors: [
        ( id: "bob", name: "Bob", asset: Some("bob.png") ),
        ( id: "alice", name: "Alice", asset: Some("alice.png") )
    ],
    script: [
        ( id: 1, action: Talk, text: Some("Bob and Alice enter the room.") ),
        ( id: 2, action: Enter, actors: [ "bob", "alice" ] ),
        ( id: 3, actors: ["bob"], text: Some("Hello, Alice!") ), // with missing action field, it defaults to Talk
        (
            id: 4,
            choices: Some([
                ( text: "Alice says hello back.", next: 5 ),
                ( text: "Alice ignores Bob.", next: 6 ),
            ])
        ),
        ( id: 5, text: Some("Bob smiles.") ), // with missing actors field, it defaults to an empty vector
        ( id: 6, text: Some("Bob starts crying.") ),
        ( id: 7, text: Some("The end.") )
    ]
)

此插件为这些 ron 文件添加了一个 AssetLoader,因此它非常简单

let handle: Handle<RawScreenplay> = server.load("simple.screenplay.ron");

然后,您可以使用 ScreenplayBuilderRawScreenplay 资产构建一个 Screenplay 组件。您可以从资产集合 raws: Res<Assets<RawScreenplay>> 中检索 RawScreenplay

let raw_sp = raws.get(&simple_sp_asset.handle).unwrap();
ScreenplayBuilder::new().build(&raw_sp);

用法

一旦将 Screenplay 组件附加到一个实体上,您就可以使用常规的 Bevy Query 来访问它,以检索有关当前动作(文本、选择、涉及的演员、动作类型)的信息。

要移动到下一个动作(或跳转到特定的动作),您可以发送两个不同的事件,并利用变更检测系统在 Screenplay 组件发生更改后做出反应。

跳转到下一个动作的事件

NextActionRequest(pub Entity);

跳转到特定动作的事件

JumpToActionRequest(pub Entity, pub ActionId);

对于前者事件,您传递具有 Screenplay 组件的实体,而对于后者事件,您传递具有 Screenplay 组件和要跳转到的动作 ID 的实体。

插件将内部调用 Screenplay 组件的 next_actionjump_to 方法。

在您的一侧,您可以使用 Changed API 在发送这些事件后对这些更改做出反应。例如

fn print_text(screenplays: Query<&Screenplay, Changed<Screenplay>>) {
    for sp in screenplays.iter() {
        println!("{}", sp.text());
    }
}

该组件提供公共 API 以从图中检索信息

  • actors 返回当前动作中涉及的演员列表。
  • choices 返回当前动作中可用的选择列表。
  • text 返回当前动作的文本。
  • action_kind 返回当前动作的类型。

查看 examples 文件夹中的示例,了解如何使用此插件。

  • simple.rs 展示了如何使用插件创建简单的、线性的对话。
  • choices.rs 展示了如何使用插件创建具有选择的对话。
  • full.rs 展示了一个使用所有动作类型的剧本。

其他事项

未来的工作是拥有一个图形编辑器来创建这些文件,但到目前为止,我们必须手动编写它们。欢迎任何贡献!

bevy_screenplay 版本的兼容性

bevy_screenplay bevy
main 0.11
0.2.0 0.11
0.1.1 0.11

许可证

双重许可以下任一项

任选其一。

贡献

除非您明确声明,否则您有意提交以包含在作品中并由您定义的任何贡献,根据 Apache-2.0 许可证,应按上述方式双重许可,无需任何附加条款或条件。

依赖项

~21–52MB
~841K SLoC