dynamika i kolizja w grach 2D
Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Zarejestruj się!

dynamika i kolizja w grach 2D

AutorWiadomość
» 2018-02-08 23:49:18

if CzyKolizja(gracz.Obszar, bullet.Obszar)
{
   dystans = ObliczDystans(gracz.Obszar, bullet.Obszar)
   obrazenia = bullet.ObliczObrazenia(dystans)
   gracz.ZadajObrazenia(obrazenia)
}

albo


if CzyKolizja(gracz, bullet)
{
   obrazenia = 0;
   if bullet.ZadajeObszarowe()
   {
      dystans = ObliczDystans(gracz.Obszar, bullet.Obszar)
      obrazenia = bullet.ObliczObrazenia(dystans)
   }
   else
   {
      obrazenia = bullet.ObliczObrazenia()
   }

   gracz.ZadajObrazenia(obrazenia)
}

Jeżeli chodzi o
getDamage(const Time & deltaTime)
 to takie coś nie powinno mieć nawet miejsca ponieważ stan fizyki powinien się przesuwać o stały interwał czasowy. Pocisk, który działa określony czas po prostu nie znika po kolizji.

pocisk.zadajObrazenia( przeciwnik[ j ] );
, nie ma potrzeby aby pocisk znał definicję przeciwnika. Zobacz sobie na przykład wyżej.

Możesz też zrobić tak naprawdę wiele różnych list. Nikt nie mówi, że to musi być jedna lista


struct WorldState
{
   list<Drawable>;
   list<Bullets>;
   list<AreaBullets>;
   list<FastObjects>; //dla problemu tunelingu
   list<Backgrounds>;
   list<GuiObjects>;
}

Przy bardzo wielu obiektach i tak będziesz chciał sortować listę obiektów po typie aby współdziałać z cache procesora a nie robić mu na złość :)

AD PS:
Jeżeli punkt zawiera się w kwadracie ale jest blisko jego krawędzi zawsze możesz przypisać dany obiekt do dwóch kwadratów. Ewentualnie faktycznie pomyśleć o drzewie czwórkowym.
P-169338
Temat założony przez niniejszego użytkownika
» 2018-02-09 00:30:47
C/C++
void SimpleBullet::Init()
{
    CollisionObject.RegisterForCollision( this, & SimpleBullet::OnCollision );
}

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

Mam pytanie odnośnie tego kodu, mianowicie po co jest i co robi metoda SimpleBullet::Init? Po co rejestrować jakiś CollisionObject, zamiast sprawdzać kolizje pocisk - przeciwnik?

Jeżeli chodzi o getDamage(const Time & deltaTime)
 to takie coś nie powinno mieć nawet miejsca ponieważ stan fizyki powinien się przesuwać o stały interwał czasowy
W sumie racja, zapomniałem o pętli stałokrokowej.
P-169339
» 2018-02-09 10:23:10
co jest i co robi metoda SimpleBullet::Init

Init - skrót od initialize czyli inicjowanie składników klasy, równie dobrze może to być konstruktor.

Po co rejestrować jakiś CollisionObject, zamiast sprawdzać kolizje pocisk - przeciwnik?

Po to żeby rozdzielić system kolizji od gameplay, animacji, renderingu itd. Tak jak pisałem
proponuję żebyś zrobił cos bardziej systemowego a nie "skrojonego na miarę".
Jeżeli zrobisz po prostu kolizje pocisk-przeciwnik to dodanie nowego typu np. wybuchająca beczka, będzie oznaczało, że musisz zrobić kolizje pocisk-beczka i jeszcze obsłużyć kolizje gracz-beczka i przeciwnik-beczka żeby nie można było w taką beczkę wejść. Tworząc oddzielny obiekt kolizyjny moższe rozdzielić logikę gameplay'u i kolizji, wtedy dodanie beczki będzie wymagało jedynie dodanie do niej obiektu kolizji, odpowiednie ustawienie parametrów kolizji i obsługa kolizji w tej beczce a nie gdzieś indziej (np. niemożliwość przechodzenia przez beczkę obsłużona w graczu - to byłoby bez sensu).
P-169344
Temat założony przez niniejszego użytkownika
» 2018-02-10 20:31:15
Troche nie łapie tej koncepcji... Czy nie prościej zrobić funkcję
bool collision( const sf::Sprite & a, const sf::Sprite & b )
? Wtedy moglibyśmy łatwo sprawdzać kolizje dla czegokolwiek co go zawiera. Jeśli natomiast nie podoba Ci sie, że trzeba będzie w takim przypadku robić tak:
C/C++
collision( bullet, enemy );
collision( bullet, barrel );
collision( barrel, enemy );
zamiast
C/C++
collision( gameObject, gameObject2 );
To i tak nie mógłbym zastosować drugiego sposobu - nie wiadomo czym są gameObjecty, więc nie wiadomo czy koliduje beczka z pociskiem, czy przeciwnik z pociskiem, a to ma duże znaczenie, bo w pierwszym przypadku pocisk uderzy w beczke i zniknie a w drugim przeciwnik powinien otrzymać obrażenia.


Ewentualnie stworzyć sobie klase wirtualną Collisionable, która ma statyczną metodę (taka jak funkcja wyżej), a obiekty które mogą kolidować (np wieża nie może, bo po co) będą po niej dziedziczyły.  Wtedy mógłbym przechowywać takie obiekty w wektorze
std::vector < Collisionable *> objects;
ale - jak już pisałem - musze wiedzieć czym jest dany obiekt.
No chyba, że chodziło Ci o coś innego...
P-169365
» 2018-02-10 22:29:49
Robisz to trochę na siłę.

Zarówno beczka jak i gracz są obiektami fizycznymi i powinny móc otrzymywać obrażenia. To co potem z nimi zrobią to jest ich sprawa. Beczka może je zignorować.


Beczka::PrzyjmijObrazenia(Obrazenia obrazenia)
{
    // nie rob nic, w tym swiecie beczki sa niezniszczalne
}

Obiekty fizyczne powinny reagować na kolizję oraz wydarzenia w Twoim świecie, ale jeżeli to potrzebne mogą po prostu je ignorować.
P-169367
» 2018-02-10 22:39:18
Czy nie prościej zrobić funkcję
bool collision( const sf::Sprite & a, const sf::Sprite & b )
?
to byłby bardzo głupi pomysł, system kolizji powinien być oddzielony od renderingu, poza tym, co jeżeli będziesz chciał mieć obiekt złożony z 2 sprajtów?

game object to podstawowa klasa dla każdego obiektu w grze, tam powinieneś mieć podstawowe funkcje (np. tick) i informacje (np. dla uproszczenia pozycja w świecie) o takim obiekcie, ale do kolizji powinien być oddzielny collision object,  to on powinien się rejestrowac do systemu kolizji i mieć jakieś callbacki do obsługi w ownerze takiego obiektu.

Handlowanie kolizji powinno być właśnie robione w obiekcie którego to dotyczy a nie w samym systemie kolizji, tak aby to było elastyczne rozwiązanie.

"Rozpoznawanie" kolizji możesz zrobić na 2 sposoby, bardziej poprawnie byłoby dodać kanały kolizji, wtedy w collision object ustawiasz na jakie kanały jak ma reagować i dzięki temu nie będziesz dostawał wszystkich możliwych kolizji tylko wybrane (takie kanały to może być np. player, enemy, projectile, worldProp itp.). Jeżeli natomiast masz stosunkowo mały projekt (max 2-3 typy obiektów które mogą ze sobą kolidować) to ja bym się nie bawił w kanały kolizji i po prostu w takim obiekcie na callbacku sprawdzał z czym mam kolizję.

np wieża nie może, bo po co
wtedy nie dodajesz do niej collision objectu labo wyłączasz takiemu obiektowy kolizje jeżeli wieża moa go odziedziczonego.

nie wiadomo czy koliduje beczka z pociskiem, czy przeciwnik z pociskiem, a to ma duże znaczenie, bo w pierwszym przypadku pocisk uderzy w beczke i zniknie a w drugim przeciwnik powinien otrzymać obrażenia.
nie ma to w ogóle znaczenia, pocisk rejestruje się na kolizję, na callbacku jedynie zadaje damage obiektowi z którym koliduje i znika, tym samym rozwiązałeś obydwa case'y (beczka może przecież mieć swoje "życie").

Edit.

Takk jak ci wcześniej pisałem, proponuję ci zrobienie czegoś bardziej uniwersalnego jeżeli jest to prywatny projekt. Jeżeli zrobisz system kolizji to wtedy dodanie nowego typu obiektu nie będzie od ciebie wymagało modyfikowania w zasadzie niczego w kodzie kolizji. Będziesz chciał dodać ścianę którą możesz rozstrzelać, nic bardziej prostszego, tworzysz klasę, dodajesz do niej collision object, ustawiasz w nim odpowiednie dane i dodajesz funkcje na reagowanie na kolizje. Nie musisz dodawać kolejnego vectora ścian, kolejnej kombinacja sprawdzania kolizji (ściana - grasz, ściana - przeciwnik, ściana - pocisk itp.).

Zresztą możesz pomyśleć o moim pomyśle jak o problemie renderingu, tworząc nowy obiekt nie musisz modyfikować źródeł SFML'a, dodajesz do swojego obiektu Sprite i tyle, jedynie musisz się martwić o ty aby został on przekazany do funkcji print.
P-169368
Temat założony przez niniejszego użytkownika
» 2018-02-13 20:59:41
Wybacz, że tak długo nie odpowiadałem, ale ciężko jest sie zmotywować widząc ile jest jeszcze do nauki :d
Wybacz również za długość tego tekstu...

Zebrałem trochę pytań, szczególnie dotyczących koncepcji @michal11 i z góry prosiłbym o łopatologiczne tłumaczenie, bez skomplikowanego nazewnictwa.

1. callbacki - znalazłem taką definicje: (
A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.
)
Czy o to Ci chodziło? Domyślam się, że tak, gdyż przekazujesz tu adres metody
CollisionObject.RegisterForCollision( this, & SimpleBullet::OnCollision );

jeśli tak, to przejdźmy dalej...

2.1 Z tego co wydedukowałem, przy rejestrowaniu przesyłasz wskaźnik na aktualny obiekt (this) oraz adres metody callbackowej. Nie wiem (ale sie domyślam) jednak po co. Żeby powiązać obiekt kolizyjny z metodą, którą wywołuje w trakcie kolizji - callbackiem? Jak rozumiem robienie tego w registerForCollision zamiast w np. konstruktorze to tylko zabieg kosmetyczny?
2.2 Po co jest tu this? Czyżby po to, by przekazać go do callbacka obiektu, z którym kolidujemy:
C/C++
if( isCollision( collisionObject1, collisionObject2 ) )
{
    collisionObejct1.onCollision( collisionObject2.getPointedObject,...); //pobiera this z collisionObject2
    collisionObejct2.onCollision( collisionObject1.getPointedObject,...); // analogicznie
}

3. Założenie są takie: Dążymy do tego, by jak najbardziej uniezależnić od siebie rendering od kolizji jak i do tego, by typ obiektu nie musiał być znany (czyli żebyśmy wywoływali onCollision (GameObject * HitObject) a nie Tree * HitTree, Player * HitPlayer)?

4. Tu niestety nie mam pojęcia, co miałeś na myśli (szczególnie wyraz handlowanie. Szukałem wyjaśnienia, ale wikipedyjny uchwyt nic mi nie mówi)
Handlowanie kolizji powinno być właśnie robione w obiekcie którego to dotyczy a nie w samym systemie kolizji, tak aby to było elastyczne rozwiązanie.
 
5.
"Rozpoznawanie" kolizji możesz zrobić na 2 sposoby, bardziej poprawnie byłoby dodać kanały kolizji, wtedy w collision object ustawiasz na jakie kanały jak ma reagować i dzięki temu nie będziesz dostawał wszystkich możliwych kolizji tylko wybrane (takie kanały to może być np. player, enemy, projectile, worldProp itp.). Jeżeli natomiast masz stosunkowo mały projekt (max 2-3 typy obiektów które mogą ze sobą kolidować) to ja bym się nie bawił w kanały kolizji i po prostu w takim obiekcie na callbacku sprawdzał z czym mam kolizję.
I tu nie jestem pewien, czy dobrze Cię zrozumiałem. Chodzi Ci o sprawdzanie typów obiektów kolidujących ze sobą? Pewnie nie, bo raczej dążymy do tego, by nie trzeba było ich znać. A więc co miałeś na myśli? Byłbym również wdzięczny za wytłumaczenie enigmatycznego pojęcia "kanały kolizji", czym są i jak miałyby działać.

A na koniec - skąd Wy wiecie jak to sie robi? Macie te swoje sztuczki z callbackami, jakimiś uchwytami. Własne doświadczenie, wzorce, książki czy mieszanka tego wszystkiego. Są jakieś konkretne sposoby i triki, czy każdy wypracowuje swój styl pisania gier/programów sam (oczywiście na pewnym poziomie każdy będzie miał swój osobisty, ale czy są jakieś powszechnie przyjęte standardy).

Bardzo dziękuję wszystkim za pomoc, bez Was nadal pisałbym snake'a w CMD.
P-169393
» 2018-02-13 22:07:57
Handlowanie czyli obsługiwanie ;')

Kanały kolizji, czyli np takie coś jak jest w Warcrafcie III choćby. Ustawiasz dla obiektu z czym ma mieć kolizję, a z czym nie. Przykład: Wojtek ma mieć kolizję z a) budynki, b) pradawne, c) żyjące, d) obiekty zniszczalne, e) mechaniczne. Natomiast ma nie mieć kolizji z a) latające

Wojtek w tym wypadku jest żyjący. Jednak jednostka może posiadać kilka klasyfikacji. Np żyjąca pradawna jednostka latająca.
P-169396
1 « 2 » 3 4
Poprzednia stronaStrona 2 z 4Następna strona