After the dialogues as entity-graph refactor it would be nice to move away from the single point of access approach (the parent entity with the Talk
component). Instead an user should be able to interact with the nodes directly (by making CurrentNode component public so it can be queried).
The Talk
parent is still needed to be able to differentiate between multiple dialogue graphs and identify which dialogue graph to advance with the NextActionRequest and ChooseActionRequest events.
We can add events from the dialogue graph to the outside (the other direction) so that it is possible to react to the changes in the dialogue graph (just moving from one node to another). Having direct access to the nodes and having the nodes send events would make the dialogue graphs way more flexible and customizable.
I have a working demo using bevy-trait-query and this trait:
#[bevy_trait_query::queryable]
pub trait NodeEventEmitter {
/// Creates an event to be emitted when a node is reached.
fn make(&self, actors: &[Entity]) -> Box<dyn Reflect>;
}
Moving to a node with text will result in an event being sent that I defined as:
/// Emitted when a text node is reached.
#[derive(Event, Reflect, Default, Clone)]
#[reflect(Event)]
pub struct TextNodeEvent {
/// The text from the node.
pub text: String,
/// The actors from the node.
pub actors: Vec<Entity>,
}
Now a "Text Node" in a dialogue graph is a component:
/// Component to mark a dialogue node as a text node containing some text.
#[derive(Component, Default, Debug)]
pub struct TextNode(pub String);
impl NodeEventEmitter for TextNode {
fn make(&self, actors: &[Entity]) -> Box<dyn Reflect> {
Box::from(TextNodeEvent {
text: self.0.clone(),
actors: actors.to_vec(),
})
}
}
Note that the "actors" are automatically injected by the plugin.
This is a complete implementation of a component for a dialogue node that will enable the node to send an event when reached.
Also the Join, Leave and Choice nodes are defined as components with the relative events attached.
For the users it will unlock the possibility to add any custom component to nodes that can optionally emit events (the TalkBuilder will need to be updated for that).
Reactive to events instead of checking the Talk entity fields also simplify the API. Now you can have multiple smaller systems that just listen to the events (join, leave, text, choice + custom ones)
This needs some cleaning and testing + all the boilerplate to enable events attached to components can be stuffed inside a macro.