Reputation: 11
I'm trying to parse a dialogue tree (YAML) in C++ using yaml-cpp. Here's a sample YAML:
dialogue_block:
character_name:
- Hello
- How are you?
- :main
main:
- 1: ["I'm fine, thank you", :response1]
- 2: ["Not very well", :response2]
- 3: ["I don't want to talk", :exit]
I'm relatively new to C++ and Yaml, so if there's an easier/more intuitive way, please point me in the right direction. My idea is to store each block as a dialogue node. In the example above, I want to be able to call on dialogue_block
, and extract character_name
to identify the character speaking, print all of the sequences up to :main
, where it'll switch to the main
node, with 3 choices for the player. I'm currently stuck on step 1 - parsing the yaml file...
The following works...
YAML::Node dialogue = YAML::LoadFile("dialogue.yaml");
if(dialogue["dialogue_block"]){
std::cout << dialogue["dialogue_block"]["character_name"][0].as<std::string>() << "\n";
}
and it prints "Hello". However, I'm stumped on the next steps: how can I retrieve "character_name" without hardcoding the string into my code? Is there a way to print all of the strings leading up to, but not including ":main"? And then make "main" the next node?
First time posting on stackoverflow, so please do let me know if there's more info needed! Thanks.
Edit: Here's the updated code I'm using:
// read in file
YAML::Node dialogue = YAML::LoadFile("dialogue.yaml");
// Extract names of each block
std::vector<std::string> dialogueBlocks;
for (const auto& kv : dialogue) {
dialogueBlocks.push_back(kv.first.as<std::string>());
} // will return "dialogue_block" and "main"
std::string character;
// if first_encounter exists, always start at that block
if(dialogue["first_encounter"]){
for(YAML::iterator it = dialogue["first_encounter"].begin(); it != dialogue["first_encounter"].end(); ++it){
character = it->first.as<std::string>();
std::cout << "\nCharacter: " << character << "\n";
for (YAML::iterator it=dialogue["first_encounter"][character].begin();it!=dialogue["first_encounter"][character].end(); ++it) {
std::cout << it->as<std::string>() << "\n";
}
}
}
I can successfully extract the character name and the dialogue, but there are a few things I'm struggling with: 1) It also prints ":main", which I want it to leave out. I'm not sure how to get it to terminate when it reaches a string starting with ":", or if there's an appropriate built-in function to use. 2) Store ":main" as the next block to pass through the for loop when called upon.
Upvotes: 1
Views: 2909
Reputation: 3908
You're asking how to find the "key name" for the list. You could certainly look at all the keys under dialogue["dialogue_block"]
, but it would be much more idiomatic yaml to make character
a separate field from their lines
, like so
dialogue_block:
character: Bob
lines:
- Hello
- How are you?
- :main
or if a block is intended to be a list,
dialogue_block:
- character: Bob
lines:
- Hello
- How are you?
- :main
- character: Alice
lines:
- Blah
- :main
Upvotes: 0