Jak działają pociski w grach wideo?

64

Natknąłem się na to pytanie, projektując grę wideo w języku C #.

Jeśli weźmiemy pod uwagę gry takie jak Battlefield lub Call of Duty , setki, a nawet tysiące pocisków lecą w tym samym czasie. Zdarzenia są uruchamiane w sposób ciągły, a z tego, co wiem, pochłania to dużą moc obliczeniową… czy to prawda? Chcę wiedzieć, jak różni twórcy gier zarządzają pociskami (2D i 3D) i jaka jest najbardziej wydajna metoda dla każdego z nich.

Czytam pytanie W jaki sposób pociski są symulowane w grach wideo? ale nie wpływa to na działanie pocisków z perspektywy projektowania programu.

Miałem kilka pomysłów, ale każdy ma swoje wady:


Najbardziej wydajna metoda, o której mogłem pomyśleć (w przypadku gier 2D):

Powiedzmy, że miałem stworzyć klasę o nazwie Bullet, i jak długo użytkownik przytrzymuje przycisk, co 0,01 sekundy powstaje obiekt Bullet. Ten punkt ma:

  • 1 prędkość

  • 2 Pozycja początkowa miejsca, z którego jest strzelany

  • 3 Struktura duszka

  • 4 Efekt przy trafieniu

Ponieważ kula byłaby własną klasą, mogłaby sama zarządzać słuchaczami rysowania, poruszania się i akcji.

Czy procesorowi nie byłoby trudno przetworzyć tysiące takich obiektów, które są tworzone, a następnie niszczone (gdy wyzwalany jest efekt przy trafieniu)? Miejsce w pamięci RAM?


Wydajna metoda gier 3D - Inną myślą, którą miałem, było:

Powiedzmy, że tworzę klasę broni. Ta broń ma różne funkcje, z których niektóre:

  • 1 Wykryj, dokąd celuje broń, i sprawdź, czy patrzy na cel

  • 2 Uruchom animację strzelania z pistoletu

  • 3 Ma metodę doDamage (), która wskazuje coś do odjęcia zdrowia od tego, na co celowana jest broń

  • 4 Powiadamia klasę animacji pocisku po naciśnięciu przycisku

Mógłbym wtedy stworzyć klasę statyczną, powiedzmy BulletAnimation, która mogłaby otrzymać powiadomienie z miejsca, w którym uruchomiła się broń, gdzie jest ona skierowana (do celu pocisku) oraz informacje na temat odpowiedniego duszka i prędkości do użycia dla pocisku . Ta klasa następnie rysuje duszki (może na nowym wątku, idk) na podstawie obu pozycji i pożądanego duszka, aby zasymulować wystrzelenie pocisku z pistoletu.


Ta ostatnia wydaje się o wiele trudniejsza do kodowania i czy nie wymagałoby to dużej mocy obliczeniowej, aby stale wywoływać statyczne, aby zrobić to dla tysięcy pocisków jednocześnie? Trudno byłoby również uzyskać ciągłe aktualizacje pozycji początkowej i końcowej.

Moje pytanie brzmi: jaki jest najbardziej efektywny sposób, w jaki robią to twórcy gier? Czy ta metoda zmienia się z gier 2D na 3D?

Eric
źródło
16
Pamiętaj, że nawet dziś większość gier nie symuluje lotu pocisków. W przypadku wszystkiego, co uważa się za „wystarczająco szybkie”, zamiast tego wykonuje się prosty hitcan - w zasadzie zakłada się, że uderzenie występuje w tym samym czasie, co naciśnięcie spustu. W każdym razie „setki lub tysiące pocisków” nie są tak naprawdę dużą kwotą - to coś, co gry miały od bardzo wczesnych konsol (różne gry typu bullet-hell), tysiące razy mniej wydajne niż dzisiejsze maszyny. Musisz tylko wykonać tak mało pracy na pocisk, jak to możliwe :)
Luaan
42
Pociski zwykle działają za pośrednictwem pew-pew-pewtechnologii :)
MonkeyZeus
5
Nigdy nie ma setek ani tysięcy pocisków latających w tym samym czasie. Nie ma pistoletu, który strzela tak szybko. Nawet potężna Falanga osiąga 75 kul na sekundę. W oparciu o „Efektywny zasięg ognia” wymieniony na Wikipedii, pociski latają najwyżej przez około 3 sekundy, więc Falanga może wystrzelić 225 pocisków w powietrze jednocześnie. M16 osiąga szczyt z prędkością około 12 nabojów na sekundę i nie może utrzymać tej prędkości (maks. Dla podtrzymywanego ognia wynosi 0,25 metra na sekundę). Po prostu nie ma zbyt wielu wystrzałów jednocześnie!
Cort Ammon
3
Aby to podkreślić, nigdy nie jest dobrze, aby obiekty były pojedynczymi klasami, gdy są tak proste. O wiele lepiej jest mieć jedną instancję bulletField dla każdego rodzaju pocisku. Niewielki narzut w długości kodu i co tam zaoszczędzi ci dodatkowe 4 bajty słowa na punktor (jeśli typ jest liczbą całkowitą). Ponadto jeden obiekt może z łatwością zeskanować listę.
The Great Duck
4
@Cort - to prawda, zakładając, że w obszarze gry jest tylko jedna broń palna. OP wspomniało o grach takich jak Battlefield i CoD, w których dziesiątki graczy mogli jednocześnie strzelać z automatycznych pistoletów. Nie jest nierozsądne, aby istniała absurdalna liczba, jeśli każdą rundę rzeczywiście rozliczono fizycznie w przestrzeni kosmicznej.
Jesse Williams

Odpowiedzi:

78

Z pewnością rozumiem, dlaczego uważasz, że tak trudno byłoby je zasymulować, ale pociski (wszystkie pociski, naprawdę) są wystarczająco ograniczone, aby je ułatwić.

  1. Na ogół są one symulowane jako pojedynczy punkt, a nie jako coś o objętości. Dzięki temu wykrywanie kolizji jest znacznie łatwiejsze, ponieważ teraz muszę tylko wykonywać kolizje z bardzo prostymi powierzchniami, takimi jak linia z okręgiem.

  2. Wiemy, jak się przeprowadzą, więc nie ma zbyt wielu informacji, które musimy przechowywać lub obliczać. Twoja lista była dość dokładna, na ogół będziemy mieć z nią jeszcze kilka rzeczy, na przykład, kto strzelił kulą i jaki jest jej typ.

  3. Ponieważ wszystkie pociski będą bardzo podobne, możemy je wstępnie przydzielić, aby uniknąć całego narzutu związanego z ich tworzeniem. Mogę przydzielić tablicę 1000 pocisków, a teraz można uzyskać do nich dostęp tylko za pomocą indeksu, a wszystkie są sekwencyjne w pamięci, więc ich przetwarzanie będzie szybkie.

  4. Mają stały czas życia / zasięg, dzięki czemu mogę szybko wygasać stare pociski i bardzo szybko przetwarzać pamięć na nowe.

  5. Gdy coś trafią, mogę je również wygasnąć, aby miały skończone życie.

  6. Ponieważ wiemy, kiedy zostały utworzone, jeśli potrzebujemy nowych i nie mamy wolnych na naszej wstępnie przydzielonej liście, mogę po prostu złapać najstarsze i poddać je recyklingowi, a ludzie nie zauważą, że kule wygasną nieco wcześniej .

  7. Są one renderowane jako modele (zwykle) lub jako modele o niskiej rozdzielczości i zajmują bardzo mało miejsca na ekranie, więc można je szybko renderować.

Biorąc to wszystko pod uwagę, pociski wydają się być stosunkowo tanie. Jeśli nasz budżet zostanie kiedykolwiek pochłonięty przez pociski i ich renderowanie, zwykle po prostu przeprojektujemy go, aby ograniczyć liczbę strzałów, które można oddać na raz (zobaczysz to w wielu starych grach zręcznościowych), używaj broni z wiązkami, które poruszają się natychmiast lub spowolnij szybkostrzelność, aby upewnić się, że nie przekraczamy budżetu.

Tom K.
źródło
12
Muszę się nie zgodzić z 5), co tak naprawdę komplikuje wszystko we współczesnych grach. We wcześniejszych strzelankach było to do przyjęcia, obecnie nawet ChZT pozwala graczom strzelać przez drewniane ściany. 6) byłoby nie do przyjęcia dla jakiegokolwiek systemu konkurencyjnego, chociaż byłby to rzadki problem.
SBoss,
17
@SBoss następnie przeformułowuje: „Gdy trafią w coś, czego nie mogą przeniknąć, ja też mogę wygasnąć, aby mieli skończone życie”. A dla 6 możesz uzyskać najgorszy przypadek, ograniczając maksymalną szybkostrzelność na postać, a następnie utrzymując tablicę długościnum_characters * max_bullets_per_character
maniak zapadkowy
14
@SBoss Myślę, że # 6 to coś więcej np. kosmiczne gry z góry na dół, w których wolno poruszająca się kula może przebyć dużą odległość poza ekranem przed uderzeniem w coś / zniknięciem. Oczywiście nie stanowi to problemu w grach typu CoD, w których pociski poruszają się szybko i szybko docierają do granic świata.
BlueRaja - Danny Pflughoeft
1
Zdecydowana większość gier wcale NIE modeluje pocisków (balistyki zewnętrzne). Większość gier wykorzystuje technikę zwaną „skanowaniem trafień”.
Aron
45

Prawdopodobnie jednym z najbardziej wydajnych sposobów wdrażania pocisków jest użycie tak zwanego hitcan . Jego implementacja jest raczej prosta - kiedy strzelasz, sprawdzasz, do czego celuje broń (być może używasz promienia, aby znaleźć najbliższy byt / obiekt / siatkę), a następnie „uderzasz” go, zadając obrażenia. Jeśli chcesz sprawić, by wyglądało to bardziej jak faktyczna, szybko poruszająca się niewidzialna kula została wystrzelona, ​​możesz ją sfałszować, dodając niewielkie opóźnienie zależne od odległości przed spowodowaniem obrażeń.

Podejście to zasadniczo zakłada, że ​​wystrzelony pocisk ma nieskończoną prędkość i jest zwykle stosowany do rodzajów broni, takich jak lasery i wiązki cząstek / armaty i może niektóre formy karabinów snajperskich .

Kolejnym podejściem byłoby modelowanie wystrzelonej kuli jako pocisku, który jest modelowany jako jego własny byt / obiekt, który podlega zderzeniu, i ewentualnie grawitacja i / lub opór powietrza, który zmienia jego kierunek i prędkość. Jest to bardziej złożone niż podejście hitcan ze względu na dodatkowe równania fizyki i bardziej wymagające zasobów, ponieważ istnieje rzeczywisty obiekt pocisku, ale może zapewnić bardziej realistyczne pociski.

Jeśli chodzi o zarządzanie kolizjami między pociskami opartymi na pociskach a innymi obiektami w grze, wykrywanie kolizji można znacznie uprościć, sortując obiekty na poczwórne lub oktaty . Oktawy są używane głównie w grach 3d, a czwórki mogą być używane w grach 2d lub 3d. Zaletą korzystania z jednego z tych drzew jest to, że można znacznie zmniejszyć liczbę możliwych kontroli kolizji. Na przykład, jeśli masz 20 obiektów aktywnych na poziomie, bez użycia jednego z tych drzew, będziesz musiał sprawdzić wszystkie 20 pod kątem kolizji z kulą. Dzieląc 20 obiektów między liście (końcowe węzły) drzewa, można zmniejszyć liczbę kontroli do liczby obiektów znajdujących się w tym samym liściu co kula.

Jeśli chodzi o te podejścia - hitcan i pocisk, oba mogą być swobodnie używane w grach 2d lub 3d. Zależy to bardziej od tego, czym jest broń i od tego, jak twórca zdecydował, że broń będzie działać.

Szczecina
źródło
Informacje o wzorze projektowym, Hitscan i quad / octrees są naprawdę pomocne. Dziękujemy również za informację!
Eric
8
Jeśli nie wytoczysz procesu trafienia, ale symulujesz pociski, mogą one wypaczać cienkie obiekty, ponieważ poruszają się tak szybko. W takim przypadku pamiętaj, że wszystko w grach jest fałszywe. Chociaż kula ma tylko kilka centymetrów długości, możesz wykonać wykrywanie kolizji tak, jakby kula miała metr długości. W ten sposób możesz nadal robić ładne zrzuty pocisków i symulować czas lotu, nie martwiąc się zbytnio o pociski wypaczające przedmioty bez ich uderzania :).
Roy T.
2
Czy istnieją gry, w których fizyka pocisków (w przeciwieństwie do, powiedzmy, pocisków armatnich), szanuje takie rzeczy jak grawitacja (zrzut pocisku), opór powietrza? (To znaczy, oprócz gier specjalistycznych, w których koncentruje się precyzyjne strzelanie do celu lub coś w tym rodzaju: FPS itp.) Nie jestem graczem, ale jestem zaskoczony, że ten poziom wierności jest (nawet czasami) potrzebny.
davidbak
3
@davidbak: zależy to silnie od typowego spotkania w grze i realizmu oczekiwanego od gatunku gry. Jeśli przeważnie (tylko?) Walczysz w zwarciu, to rzeczywiście ten poziom wierności nie jest potrzebny. Ale jeśli istnieje opcja walki na dalekie odległości (np. Snajperzy lub łucznicy w ustawieniach bardziej przypominających RPG), pociski wpływające na grawitację są obecnie w pewnym stopniu oczekiwane. Jeśli skierujesz wyrzutnię rakiet w górę, nadal oczekujesz, że rakieta wyląduje i gdzieś eksploduje, nie? Mimo to trajektorie nie zawsze są obliczane na podstawie rzeczywistej fizyki, a jedynie w przybliżeniu (ze względu na wydajność)
hoffmale,
1
@davidbak Battlefield, odkąd Bad Company 2 miał zrzut kuli. Zarówno do karabinów, pistoletów, pocisków czołgów, rakiet, wszystkiego. Battlefield 3 jest bezpłatny w Origin, możesz sprawdzić (IIRC). Oczywiście Battlefield 4 ma również tę „funkcję”. Inną grą, w której możesz to zobaczyć, jest „Sniper Elite”. 2 lub 3 to nowsze tytuły. W tej grze ważną rolę odgrywa fizyka.
Apache
7

Nie jestem bynajmniej ekspertem, ale aby odpowiedzieć na twoje pytanie, tak, potrzebowałbyś wielu z tych rzeczy, o których wspomniałeś.

Na przykład w 2D możesz mieć pozycję i prędkość pocisku. (Możesz także potrzebować dożywotniego lub maksymalnego dystansu, w zależności od tego, jak zaimplementujesz swoje pociski.) Zwykle wymagałoby to 2 (x, y) wartości. Jeśli byłyby zmiennoprzecinkowe, to 16 bajtów. Jeśli masz 100 pocisków, to tylko 1600 bajtów lub około 1,5 tys. To dziś nic na maszynie.

Następnie wspominasz duszki. Potrzebowałbyś tylko jednego duszka do reprezentowania każdej kuli. Jego rozmiar zależy od głębi bitowej, na której rysujesz, oraz od tego, jak duży powinien wyglądać na ekranie. Nawet nieskompresowany, powiedzmy, 256x256 w pełnej liczbie 32 bitów na kanał, to 1 MB dla duszka. (I to byłoby bardzo duże!) Narysowałbyś tego samego duszka w każdym miejscu pocisku, ale nie zajmuje to dodatkowej pamięci dla każdej kopii duszka. Podobnie byłoby w przypadku efektu przy trafieniu.

Wspominasz o strzelaniu co 0,01 sekundy. To byłoby 100 pocisków na sekundę z twojej broni. Nawet jak na futurystyczną broń to całkiem sporo! Zgodnie z tym artykułem wikipedia :

Po naciśnięciu spustu szybkość, z jaką wystrzeliwane są rundy, jest częstością cykliczną. Typowa cykliczna szybkostrzelność wynosi 600–900 obr./min w przypadku karabinów szturmowych, 1000–1100 obr./min w niektórych przypadkach, 900–1200 obr./min w przypadku pistoletów maszynowych i pistoletów maszynowych oraz 600–1 200 obr./min w przypadku karabinów maszynowych. Miniguny M134 zamontowane na śmigłowcach szturmowych i innych pojazdach bojowych mogą osiągać szybkostrzelność ponad 100 pocisków na sekundę (6000 obr / min).

Tak by to było z prędkością śmigłowca szturmowego!

W przypadku dużego świata, takiego jak wspomniany w Battlefield / Call of Duty / itp., Mogą obliczyć wszystkie pozycje pocisków, ale nie mogą ich narysować, jeśli akcja jest daleko. Lub mogą ich nie symulować, dopóki się nie zbliżysz. (Muszę przyznać, że zgaduję trochę z tej strony, ponieważ nie pracowałem nad niczym tak dużym).

użytkownik1118321
źródło
6

Czy procesorowi nie byłoby trudno przetworzyć tysiące takich obiektów, które są tworzone, a następnie niszczone (gdy wyzwalany jest efekt przy trafieniu)? Miejsce w pamięci RAM?

Myślę, że nie doceniasz szybkości komputerów. To był czasem problem na systemach latach 80. i 90.. Jest to częściowo spowodowane tym, że oryginalne Space Invaders nie pozwalają wystrzelić kolejnej kuli, dopóki obecna nie trafi. Niektóre gry cierpiały z powodu „spowolnienia”, jeśli na ekranie było zbyt wiele ikonek.

Ale w dzisiejszych czasach? Masz wystarczającą moc obliczeniową dla tysięcy operacji na piksel, które są wymagane do teksturowania i oświetlenia. Nie ma problemu z tysiącami ruchomych obiektów; pozwala to na zniszczenie terenu (np. Red Faction), gdzie każdy fragment przetwarza kolizję z innymi fragmentami i podąża za krzywą balistyczną.

Musisz być ostrożny algorytmicznie - nie możesz naiwnie podejść do sprawdzania każdego obiektu względem każdego innego obiektu, gdy masz tysiące obiektów. Pociski zasadniczo nie sprawdzają kolizji z innymi pociskami.

Mała anegdota: pierwsza wersja sieciowego Dooma (oryginał z lat 90.) wysyłała jeden pakiet przez sieć na każdy wystrzelony pocisk. Gdy jeden lub więcej graczy otrzyma karabin maszynowy, może to łatwo przytłoczyć sieć. Lata 90. były pełne ludzi nielegalnie grających w Dooma na uniwersytetach lub w sieciach pracy, mających kłopoty z administratorami sieci, gdy sieć stała się bezużyteczna.

pjc50
źródło
Zastanawiam się, jak działała piła łańcuchowa w tym kontekście
reas0n
1
IIRC, prawdziwym problemem związanym z pierwszą zagładą sieciową jest to, że uniknięto konieczności wysyłania każdego pakietu osobno do każdego przeciwnego gracza, używając zamiast tego pakietów rozgłoszeniowych. Zmniejszyło to liczbę wysłanych pakietów, ale niestety spowodowało znaczne obciążenie procesora na każdym komputerze w sieci, w tym na tych, które nie grały w grę.
supercat
1

Nie jestem ekspertem, ale w wolnym czasie pracowałem nad strzelanką 2D.

Moja metoda

Istnieją różne klasy punktorów między klientem a serwerem (nawet w trybie offline instancja serwera jest uruchamiana w osobnym procesie i połączona z „główną” grą).

Co tyknięcie (60 na sekundę) klient oblicza namiar między wskaźnikiem myszy gracza a środkiem ekranu (tam, gdzie jest jego postać) i jest to część informacji przesyłanych do serwera. Jeśli gracz również strzela w tym momencie (zakładając, że broń jest załadowana i gotowa), tworzona jest instancja pocisku po stronie serwera, z po prostu pewnymi współrzędnymi i podstawowymi obrażeniami (które wynikają ze statystyk strzelanej broni to). Instancja pocisku używa następnie niektórych funkcji matematycznych do obliczenia prędkości X i Y z łożyska zebranego od klienta.

Za każdym kolejnym tyknięciem pocisk porusza się o te współrzędne i zmniejsza zadawane obrażenia podstawowe o określoną wartość. Jeśli ta wartość spadnie poniżej 1 lub uderzy w solidny obiekt na świecie, instancja pocisku zostanie usunięta, a ponieważ kolizje punktów testowych są niewiarygodnie tanie w 2D, nawet broń szybkostrzelna ma znikomy wpływ na wydajność.

Jeśli chodzi o klienta, informacje o pociskach nie są faktycznie odbierane przez sieć (okazało się to marnotrawstwem w testach), zamiast tego w ramach aktualizacji per-tick każdy znak ma „odpaloną” wartość logiczną, która jeśli prawda, tworzy lokalną obiekt punktora, który działa prawie dokładnie tak samo jak serwer, z tą różnicą, że ma duszka.

Oznacza to, że chociaż kula, którą widzisz, nie jest w pełni dokładnym odwzorowaniem jej na serwerze, każda różnica byłaby ledwo zauważalna, jeśli w ogóle dla gracza, a korzyści sieciowe przeważają nad wszelkimi niespójnościami.

Uwaga na różne metody

Niektóre gry, w tym moja własna, przesuwają pociski za każdym kleszczem, jakby były obiektami fizycznymi, podczas gdy inne po prostu tworzą wektor w kierunku strzelania lub obliczają całą ścieżkę pocisku w utworzonym kleszczu, na przykład w Counter- Gry strajkowe. Istnieje kilka małych sztuczek po stronie klienta, aby to ukryć, takich jak animacja strzelania pociskami, ale dla wszystkich celów i celów każda kula jest tylko laserem .

W przypadku modeli 3D, które mogą mieć złożone trafienia, standardem jest PIERWSZE testowanie kolizji z prostą ramką ograniczającą, a jeśli to się powiedzie, przejdź do bardziej „szczegółowego” wykrywania kolizji.

TheCatOfWar
źródło
0

To się nazywa wykrywanie kolizji. Komputery 8-bitowe zrobiły to, używając sprzętowo grafiki pocisków gracza. Współczesne silniki gier wykorzystują silniki fizyki i algebrę liniową. Bieżący kierunek broni jest reprezentowany jako wektor 3D. To zapewnia nieskończoną linię w kierunku ognia. Każdy poruszający się obiekt ma jedną lub więcej kulę ograniczającą, ponieważ jest to najprostszy obiekt do wykrycia kolizji z linią. Jeśli te dwa przecinają się, jest to trafienie, jeśli nie, nie ma trafienia. Ale sceneria może być przeszkodą, dlatego też należy to sprawdzić (przy użyciu hierarchicznych woluminów ograniczających). Najbliższym obiektem, który ma skrzyżowanie, jest ten, który został trafiony.

Mikael
źródło