Klasy pochodne wymagające różnych argumentów dla tej samej dziedziczonej metody.
Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Zarejestruj się!

Klasy pochodne wymagające różnych argumentów dla tej samej dziedziczonej metody.

AutorWiadomość
Temat założony przez niniejszego użytkownika
Klasy pochodne wymagające różnych argumentów dla tej samej dziedziczonej metody.
» 2018-02-08 17:33:27
Witam. Mam klasę bullet, po której dziedziczą Rocket, StandardBullet oraz Laser. Są to - jak nazwa wskazuje - różne typy pocisków. Mają swoje obrażenie, teksture lotu oraz prędkość. Mam jednak problem:

Potrzebna mi możliwość pobierania obrażeń i tu zaczynają się schody. Standard bullet zwraca po prostu obrażenie, bo to pocisk jak każdy, uderzy to uderzy, więc getDamage() jest bez argumentów.
Ale:
Rocket wybucha i obrażenie zależą od pozycji przeciwnika - im bliżej wybuchu tym mocniejsze, więc to powinno być getDamage(const vector & Position)
Ale to jeszcze nie wszystko :D

Laser, jak to laser, bije cały czas, a jego obrażenie to damage per second, więc: getDamage(const Time & deltaTime)

No i klops. Bo jeśli chce wszystkie te pociski przechowywać w wektorze: std::vector<Bullet*> Bullets to niestety, nie mam jak wywoływać metody getDamage.

Ktoś mógłby powiedzieć
To niech każdy pocisk, niezależnie od rodzaju zwraca damage, a klasa np. Engine czy Game sobie ogarnie już zarządzanie (pomnoży przez deltaTime itd.)
No nie, bo przecież klasa nie wie, co kryje się pod Bullet*. To może być laser ale i rocket.

To zwracaj strukturę, która zawiera zmienną damage oraz enuma, np. eLaserDamage, eRocketDamage i w zależności od tego niech klasa Engine sie z tym bawi

No nie po raz drugi. To pogwałcenie zasady(nie pamiętam jak sie nazywała) która mówi, że nie powinna być wymagana znajomość typu obiektu klasy dziedziczącej (na tym polega w końcu dziedziczenie, żeby wywoływać tą samą metodę dla różnych obiektów klasy podstawowej). Jeśli dodam kiedyś klasę dziedziczącą po pocisk będę musiał tworzyć kolejnego enuma i jego obsługę.

Także proszę o jakiś pomysł.

edit:
@Saran (na dole :D)
Zapomniałem, że taki dział w ogóle istnieje.
P-169317
» 2018-02-08 18:07:47
O właśnie takie tematy jak te. One powinny być w dziale Tworzenia Gier, a nie jakieś pytania dot. instalacji bibliotek jakie tam są teraz. Według mnie przynajmniej.
P-169318
» 2018-02-08 18:48:43
Niech każdy pocisk sam oblicza zadane obrażenia.
  • StandardBullet po prostu zwróci obrażenia.
  • Rocket niech w momencie wybuchu pobiera pozycję przeciwnika i oblicza wynik.
  • Laser niech podczas rażenia zapamiętuje, ile czasu to trwa i oblicza wynik.

Dopisano:
Potrzebna mi możliwość pobierania obrażeń
Jak to obsługujesz? Co klatkę pytasz każdy pocisk, czy i jakie zadał obrażenia? Skrajny przypadek: jeśli 1000 pocisków samonaprowadzających będzie sobie fruwało przez minutę za jakimś wrogiem, to w każdej klatce będziesz pytał każdy z nich o zadane obrażenia? Może lepiej niech pocisk sam o tym powiadamia. Wtedy masz kontener z "ciekawymi" zdarzeniami, które po kolei obsługujesz.
P-169319
» 2018-02-08 21:15:09
Odwróć logikę, niech to każdy "Bullet" odpowiednio implementuje zadawanie obrażeń a nie cel sobie pobiera damage z tego co go trafiło.

StandardBullet niech na zwykłym callbacku kolizyjnym zadaje te swoje obrażenia.
Laser niech robi to na swoim ticku (czy tam funkcji update), po trafieniu.
Rocket - tu masz dwa podejścia, albo bardziej rzeczywiste czyli rozszerzanie się wybuchu w czasie albo w jednej klatce zbierasz okolicznych przeciwników i zadajesz im damage.
W pierwszym przypadku robisz to na ticku rocketa (ew. na callbacku kolizji) i po prostu sprawdzasz odległość od centrum trafienia.
W drugim przypadku po prostu na trafieniu zbierasz okolicznych aktorów z systemu kolizji i wyliczasz odległość.
P-169329
Temat założony przez niniejszego użytkownika
» 2018-02-08 22:24:00
Jak to obsługujesz?
Tu właśnie jeszcze nie mam pomysłu, jak sam zauważyłeś, niezbyt wydajnie jest sprawdzać każdy pocisk, czy koliduje z każdym przeciwnikiem. Miałem pomysł na coś w tym stylu:

C/C++
for( auto & i: wektorPrzeciwnikow )
{
    if( koliduje( pocisk, i ) )
         i.zadajObrazenia( pocisk.obrazenia() );
   
}

@michal11

Czyli coś w ten deseń:

C/C++
if( kolizja( pocisk, przeciwnik[ j ] ) )
{
    pocisk.zadajObrazenia( przeciwnik[ j ] );
}

?
Wydaje mi sie, że dobrym rozwiązaniem będzie połączenie Waszych metod - przy Update laser zapamiętuje deltaTime i wykorzystuje go przy ewentualnym zadawaniu obrażeń :))

PS. jankowalski myślałem, o podziale ekranu na części, np 20 i co update ruchu każdej postaci sprawdzałbym, w którym polu sie znajduje, tylko jest jeden problem: Dajmy na to pocisk znajduje sie
w polu o numerze 1 (rysunek poglądowy proszę!), więc sprawdza kolizje tylko dla postaci znajdujących się w polu 1, natomiast - jak wynika z załączonego obrazka - formalnie postać (jej środek) znajduje sie na polu nr. 2. Nie wiem, czy będzie to miało ogromny wpływ, ale proszę spojrzeć, jeszcze gorzej! Drugi przeciwnik jest na krzyżowaniu 4 pól, choć formalnie jego miejsce to pole 14. To oznacza, że jego obszar kolizji zmniejsza sie do zamalowanego na zielono fragmentu.
P-169332
» 2018-02-08 23:00:20
Może quadtree
P-169334
Temat założony przez niniejszego użytkownika
» 2018-02-08 23:32:47
Zerknąłem na quadtree (ten film), tylko nie bardzo wiem, jak to ma wydajnie działać. W końcu jeśli podzielimy sobie okno na 4 części, to nadal musimy wiedzieć, ile obiektów znajduje sie w poszczególnych częściach (gałęziach) okna, po to by wiedzieć czy nadal mamy je dzielić, czy sprawdzać kolizje. A nie da sie tego policzyć inaczej, niż sprawdzić, czy obiekty kolidują z wydzielonym obszarem. Czy może gdzieś się mylę?
P-169336
» 2018-02-08 23:46:34
Jeżeli to jest projekt prywatny w którym chcesz się jak najwięcej nauczyć to proponuję żebyś zrobił cos bardziej systemowego a nie "skrojonego na miarę". Jeżeli ja bym pisał taki system pocisków to chciałbym móc zrobić tak
C/C++
void SimpleBullet::Init()
{
    CollisionObject.RegisterForCollision( this, & SimpleBullet::OnCollision );
}

void SimpleBullet::OnCollision( GameObject * HitObject, const Vector & HitLocation )
{
    if( HitObject )
    {
        HitObject->ApplyDamage( getBulletDamage(), GetBulletDamageType() );
    }
}

//....

void Laser::Tick( float DeltaTime )
{
    if( LastHitObjectIsValid() )
    {
        LastHitObject->ApplyDamage( getBulletDamage() * DeltaTime, GetBulletDamageType() );
    }
}

void Laser::OnCollision( GameObject * HitObject, const Vector & HitLocation )
{
    if( HitObject )
    {
        LastHitObject = HitObject;
    }
}

i wtedy musisz oczywiście odpowiednio zadbać o to aby CollisionObject rejestrował się do systemu kolizji, dla uproszczenia możesz założyć tylko kolizje BoxToBox. No i najlepiej zrobić też coś na zasadzie CollisionStart i CollisionEnd ale to już powinno być stosunkowo łatwe.

To o czym piszesz w PS nazywa się quadtree, możesz poczytać o tym, powinno pomóc w optymalizacji, aczkolwiek nawet jeżeli będziesz miała setki obiektów które mogą ze sobą kolidować i w każdym ticku będziesz sprawdzał kolizję każdy z każdym to nie powinien to być problem, pewnie nawet tysiące obiektów na raz nie będą dużym problemem,
P-169337
« 1 » 2 3
 Strona 1 z 3Następna strona