R0ut4 Temat założony przez niniejszego użytkownika |
[sfml] [game 2d] itemy, eq » 2020-03-27 13:27:55 Witam wszystkich (Pekfos Ciebie szczególnie :)) Piszę tym razem o radę. Mianowicie w jaki sposób mógłbym zrobić itemy i ekwipunek bohatera. (Można patrzeć na styl jaki istnieje np a Minecraft, lub Albion) Tzn. Żeby surowce można było wydobywać, stawiać itp. (kwestia wydobywania to już mam mniej więcej pomysł na to)
Z góry dziękuję |
|
RazzorFlame |
» 2020-03-27 14:03:35 Pytanie bardzo ogólne. Zwykle robi się hierarchię klas, w której najbardziej ogólną jest klasa Item, następnie z niej dziedziczą takie klasy jak Weapon, Armor, Food itd. Musisz przemyśleć to co będziesz mógł robić z tymi itemami. Prawdopodobnie będziesz chciał, żeby każdy item posiadał informacje o: - jego nazwie (name) - jego ilości (amount) - w którym slocie w ekwipunku się znajduje lub czy istnieje poza ekwipunkiem jako przedmiot, który można podnieść (Pickup) W Minecrafcie i wielu innych grach ekwipunek i kontenery/pojemniki posiadają sloty, czyli miejsca, w których można umieścić przedmioty. Kontener jest zbudowany zwykle z N slotów i każdy slot może posiadać przedmiot lub być pusty. Do tego idealnie nada się wskaźnik na przechowywany przedmiot. class Item { public: sf::Sprite sprite; };
class Slot { public: class Container & owner; Item * item = nullptr; sf::Sprite sprite; };
class Container { public: std::array < Slot, N > slots; };
No i do tego, gdy chcesz zrobić wyświetlanie ekwipunku, to po prostu robisz coś takiego: void drawSlot( sf::RenderWindow & window, Slot const & s ) { window.draw( s.sprite ); if( s.item ) { window.draw( s.item->sprite ); } }
void drawContainer( sf::RenderWindow & window, Container const & cnt ) { for( Slot const & s: cnt.slots ) { drawSlot( window, s ); } }
Jak sobie to tak zrobisz, to potem łatwo będziesz mógł przenosić itemy między slotami i w ogóle robić co tylko chcesz. |
|
R0ut4 Temat założony przez niniejszego użytkownika |
» 2020-03-27 15:45:42 Jakbyś mógł jeszcze wyjaśnić, o co chodzi z tym fragmente: class Container & owner;
Item * item = nullptr;
I jeszcze ten drugi kod gdzie jest funkcja drawSlot, to byłbym bardzo wdzięczny. Jeśli chodzi o przykładowy jeden item np. butelka to tworzę sobie obiekt klasy Bottle o danych parametrach typu nazwa, ilość, zawartość, id to po podniesieniu wystarczy jeśli podniosę ilość o daną liczbę, a kiedy zużyje wszystkie to użyć destruktora i wtedy "usunąć" item? Kolejne pytanie czy na każdy rysunek danego itemu muszę tworzyć obiekt? Np gdyby była to gra rpg to musiałbym tworzyć 100 obiektów klasy skrzynia, aby umieścić je na świecie? |
|
RazzorFlame |
» 2020-03-27 17:14:46 Warto, żeby slot wiedział w jakim jest kontenerze, dlatego tworzę referencję na ten kontener. Użyłem słowa class bo definicja klasy Container znajduje się dopiero niżej w kodzie, więc trzeba zrobić forward declaration. Można to zrobić też tak: class Container;
class Slot { public: Container & owner; };
... i teraz już nie trzeba dawać class w tej linii. Tak jak mówiłem, wewnątrz Slotu możesz umieścić jakiś item, więc dajesz do niego wskaźnik. Możesz użyć smart pointera tutaj. Jeśli nie znasz smart pointerów to koniecznie powinieneś o nich dużo przeczytać, wtedy zrozumiesz o czym mówię. W skrócie chodziło o to, że możesz sprawić, że czas istnienia danego itemu będzie mógł zależeć od czasu istnienia slotu. Wtedy np. gdy wyrzucisz/zniszczysz jakiś plecak, który ma itemy w środku, to sloty zostaną zniszczone i wraz z nimi te itemy. drawSlot po prostu rysuje slot (jego sprite tła) oraz item, który się znajduje na slocie, przedtem jeszcze sprawdzając czy slot nie jest pusty. tworzę sobie obiekt klasy Bottle (...) to po podniesieniu wystarczy jeśli podniosę ilość o daną liczbę |
To już zależy od itemu. Zwykle jest tak, że część rzeczy się stackuje (grupuje) a część nie. Na początek możesz zrobić, że nic się nie stackuje, wtedy każdy item będzie dodawany na następny slot. Będzie to łatwiejsze do zaimplementowania. Jak już to zrobisz, to możesz pomyśleć o tym co napisałeś - jeśli posiadasz już identyczny item to możesz zwiększyć jego ilość, a zebrany item usunąć. czy na każdy rysunek danego itemu muszę tworzyć obiekt |
SFML tak to zaprojektował, że jego sf::Sprite jest bardzo lekkim obiektem, możesz śmiało tworzyć je w dużych ilościach. One nie zawierają bezpośrednio w środku tekstury, tylko wskaźnik na nią. Nawet jeśli utworzysz 10000 takich sprite-ów o tej samej teksturze, to do tego wystarczy tylko jedna tekstura. Np gdyby była to gra rpg to musiałbym tworzyć 100 obiektów klasy skrzynia, aby umieścić je na świecie? |
Powinieneś rozróżnić itemy od obiektów na mapie, bo do mapy podchodzi się inaczej. W grach, jeśli masz np. 1000 takich samych drzew do narysowania, które różnią się tylko np. pozycją, stosuje się tzw. instancing. Dzięki temu można zyskać bardzo dużo na wydajności, jednak o ile się orientuje nie da się tego zrobić w SFML bez modyfikacji kodu źródłowego samej biblioteki. Nie powinieneś się tym przejmowac na tym etapie. Najpierw zrób tak, żeby działało a potem optymalizuj. |
|
R0ut4 Temat założony przez niniejszego użytkownika |
» 2020-03-27 17:38:58 Przeczytałem co napisałeś i przeczytam jeszcze parę razy, razem z wyjaśnieniem "każdego" słowa którego użyłeś w kodzie.
Kiedyś już zadawałem to pytanie, ale czy mógłbyś mi jeszcze polecić jakiś sposób na kolizje gracza z np. ogrodzenie?
Nie raz widziałem o kolizjach per-pixel, ale nie bardzo to rozumiem |
|
pekfos |
» 2020-03-27 18:04:06 Kolizje to zupełnie inny temat-rzeka, lepiej zadaj pytanie w osobnym temacie. SFML tak to zaprojektował, że jego sf::Sprite jest bardzo lekkim obiektem, możesz śmiało tworzyć je w dużych ilościach. One nie zawierają bezpośrednio w środku tekstury, tylko wskaźnik na nią. Nawet jeśli utworzysz 10000 takich sprite-ów o tej samej teksturze, to do tego wystarczy tylko jedna tekstura. |
Bez przesady z tym 10k. To już zadanie dla sf::Vertex, nie sf::Sprite. void drawSlot( sf::RenderWindow & window, Slot const & s )
|
Masz nietrywialną klasę Slot, więc może warto zrobić to tak: void Slot::draw( sf::RenderWindow & window ) const
Raczej jest jeden słuszny sposób rysowania slotów, więc zrobienie z tego metody pozwala skrócić kod. Nie trzeba też wystawiać wszystkiego jako publiczne. |
|
R0ut4 Temat założony przez niniejszego użytkownika |
» 2020-03-27 18:25:28 Czyli tworzeniespritu i ustawienie na nim textury w klasie i stworzenie obiektu tej klasy działa tak samo jak bym miał podstawić zamiast Sprite - sf::Vertex/vertexarray? |
|
pekfos |
» 2020-03-27 18:29:50 sf::Sprite używa wewnętrznie sf::Vertex. Do rysowania wielu elementów z jednej tekstury, np map kafelkowych, czy systemów cząsteczkowych, znacznie lepiej jest użyć od razu sf::Vertex. Wydajność rysowania dużego zbioru wierzchołków jednym wywołaniem jest bez porównania lepsza od N wywołań po 4 wierzchołki, jakie będziesz mieć z sf::Sprite. |
|
« 1 » |