Skip to content

Commit ffa44e8

Browse files
committed
docs(README): prepare for 0.4.0
1 parent b711047 commit ffa44e8

File tree

2 files changed

+128
-78
lines changed

2 files changed

+128
-78
lines changed

Diff for: README.md

+121-71
Original file line numberDiff line numberDiff line change
@@ -10,177 +10,227 @@
1010
> [!WARNING]
1111
> Be aware that `bevy_talks`'s API is still undergoing revisions (with possibly big architectural changes). Feedback on its ergonomics and developer experience (DX) is highly appreciated.
1212
13+
This [Bevy][bevy] plugin provides a way to create dialogues and conversations in your game as graphs.
1314

14-
This [Bevy][bevy] plugin provides a way to create dialogues and conversations in your game, via *Talk*s components.
15-
A *Talk* is a directed graph where each node is an *action* that an actor can perform,
16-
such as saying a line, joining/leaving the scene, or even a choice the player can make.
15+
You can imagine a *Talk* between the player and NPCs as a directed graph where each node is an *action* that can be performed
16+
such as saying a line, joining/leaving the conversation, or a choice the player can make.
1717

1818
The most common action is text being displayed on the screen, and a simple *Talk* is
1919
just a sequence of texts forming a conversation between actors.
2020

21-
You can have multiple entities each with their own *Talk*. Or you can make a VN-like game with one single Talk in the game.
21+
You can have multiple entities each with their own *Talk* graph. Or you can make a VN-like game with one single big dialogue graph in the game.
2222

23-
The heart of the Talk is a directed graph where each node is a `TalkNode` struct:
23+
> [!NOTE]
24+
> A more in-depth documentation is being slowly written as an [mdbook here!](giusdp.github.io/bevy_talks/) Help is appreciated :)
25+
26+
## Actions and Actors
27+
28+
Talks are made up of actions that are translated into graph nodes.
29+
Actions can be defined either via the `TalkBuilder` of with asset files and they have this form:
2430

2531
```rust
26-
struct TalkNode {
27-
/// Talk, Join, Leave, Choice
28-
kind: TalkNodeKind,
29-
/// Text to display on the screen.
30-
text: String,
32+
struct Action {
33+
/// The ID of the action.
34+
id: ActionId,
35+
/// The kind of action.
36+
action: NodeKind,
3137
/// The actors involved in the action.
32-
actors: Vec<Actor>,
33-
/// The choices available for the player
34-
choices: Vec<Choice>,
38+
actors: Vec<ActorSlug>,
39+
/// Any choices that the user can make during the action.
40+
choices: Option<Vec<Choice>>,
41+
/// The text of the action.
42+
text: Option<String>,
43+
/// The ID of the next action to perform.
44+
next: Option<ActionId>,
3545
}
3646
```
47+
48+
You won't be writing this struct directly, but you can see that it contains several fields that define the kind of action it can be, the relevant actors, text or choices and the next action to perform (where to go in the graph after).
49+
50+
The actors are quite simple right now. It is just the name and an identifier (the slug).
51+
3752
The `Actor` struct is a simple struct that contains the name of the actor and the asset to display on the screen.
3853

3954
```rust
4055
struct Actor {
41-
/// The name of the character that the actor plays.
56+
/// The name of the actor.
4257
name: String,
43-
/// An optional asset for the actor.
44-
asset: Option<Handle<Image>>,
58+
/// The unique slug of the actor.
59+
slug: ActorSlug,
4560
}
4661
```
4762

48-
The Choice struct is a simple struct that contains the text of the choice and the index of the node to jump to.
63+
Having a well defined *Talk* with actions and actors will result in spawning a graph where all the nodes are entities.
64+
Each action will be an entity "node", and each actor is also an entity.
65+
66+
All the action nodes will be connected with each other with a aery relationship (called *FollowedBy*), following the graph structure given by the actions next and id fields, and each action with actors will result in the corresponding entity being connected with the actors entity with another aery relationship (called *PerformedBy*).
67+
68+
Finally all the action entities in the graph will be a child of a main entity that represents the *Talk* itself, with the *Talk* component attached to it.
69+
70+
## The Talk Component
71+
72+
This parent Talk component that "encapsulates" the graph is the main component that you will use to interact with the dialogue system.
73+
With it you can keep track of the current node data, and use it to send events to advance the dialogue (through the related entity).
4974

5075
```rust
51-
struct Choice {
52-
/// The text of the choice.
53-
pub text: String,
54-
/// The ID of the next action to jump to if the choice is selected.
55-
pub next: NodeIndex,
76+
/// The Talk component. It's used to identify the parent entity of dialogue entity graphs.
77+
#[derive(Component, Debug)]
78+
pub struct Talk {
79+
/// The text of the current node (if not a Talk node it's empty)
80+
pub current_text: String,
81+
/// The kind of the current node
82+
pub current_kind: NodeKind,
83+
/// The actor(s) name of the current node
84+
pub current_actors: Vec<String>,
85+
/// The choices of the current node (if not a Choice node it's empty)
86+
pub current_choices: Vec<Choice>,
5687
}
5788
```
5889

59-
### Build Talks from talk.ron files
90+
## Build Talks from talk.ron files
6091

61-
The plugin can parse ron files to create `RawTalk` assets, which can then be used to build a `Talk` component.
92+
The plugin can parse ron files to create `TalkData` assets, which can then be used to build the graph.
6293
The files must have the extension: `talk.ron`.
6394

6495
Here's an example:
6596

6697
```rust,ignore
6798
(
6899
actors: [
69-
( id: "bob", name: "Bob" ),
70-
( id: "alice", name: "Alice" )
100+
( slug: "bob", name: "Bob" ),
101+
( slug: "alice", name: "Alice" )
71102
],
72103
script: [
73-
( id: 1, action: Talk, text: Some("Bob and Alice enter the room.") ),
74-
( id: 2, action: Join, actors: [ "bob", "alice" ] ),
75-
( id: 3, actors: ["bob"], text: Some("Hello, Alice!") ), // with missing action field, it defaults to Talk
104+
( id: 1, action: Talk, text: Some("Bob and Alice enter the room."), next: Some(2) ),
105+
( id: 2, action: Join, actors: [ "bob", "alice" ], next: Some(3)),
106+
( id: 3, actors: ["bob"], text: Some("Hello, Alice!"), next: Some(4) ), // without the action field, it defaults to Talk
76107
(
77108
id: 4,
78109
choices: Some([
79110
( text: "Alice says hello back.", next: 5 ),
80111
( text: "Alice ignores Bob.", next: 6 ),
81112
])
82113
),
83-
( id: 5, text: Some("Bob smiles.") ), // with missing actors field, it defaults to an empty vector
84-
( id: 6, text: Some("Bob starts crying.") ),
85-
( id: 7, text: Some("The end.") )
114+
( id: 5, text: Some("Bob smiles."), next: Some(7)), // without the actors field, it defaults to an empty vector
115+
( id: 6, text: Some("Bob starts crying."), next: Some(7) ),
116+
( id: 7, text: Some("The end.") ) // without the next, it is an end node
86117
]
87118
)
88119
```
89120

90121
The plugin adds an `AssetLoader` for these ron files, so it's as easy as:
91122

92123
```rust
93-
let handle: Handle<RawTalk> = asset_server.load("simple.talk.ron");
124+
let handle: Handle<TalkData> = asset_server.load("simple.talk.ron");
94125
```
95126

96-
Then you can use `Talk::build` function with the `RawTalk` asset.
97-
You can retrieve the `RawTalk` from the assets collection `raws: Res<Assets<RawTalk>>`.
127+
Then you can use `Talk::builder()` to create a `TalkBuilder`, which has the `fill_from_talk_data` method.
128+
You can retrieve the `TalkData` from the assets collection `talks: Res<Assets<TalkData>>`.
129+
130+
131+
With the builder ready, you can use the Commands extension to spawn the dialogue graph in the world:
98132

99133
```rust
100-
let raw_sp = raws.get(&simple_sp_asset.handle).unwrap();
101-
Talk::build(&raw_sp)
102-
```
134+
use bevy::prelude::*;
135+
use bevy_talks::prelude::*;
103136

104-
### Usage
137+
// We stored the previously loaded handle of a TalkData asset in this resource
138+
#[derive(Resource)]
139+
struct TalkAsset {
140+
handle: Handle<TalkData>,
141+
}
105142

143+
fn spawn(mut commands: Commands, talks: Res<Assets<TalkData>>, talk_asset: Res<TalkAsset>) {
144+
let talk = talks.get(&talk_asset.handle).unwrap();
145+
let talk_builder = TalkBuilder::default().fill_from_talk_data(simple_talk);
106146

107-
The plugin provides a `TalkerBundle` to give an entity the required components to handle its own dialogues.
108-
```rust
109-
struct TalkerBundle {
110-
/// The Talk to display.
111-
talk: Talk,
112-
/// The dialogue line component for a Talk.
113-
talk_text: CurrentText,
114-
/// The actor component that represents a character in a Talk.
115-
current_actors: CurrentActors,
116-
/// The Talk Node Kind component that represents the kind of action in a Talk.
117-
kind: CurrentNodeKind,
118-
/// The component that represents the current choices in a Talk.
119-
current_choices: CurrentChoices,
147+
// grab the talk commands
148+
let mut talk_commands = commands.talks();
149+
// spawn the talk graph
150+
talk_commands.spawn_talk(talk_builder, ());
120151
}
121152
```
122153

123-
With these components you can query the current text/actor/choices for the current action in a talk.
154+
Spawning that talk graph will result in this:
155+
156+
157+
```mermaid
158+
graph LR;
159+
A[Narrator Talks] --> B[Alice,Bob Join];
160+
B --> C[Bob Talks];
161+
C --> D[Choice];
162+
D --> E[Narrator Talks];
163+
D --> F[Narrator Talks];
164+
F --> G[Narrator Talks];
165+
E --> G;
166+
```
167+
168+
## Usage
169+
170+
With the `Talk` component you can get the current text/actor/choices for the current action in a talk.
124171
Together with the Change Detection System, you can react to changes in the `Talk` component to update your UI.
125172

126173
```rust
127-
fn print_text(talks: Query<(Ref<CurrentText> &CurrentNodeKind)>) {
128-
for (text, kind) in talks.iter() {
129-
if kind == TalkNodeKind::Talk && text.is_changed() {
174+
fn print_text(talks: Query<Ref<Talk>>) {
175+
for talk in talks.iter() {
176+
if text.is_changed() && talk.current_kind == NodeKind::Talk {
130177
println!("{}", text.text());
131178
}
132179
}
133180
}
134181
```
135182

136-
To interact with Talks you can send 3 different events. One to initialize the Talk (it populates the components with the first node), and two to advance the Talk to the next node or to jump to a specific node):
137-
138-
```rust
139-
struct InitTalkRequest(pub Entity);
140-
```
183+
To interact with the dialogue graphs you can send 2 different events to advance the Talk to the next node or to jump to a specific node:
141184

142185
To move forward to the next action:
143186

144187
```rust
145-
NextActionRequest(pub Entity);
188+
pub struct NextActionRequest(pub Entity);
146189
```
147190

148191
To jump to a specific action (used with choices):
149192

150193
```rust
151-
JumpToActionRequest(pub Entity, pub NodeIndex);
194+
pub struct ChooseActionRequest {
195+
/// The entity with the [`Talk`] component you want to update.
196+
pub talk: Entity,
197+
/// The next entity to go to.
198+
pub next: Entity,
199+
}
152200
```
153201

154-
You pass the entity with the `Talk` component for the first 2 events.
155-
The third required the entity and the index that identifies the node to jump to.
202+
You pass the entity with the `Talk` component in these events, plus the next node entity in case of the choose event.
156203

157-
Check out the example in the `examples` folder to see how to use the plugin.
204+
Check out the `examples` folder to see how to use the plugin.
158205

159206
- [simple.rs](examples/simple.rs) shows how to use the plugin to create a simple, linear conversation.
160207
- [choices.rs](examples/choices.rs) shows how to use the plugin to create a conversation with choices (jumps in the graph).
161208
- [full.rs](examples/full.rs) shows a Talk where all the action kinds are used.
162-
- [ingame.rs](examples/ingame.rs) shows how to use the plugin with more than one `Talker` entity you can interact with.
209+
- [ingame.rs](examples/ingame.rs) shows how to use the plugin with more than one talk you can interact with.
163210

164211
### Roadmap
165212

166-
- [x] A `TalkerBundle` to give an entity the required components to access and track the dialogues
213+
Some nice-to-haves from the top of my head:
214+
215+
- [ ] Use the built-in bevy_ecs relations (when one day we will have them)
167216
- [ ] Dialogue UIs
168-
- [ ] Interaction/Trigger system (to activate/advance dialogues)
217+
- [ ] Extensible Interaction/Trigger system (to activate/advance dialogues)
169218
- [ ] Graphical editor to create the asset files
170219
- [ ] Voice lines/sound support
220+
- [ ] More node kinds (and a custom node kind system)
171221
- [ ] Support other asset formats (?)
172222
- [ ] More examples
173-
- [ ] Extensive documentation/manual wiki
223+
- [ ] Extensive documentation/manual wiki (always in progress...)
174224
- [ ] Localization with [Fluent](https://projectfluent.org/)
175225

176-
177226
### Bevy Version Support
178227

179228

180229
Compatibility of `bevy_talks` versions:
181230
| `bevy_talks` | `bevy` |
182231
| :-- | :-- |
183232
| `main` | `0.12` |
233+
| `0.4.0` | `0.12` |
184234
| `0.3.1` | `0.12` |
185235
| `0.3.0` | `0.11` |
186236
| `0.2.0` | `0.11` |

Diff for: docs/src/index.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ You can have multiple entities each with their own *Talk* graph. Or you can make
2323
> [!NOTE]
2424
> A more in-depth documentation is being slowly written as an [mdbook here!](giusdp.github.io/bevy_talks/) Help is appreciated :)
2525
26-
## Actions and Actors
26+
## Actions and Actors
2727

2828
Talks are made up of actions that are translated into graph nodes.
2929
Actions can be defined either via the `TalkBuilder` of with asset files and they have this form:
@@ -53,7 +53,6 @@ The `Actor` struct is a simple struct that contains the name of the actor and th
5353

5454
```rust
5555
struct Actor {
56-
5756
/// The name of the actor.
5857
name: String,
5958
/// The unique slug of the actor.
@@ -68,7 +67,7 @@ All the action nodes will be connected with each other with a aery relationship
6867

6968
Finally all the action entities in the graph will be a child of a main entity that represents the *Talk* itself, with the *Talk* component attached to it.
7069

71-
### The Talk Component
70+
## The Talk Component
7271

7372
This parent Talk component that "encapsulates" the graph is the main component that you will use to interact with the dialogue system.
7473
With it you can keep track of the current node data, and use it to send events to advance the dialogue (through the related entity).
@@ -88,7 +87,7 @@ pub struct Talk {
8887
}
8988
```
9089

91-
### Build Talks from talk.ron files
90+
## Build Talks from talk.ron files
9291

9392
The plugin can parse ron files to create `TalkData` assets, which can then be used to build the graph.
9493
The files must have the extension: `talk.ron`.
@@ -112,7 +111,7 @@ Here's an example:
112111
( text: "Alice ignores Bob.", next: 6 ),
113112
])
114113
),
115-
( id: 5, text: Some("Bob smiles."), next: Some(6)), // without the actors field, it defaults to an empty vector
114+
( id: 5, text: Some("Bob smiles."), next: Some(7)), // without the actors field, it defaults to an empty vector
116115
( id: 6, text: Some("Bob starts crying."), next: Some(7) ),
117116
( id: 7, text: Some("The end.") ) // without the next, it is an end node
118117
]
@@ -156,16 +155,17 @@ Spawning that talk graph will result in this:
156155

157156

158157
```mermaid
159-
graph TD;
158+
graph LR;
160159
A[Narrator Talks] --> B[Alice,Bob Join];
161160
B --> C[Bob Talks];
162161
C --> D[Choice];
163162
D --> E[Narrator Talks];
164163
D --> F[Narrator Talks];
165164
F --> G[Narrator Talks];
165+
E --> G;
166166
```
167167

168-
### Usage
168+
## Usage
169169

170170
With the `Talk` component you can get the current text/actor/choices for the current action in a talk.
171171
Together with the Change Detection System, you can react to changes in the `Talk` component to update your UI.

0 commit comments

Comments
 (0)