tBane Temat założony przez niniejszego użytkownika |
» 2024-06-03 21:37:43 dobra spróbuję. nie wiem jak to dalej napisać... Konstruktor DialogueOption:DialogueOption( std::wstring text, int nextDialogueID, std::function < bool() > condition = { } ) { this->text = text; this->nextDialogueID = nextDialogueID; }
Dialogi: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"Nauczysz mnie czegoś o polowaniu?", 10 ) ); dial5->options.push_back( DialogueOption( L"Mam skórę wilczura, chcesz ją odkupić?", 8,[ ] { return player->bag->hasItemsInInventory( "wolf skin", 1 ); } ) ); 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"Nauczysz mnie czegoś o polowaniu?", 10 ) ); dial6->options.push_back( DialogueOption( L"Mam skórę wilczura, chcesz ją odkupić?", 8,[ ] { return player->bag->hasItemsInInventory( "wolf skin", 1 ); } ) ); 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"Nauczysz mnie czegoś o polowaniu?", 10 ) ); dial7->options.push_back( DialogueOption( L"Mam skórę wilczura, chcesz ją odkupić?", 8,[ ] { return player->bag->hasItemsInInventory( "wolf skin", 1 ); } ) ); 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", 9 ) ); dial8->options.push_back( DialogueOption( L"Może innym razem ... ", 5 ) ); dialogues.push_back( dial8 );
Dialogue * dial9 = new Dialogue( 9, L"A to Twoja mikstura." ); dial9->options.push_back( DialogueOption( L"Kim jesteś?", 6 ) ); dial9->options.push_back( DialogueOption( L"Co tutaj robisz?", 7 ) ); dial9->options.push_back( DialogueOption( L"Nauczysz mnie czegoś o polowaniu?", 10 ) ); dial9->options.push_back( DialogueOption( L"Mam skórę wilczura, chcesz ją odkupić?", 8,[ ] { return player->bag->hasItemsInInventory( "wolf skin", 1 ); } ) ); dial9->options.push_back( DialogueOption( L"Żegnaj", - 1 ) ); dialogues.push_back( dial9 );
Dialogue * dial10 = new Dialogue( 10, L"Niestety, nie jestem w stanie Cię niczego nauczyć." ); dial10->options.push_back( DialogueOption( L"Kim jesteś?", 6 ) ); dial10->options.push_back( DialogueOption( L"Co tutaj robisz?", 7 ) ); dial10->options.push_back( DialogueOption( L"Nauczysz mnie czegoś o polowaniu?", 10 ) ); dial10->options.push_back( DialogueOption( L"Mam skórę wilczura, chcesz ją odkupić?", 8,[ ] { return player->bag->hasItemsInInventory( "wolf skin", 1 ); } ) ); dial10->options.push_back( DialogueOption( L"Żegnaj", - 1 ) ); dialogues.push_back( dial10 );
|
|
pekfos |
» 2024-06-03 21:49:59 Nagłówek <functional>.
Taka myśl: Ja tylko zgaduję jaką grę chcesz zrobić, a wydajesz się skupiać na rozwiązywaniu przykładowych problemów które podaję. Co powiesz na to żeby jednak zrobić to jako jeden wielki switch-case który robi wszystko manualnie zamiast używać obiektowej reprezentacji drzewa dialogów? I tak nadajesz identyfikatory ręcznie, mając switch kompilator przynajmniej sprawdzi ich unikalność. To będzie spaghetti i będzie mało skalowalne, ale: możesz zrobić szybko cokolwiek, bez potykania się o ograniczenia własnego języka skryptów i obiektowej struktury. Zrób tak trochę reprezentatywnego contentu do gry, jaką chcesz zrobić. Wtedy odpowiedz sobie na pytanie "czy chcę to zrobić bardziej profesjonalnie?" i jeśli tak, "co musi potrafić mój system dialogów/zadań by przeportować istniejący content". Teraz lecisz z rozwiązaniem nie mając wymagań, co wróży refaktor. Robiąc content i (w miarę potrzeb) system równolegle, każda zmiana systemu będzie robiona z myślą "jak to zrobić najprościej" i "jak nie zepsuć wszystkiego innego", co zwykle oznacza hack i prowizorkę. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-06-03 21:55:42 Skrypty i tak będą, bo zamierzam trochę więcej opcji dodać, ale zaintrygowałeś mnie tą lambdą i jednak chcę się jej nauczyć.
Dodałem nagłówek <functional>. Jak teraz przetworzyć tę lambdę ? |
|
pekfos |
» 2024-06-03 22:12:09 Po pierwsze, jak menu ma być zduplikowane, to wcale nie znaczy że kod musi być zduplikowany. Łatwiej będzie to zmieniać (i mi na to patrzeć). std::vector < DialogueOption > menuHandlarza; menuHandlarza.emplace_back( L"Kim jesteś?", 6 ); menuHandlarza.emplace_back( L"Co tutaj robisz?", 7 ); menuHandlarza.emplace_back( L"Nauczysz mnie czegoś o polowaniu?", 10 ); menuHandlarza.emplace_back( L"Mam skórę wilczura, chcesz ją odkupić?", 8,[ ] { return player->bag->hasItemsInInventory( "wolf skin", 1 ); } ); menuHandlarza.emplace_back( L"Żegnaj", - 1 );
Dialogue * dial9 = new Dialogue( 9, L"A to Twoja mikstura." ); dial9->options = menuHandlarza; dialogues.push_back( dial9 );
Dialogue * dial10 = new Dialogue( 10, L"Niestety, nie jestem w stanie Cię niczego nauczyć." ); dial10->options = menuHandlarza; dialogues.push_back( dial10 ); Utwórz pole typu std::function<bool()> w DialogueOption i po prostu przypisz w konstruktorze. DialogueOption( std::wstring text, int nextDialogueID, std::function < bool() > condition = { } ) { this->text = text; this->nextDialogueID = nextDialogueID; this->condition = condition; } Kod na sprawdzenie warunku już podałem wcześniej: for( auto & option: dial->options ) { if( option.condition && !option.condition() ) continue; effectiveOptions.push_back( option ); } Sugeruję jednorazowo utworzyć kopię opcji które mają być wyświetlone, bo wtedy łatwo jest stwierdzić na przykład ile ich jest, bez konieczności sprawdzania warunków bez przerwy. Nie wiem jak wygląda kod obsługi tych dialogów, ale przefiltrowane effectiveOptions powinno dać się łatwo zintegrować. Jak teraz przetworzyć tę lambdę ? Nie musisz wiedzieć nic o niej. Wszystko to jest ukryte przez std::function<>. #include <iostream> #include <functional>
int four() { return 4; }
void test( std::function < int() > f = { } ) { if( f ) std::cout << "returned: " << f() << '\n'; else std::cout << "not set\n"; }
int main() { test( four ); test([ ] { return 123; } ); test(); } returned: 4 returned: 123 not set |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-06-03 22:23:49 Dobra. Działa. Funkcja renderująca chooseBox. void renderChooseBox( sf::RenderWindow * window ) { sf::Texture dialogBoxTexture; if( !dialogBoxTexture.loadFromFile( "assets/GUI/DialogBoxTexture.png" ) ) { return; } sf::Sprite background; background.setTexture( dialogBoxTexture ); background.setOrigin( dialogSize.x / 2.0f, dialogSize.y / 2.0f ); background.setPosition( view.getCenter().x, view.getCenter().y + screenHeight / 2.0f - dialogSize.y / 2.0f ); window->draw( background ); availableOptions.clear(); for( auto & o: currentDialogue->options ) { if( o.condition && !o.condition() ) continue; availableOptions.push_back( o ); } for( int i = 0; i < availableOptions.size(); i++ ) { sf::Text text = sf::Text( availableOptions[ i ].text, dialogBoxFont, characterSize ); if( i == chooseOption ) text.setFillColor( sf::Color( 255, 201, 14 ) ); else text.setFillColor( textColor ); textPosition.x = background.getPosition().x - dialogSize.x / 2.f + padding; textPosition.y = background.getPosition().y - dialogSize.y / 2.f + float( i ) * lineHeight + padding; text.setPosition( textPosition ); window->draw( text ); } }
|
|
pekfos |
» 2024-06-03 22:49:55 Po tym jako konstruujesz dialogi w kodzie spodziewałem się że to co mówi NPC będzie widoczne razem z opcjami do wyboru. Miałoby sens dla kontekstu, a nie że gracz niecierpliwie pomija dialogi i nagle ma wybór "TAK/NIE" i wtedy uuhh... ;) Ale skoro wyświetlasz albo jedno, albo drugie, tym bardziej bym rozdzielił mowę NPC od wyborów gracza by nie duplikować rzeczy. Przykładowo konkretny numer "dialogu" mógłby się odnosić albo do
To ubrać w hierarchię klas by można było wszystko wrzucić do jednego kontenera. No ale wychodzę tu trochę w system zadań, bo uważam że to ściśle powiązany temat. No chyba że dialogi to dwóch aktorów stojących na baczność i wymieniających zdania, a cokolwiek ciekawszego będzie musiało zaczekać na koniec rozmowy i być zaimplementowane zupełnie niezależnym mechanizmem? |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-06-03 23:11:58 Mogę wyświetlać ostatni fragment wypowiedzi boota, z tym nie będzie problemu. Ale uważam, że obecna opcja jest wystarczająca :-) |
|
pekfos |
» 2024-06-03 23:13:42 To ty masz wizję na tą grę, ja tylko zgaduję :) |
|
1 « 2 » 3 4 |