How to express branching dialogue with Bevy ECS? #6510
-
I'm new to Bevy and somewhat new to Rust, and I'm evaluating Bevy for a dialogue-based RPG. I'm trying to express branching dialogues with Bevy's ECS. Getting a rudimentary data structure in place was straightforward, but I'm unclear on how to access the components of a specific entity, in this case the next statement after the user chooses a reply. I feel like I'm missing something fundamental here. Is this even the right way to frame the problem in Bevy? Here is my code so far, defining a rudimentary data structure and creating some dummy data: use bevy::prelude::*;
#[derive(Component)]
struct Character
{
name: String
}
#[derive(Component)]
struct Statement
{
text: String,
speaker: Option<Entity>,
next: Option<Entity>
}
struct Choice
{
text: String,
next: Option<Entity>
}
#[derive(Component)]
struct Junction
{
choices: Vec<Choice>
}
fn add_entities(mut commands: Commands) {
let character = commands.spawn().insert(Character{name: "Character name".to_string()}).id();
let char_statement = commands.spawn().insert(Statement{text: "Character statement.".to_string(), speaker: Some(character), next: None})
.insert(Junction{ choices: vec!(
Choice{text: "Choice 1.".to_string(), next: None},
Choice{text: "Choice 2.".to_string(), next: None})
})
.id();
let first_statement = commands.spawn().insert(Statement{text: "Narration statement.".to_string(), speaker: None, next: Some(char_statement)}).id();
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 4 replies
-
I implemented something similar for cutscenes in one of my projects, I'm not sure how practical it is etc though. To access the individual entities and their components you can use queries: #[derive(Resource)]
struct CurrentNarrationNode(Option<Entity>);
fn statement_system(
mut node: ResMut<CurrentNarrationNode>,
statements: Query<&Statement>,
characters: Query<&Character>,
) {
if let Some(statement) = node.0.and_then(|id| statements.get(id).ok()) {
let name = statement.speaker
.and_then(|id| characters.get(id).ok())
.map(|character| character.name.as_str())
.unwrap_or("unnamed");
println!("{name}: {}", statement.text);
node.0 = statement.next;
}
} |
Beta Was this translation helpful? Give feedback.
I implemented something similar for cutscenes in one of my projects, I'm not sure how practical it is etc though.
A more granular design might fit more naturally with Bevy's ECS. For instance, the components like Character, Statement, Junction, Choice and Junction could be empty Marker Components, and Name, Text, Speaker, Next and Choices could be POD newtype components.
To access the individual entities and their components you can use queries: