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

[sfml] [game 2d] itemy, eq

Ostatnio zmodyfikowano 2020-03-27 18:29
Autor Wiadomość
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ę
P-176534
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.

C/C++
class Item
{
public:
    sf::Sprite sprite; // obrazek itemu
    // ... reszta rzeczy
};

class Slot
{
public:
    class Container & owner;
   
    Item * item = nullptr; // mozesz uzyc smart pointera
   
    sf::Sprite sprite; // tlo
};

class Container
{
public:
    std::array < Slot, N > slots;
};

No i do tego, gdy chcesz zrobić wyświetlanie ekwipunku, to po prostu robisz coś takiego:
C/C++
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.
P-176535
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:
C/C++
class Container & owner;

Item * item = nullptr; // mozesz uzyc smart pointera
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?
P-176536
RazzorFlame
» 2020-03-27 17:14:46
C/C++
class Container & owner;
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:
C/C++
class Container; // forward declaration

class Slot
{
public:
    Container & owner;
};
... i teraz już nie trzeba dawać class w tej linii.

C/C++
Item * item = nullptr;
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.
P-176537
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
P-176538
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.

C/C++
void drawSlot( sf::RenderWindow & window, Slot const & s )
Masz nietrywialną klasę Slot, więc może warto zrobić to tak:
C/C++
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.
P-176540
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?
P-176541
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.
P-176542
« 1 »
  Strona 1 z 1