Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Prosty System Dialogów

Ostatnio zmodyfikowano 2024-06-06 02:26
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
Prosty System Dialogów
» 2024-06-02 20:56:50
Witam. Napisałem prosty system Dialogów. Co o nim sądzicie ?

C/C++
#ifndef Dialogues_hpp
#define Dialogues_hpp

class DialogueOption {
public:
   
string text;
   
int nextDialogueID;
   
   
DialogueOption( string text, int nextDialogueID ) {
       
this->text = text;
       
this->nextDialogueID = nextDialogueID;
       
   
}
}
;

class Dialogue {
public:
   
int id;
   
string text;
   
std::vector < DialogueOption > options;
   
   
Dialogue( int id, string text ) {
       
this->id = id;
       
this->text = text;
   
}
}
;

std::vector < Dialogue * > dialogues;
Dialogue * currentDialogue;

enum class dialogueStates { dialogue, choose };

dialogueStates dialogueState;
int chooseOption = 0;

void loadDialogues() {
   
dialogues.clear();
   
   
Dialogue * dial0 = new Dialogue( 0, "Witam w grze One - The Beginning." );
   
dial0->options.push_back( DialogueOption( "ok", - 1 ) );
   
   
Dialogue * dial1 = new Dialogue( 1, "Witaj w czym mogę Ci pomóc?" );
   
dial1->options.push_back( DialogueOption( "Kim Jesteś?", 2 ) );
   
dial1->options.push_back( DialogueOption( "Co tutaj robisz?", 3 ) );
   
dial1->options.push_back( DialogueOption( "Żegnaj.", - 1 ) );
   
dialogues.push_back( dial1 );
   
   
Dialogue * dial2 = new Dialogue( 2, "Nazywam się Jack i jestem handlarzem, chcesz może rzucić okiem na moje towary?" );
   
dial2->options.push_back( DialogueOption( "Kim Jesteś?", 2 ) );
   
dial2->options.push_back( DialogueOption( "Co tutaj robisz?", 3 ) );
   
dial2->options.push_back( DialogueOption( "Żegnaj.", - 1 ) );
   
dialogues.push_back( dial2 );
   
   
Dialogue * dial3 = new Dialogue( 3, "Hanlduje towarami, a na co Ci to wygląda?" );
   
dial3->options.push_back( DialogueOption( "Kim Jesteś?", 2 ) );
   
dial3->options.push_back( DialogueOption( "Co tutaj robisz?", 3 ) );
   
dial3->options.push_back( DialogueOption( "Żegnaj.", - 1 ) );
   
dialogues.push_back( dial3 );
   
   
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   
   
Dialogue * dial4 = new Dialogue( 4, "Czego chcesz od starego Johna. Daj mi spokój" );
   
dial4->options.push_back( DialogueOption( "Ja tylko chciałem...", - 1 ) );
   
dialogues.push_back( dial4 );
}

Dialogue * getDialogue( int id ) {
   
for( auto & d: dialogues )
   
if( d->id == id )
       
 return d;
   
   
cout << "incorrect dialog id\n";
   
return nullptr;
}
#endif
P-181165
pekfos
» 2024-06-02 22:30:01
Jeśli działa, to działa. Undertale ma dialogi w jednym wielkim switch case, więc Twój mechanizm nie jest złym pierwszym podejściem ;)
Co do samego kodu
  • Menu na 10 opcji musi być powtórzone 10 razy - może mechanizm powinien pozwalać na uniknięcie tych powtórzeń?
  • Co jeśli będziesz chciał mieć w menu opcję dostępną warunkowo? Prędzej czy później będziesz chciał dodać system zadań, a ten będzie związany z dialogami.
Powtórzenia możesz wyeliminować rozdzielając opcje dialogowe od wyświetlanego tekstu. Na przykład:
P-181167
tBane
Temat założony przez niniejszego użytkownika
» 2024-06-03 18:47:10
No właśnie jeszcze nie zastanawiałem się nad tym. Pewnie będzie trzeba stworzyć cały system skryptów.

Na początek stworzyłem dialog, który będzie potrzebował dodatkowego przetwarzania tzn. będzie potrzebował jakiegoś skryptu, który sprawdzi czy gracz posiada określony item w danej ilości.

Dialogue* dial5 = new Dialogue(5, L"Czego chcesz?");
dial5->options.push_back(DialogueOption(L"Kim jesteś?", 6));
dial5->options.push_back(DialogueOption(L"Co tutaj robisz?", 7));
dial5->options.push_back(DialogueOption(L"Mam skórę wilczura, chcesz ją odkupić?", 8));
dial5->options.push_back(DialogueOption(L"Żegnaj", -1));
dialogues.push_back(dial5);

Dialogue* dial6 = new Dialogue(6, L"Jestem myśliwym. Poluję na zwierzynę.");
dial6->options.push_back(DialogueOption(L"Kim jesteś?", 6));
dial6->options.push_back(DialogueOption(L"Co tutaj robisz?", 7));
dial6->options.push_back(DialogueOption(L"Mam skórę wilczura, chcesz ją odkupić?", 8));
dial6->options.push_back(DialogueOption(L"Żegnaj", -1));
dialogues.push_back(dial6);

Dialogue* dial7 = new Dialogue(7, L"Obecnie odpoczywam, ale gdy tylko zbiorę siły, ruszę na polowanie.");
dial7->options.push_back(DialogueOption(L"Kim jesteś?", 6));
dial7->options.push_back(DialogueOption(L"Co tutaj robisz?", 7));
dial7->options.push_back(DialogueOption(L"Mam skórę wilczura, chcesz ją odkupić?", 8));
dial7->options.push_back(DialogueOption(L"Żegnaj", -1));
dialogues.push_back(dial7);

Dialogue* dial8 = new Dialogue(8, L"Bardzo chętnie, dam ci za nią miksturę leczniczą.");
dial8->options.push_back(DialogueOption(L"Proszę, oto skóra wilczura", 5));
dial8->options.push_back(DialogueOption(L"Może innym razem ... ", 5));
dialogues.push_back(dial8);

teraz ten dialog bym oskryptował np. tak
dial7->options.push_back(DialogueOption(L"<ifItem "wolf skin" 1>Mam skórę wilczura, chcesz ją odkupić?", 8));


wtedy by trzeba było za każdym razem gdy chcemy wyświetlić dialog sprawdzić czy spełnia on warunki.

W dobrą stronę idę tym tokiem rozumowania ?
P-181170
pekfos
» 2024-06-03 19:31:08
Jeżeli nie planujesz wczytywać tych dialogów z pliku, skryptowanie mija się z celem. Skoro wszystkie dialogi są wprost w kodzie, możesz warunki wyrazić w C++. Do DialogueOption możesz dodać pole std::function<bool()> z opcjonalnym predykatem mówiącym czy opcja dialogowa powinna być dołączona.
C/C++
dial7->options.push_back( DialogueOption( L"Mam skórę wilczura, chcesz ją odkupić?", 8,[ ] { return player->getNumberOfItems( "wolf skin" ) > 0; } ) );
i wchodząc z stan z opcjami do wyboru byś przygotowywał efektywne opcje na podstawie wyniku warunku
C/C++
for( auto & option: dial->options )
{
   
if( option.condition && !option.condition() )
       
 continue; // Warunek ustawiony i zwraca false = pomiń
   
   
effectiveOptions.push_back( option );
}
P-181171
tBane
Temat założony przez niniejszego użytkownika
» 2024-06-03 19:36:00
ok. Spróbuję tym sposobem. Co oznaczają te nawiasy kwadratowe ?

[ ] { return player->getNumberOfItems( "wolf skin" ) > 0; } ) );
P-181172
pekfos
» 2024-06-03 19:39:49
To jest składnia wyrażenia lambda. Można powiedzieć że to anonimowa funkcja definiowana w miejscu użycia (» Kurs C++» Poziom 5Wyrażenia lambda (C++11) lekcja).
P-181173
tBane
Temat założony przez niniejszego użytkownika
» 2024-06-03 20:28:23
jednak to Lambda się nie sprawdza za dużo kombinowania z dopisywaniem funkcji do każdej opcji dialogowej. Lepiej jak oskryptuję text po prostu.
P-181174
pekfos
» 2024-06-03 21:13:44
Ale jak do każdej? Nagle wszystkie opcje są warunkowe? Domyślnie byś miał brak warunku.
C/C++
DialogueOption( string text, int nextDialogueID, std::function < bool() > cond = { } )
{
   
//.....
}

dial7->options.push_back( DialogueOption( L"Mam skórę wilczura, chcesz ją odkupić?", 8,[ ] { return player->getNumberOfItems( "wolf skin" ) > 0; } ) );
dial7->options.push_back( DialogueOption( L"Żegnaj", - 1 ) );
P-181175
« 1 » 2 3 4
  Strona 1 z 4 Następna strona