latajacaryba Temat założony przez niniejszego użytkownika |
dynamika i kolizja w grach 2D » 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. |
|
Saran |
» 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. |
|
jankowalski25 |
» 2018-02-08 18:48:43 Niech każdy pocisk sam oblicza zadane obrażenia. 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. |
|
michal11 |
» 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ść. |
|
latajacaryba Temat założony przez niniejszego użytkownika |
» 2018-02-08 22:24:00 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: for( auto & i: wektorPrzeciwnikow ) { if( koliduje( pocisk, i ) ) i.zadajObrazenia( pocisk.obrazenia() ); }
@michal11 Czyli coś w ten deseń: 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. |
|
Saran |
» 2018-02-08 23:00:20 Może quadtree |
|
latajacaryba 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ę? |
|
michal11 |
» 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 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, |
|
« 1 » 2 3 4 |