To pytanie ma tylko na celu zdobycie wiedzy o tym, jak gra może poradzić sobie z tak wieloma postaciami na raz. Jestem nowy w grach, dlatego z góry proszę o wybaczenie.
Przykład
Tworzę grę obrony wieży, w której jest 15 miejsc na wieże, w których buduje się wieże, a każda z nich wyrzuca pocisk w określonym tempie; powiedzmy, że co sekundę każda z wież tworzy 2 pociski, a na polu bitwy maszerują wrogowie, powiedzmy 70 (każdy z 10 typami atrybutów, takimi jak HP, mana itp.), które będą się zmieniać w miarę przemieszczania się po pole bitwy).
Podsumowanie
Liczba wież = 15
pocisków utworzonych przez każdą wieżę na sekundę = 2
Całkowita liczba pocisków wytworzonych na sekundę = 30
jednostek w polu bitwy = 70
Czy gra radzi sobie z tymi 30 pociskami i 70 jednostkami , obsługując je na 100 różnych wątkach (co jest zbyt duże na PC) lub 1 wątku, który porusza nimi wszystkimi, zmniejsza ich wartość itp. (Co będzie rodzajem powolności , Myślę)?
Nie mam pojęcia na ten temat, więc czy ktoś może poprowadzić mnie przez to, jak to się ułoży?
źródło
Odpowiedzi:
Nie, nigdy tego nie rób. Nigdy nie twórz nowego wątku dla zasobu, to nie skaluje się w sieci, ani w aktualizowaniu jednostek. (Czy ktoś pamięta czasy, kiedy miałeś jeden wątek do odczytu na gniazdo w Javie?)
Tak, na początek, taka jest droga. „Duże silniki” dzielą część pracy na wątki, ale nie jest to potrzebne do rozpoczęcia prostej gry, takiej jak gra w obronę wieży. Prawdopodobnie jest jeszcze więcej pracy do wykonania każdego tyknięcia, które również wykonasz w tym jednym wątku. O tak i oczywiście rendering.
Cóż ... Jaka jest twoja definicja wolnego ? Dla 100 jednostek nie powinno to zająć więcej niż pół milisekundy, prawdopodobnie nawet mniej, w zależności od jakości kodu i języka, z którym pracujesz. I nawet jeśli zajmuje to dwie pełne milisekundy, nadal wystarczy, aby trafić do 60 tps (tyknięć na sekundę, nie mówiąc o klatkach w tym przypadku).
źródło
Zasada numeryczna wielowątkowości to: Nie używaj jej, chyba że musisz równolegle pracować na wielu rdzeniach procesora w celu uzyskania wydajności lub szybkości reakcji. Wymaganie „x i y powinny zdarzyć się jednocześnie z punktu widzenia użytkownika” nie jest jeszcze wystarczającym powodem do korzystania z wielowątkowości.
Czemu?
Wielowątkowość jest trudna. Nie masz kontroli nad tym, kiedy każdy wątek jest wykonywany, co może skutkować wszelkiego rodzaju niemożliwymi do odtworzenia problemami („warunki wyścigu”). Istnieją metody, aby tego uniknąć (blokady synchronizacji, sekcje krytyczne), ale wiążą się one z własnym zestawem problemów („zakleszczenia”).
Zwykle gry, które radzą sobie z tak małą liczbą obiektów, jak zaledwie kilkaset (tak, nie jest to tak dużo w rozwoju gier), zazwyczaj przetwarzają je w sposób szeregowy, każdy logiczny tik za pomocą wspólnej
for
pętli.Nawet stosunkowo słabsze procesory smartfonów mogą wykonywać miliardy instrukcji na sekundę. Oznacza to, że nawet gdy logika aktualizacji twoich obiektów jest złożona i zajmuje około 1000 instrukcji na obiekt i tyknięcie, a ty dążysz do hojnego 100 tyknięć na sekundę, masz wystarczającą moc procesora dla dziesiątek tysięcy obiektów. Tak, jest to bardzo uproszczone obliczenie z tyłu koperty, ale daje pomysł.
Powszechną mądrością przy tworzeniu gier jest to, że logika gry bardzo rzadko stanowi wąskie gardło gry. Najważniejszą częścią wydajności jest prawie zawsze grafika. Tak, nawet w grach 2d.
źródło
Inne odpowiedzi dotyczyły wątków i mocy współczesnych komputerów. Aby odpowiedzieć na większe pytanie, starasz się tutaj unikać sytuacji „n-kwadrat”.
Na przykład, jeśli masz 1000 pocisków i 1000 wrogów, naiwnym rozwiązaniem jest sprawdzenie ich wszystkich względem siebie.
Oznacza to, że otrzymujesz p * e = 1.000 * 1.000 = 1.000.000 różnych czeków! To jest O (n ^ 2).
Z drugiej strony, jeśli lepiej uporządkujesz swoje dane, możesz tego uniknąć.
Na przykład, jeśli wymieniasz na każdym kwadracie siatki, którzy wrogowie są na tym kwadracie, możesz przerzucić 1000 pocisków i po prostu sprawdzić kwadrat na siatce. Teraz musisz tylko sprawdzić każdy pocisk względem kwadratu, to jest O (n). Zamiast miliona czeków na każdą klatkę potrzebujesz tylko tysiąc.
Myślenie o uporządkowaniu danych i ich wydajnym przetwarzaniu ze względu na tę organizację jest największą pojedynczą optymalizacją, jaką możesz kiedykolwiek zrobić.
źródło
Nie twórz wątków dla zasobu / obiektu, ale dla sekcji logiki programu. Na przykład:
Zaletą tego jest to, że GUI (np. Przyciski) niekoniecznie utknie, jeśli logika jest wolna. Użytkownik może nadal wstrzymywać i zapisywać grę. Jest również dobry do przygotowania gry do gry wieloosobowej, gdy oddzielisz grafikę od logiki.
źródło
Nawet Space Invaders zarządzały dziesiątkami interaktywnych obiektów. Natomiast dekodowanie jednej klatki wideo HD H264 wymaga setek milionów operacji arytmetycznych. Dostępna jest duża moc obliczeniowa.
To powiedziawszy, nadal możesz zwolnić, jeśli go zmarnujesz. Problemem jest nie tyle liczba obiektów, ile liczba przeprowadzonych testów zderzeniowych; podejście prosty sprawdzenia każdego obiektu przed siebie obiektów kwadratów liczby obliczeń wymagane. Testowanie 1001 obiektów pod kątem kolizji wymagałoby miliona porównań. Często rozwiązuje się to poprzez np. Nie sprawdzanie pocisków pod kątem kolizji.
źródło
Nie zgadzam się z niektórymi innymi odpowiedziami tutaj. Oddzielne wątki logiczne są nie tylko dobrym pomysłem, ale są niezwykle korzystne dla szybkości przetwarzania - jeśli logika jest łatwa do rozdzielenia .
Twoje pytanie jest dobrym przykładem logiki, którą prawdopodobnie można oddzielić, jeśli możesz dodać na niej dodatkową logikę. Na przykład, możesz uruchomić kilka wątków wykrywających uderzenia, blokując wątki do określonych obszarów przestrzeni lub muteksując zaangażowane obiekty.
Prawdopodobnie NIE chcesz jednego wątku dla każdej możliwej kolizji, tylko dlatego, że prawdopodobnie spowoduje to utratę harmonogramu; istnieje również koszt związany z tworzeniem i niszczeniem wątków. Lepiej zrobić pewną liczbę wątków wokół rdzeni systemu (lub użyć metryki takiej jak stara
#cores * 2 + 4
), a następnie użyć ich ponownie po zakończeniu procesu.Jednak nie wszystkie logiki można łatwo oddzielić. Czasami twoje operacje mogą obejmować wszystkie dane gry naraz, co sprawia, że wątki są bezużyteczne (w rzeczywistości szkodliwe, ponieważ musisz dodać kontrole, aby uniknąć problemów z wątkami). Ponadto, jeśli wiele etapów logiki jest w dużym stopniu zależnych od siebie występujących w określonych zamówieniach, będziesz musiał kontrolować wykonywanie wątków w taki sposób, aby zapewnić, że nie będą dawały wyników zależnych od zamówienia. Jednak ten problem nie został wyeliminowany przez nieużywanie wątków, wątki tylko go zaostrzają.
Większość gier nie robi tego po prostu dlatego, że jest bardziej złożona niż przeciętny twórca gier jest w stanie poradzić sobie z tym, co zwykle nie jest wąskim gardłem. Zdecydowana większość gier jest ograniczona GPU, a nie CPU. Chociaż poprawa szybkości procesora może ogólnie pomóc, zwykle nie jest to najważniejsze.
To powiedziawszy, silniki fizyki często wykorzystują wiele wątków i mogę wymienić kilka gier, które moim zdaniem skorzystałyby z wielu wątków logicznych (na przykład gry Paradox RTS, takie jak HOI3).
Zgadzam się z innymi postami, że prawdopodobnie nie będziesz musiał używać wątków w tym konkretnym przykładzie, nawet jeśli może to być korzystne. Wątek powinien być zarezerwowany dla przypadków, w których występuje nadmierne obciążenie procesora, którego nie można zoptymalizować innymi metodami. To ogromne przedsięwzięcie, które wpłynie na podstawową strukturę silnika; nie jest to coś, na co można się skupić po fakcie.
źródło
Myślę, że w innych odpowiedziach brakuje ważnej części pytania, ponieważ zbytnio koncentruję się na wątku pytania.
Komputer nie obsługuje jednocześnie wszystkich obiektów w grze. Obsługuje je kolejno.
Gra komputerowa rozwija się w dyskretnych odstępach czasu. W zależności od gry i prędkości komputera kroki te wynoszą zwykle 30 lub 60 kroków na sekundę lub tyle / kilka kroków, ile komputer może obliczyć.
W jednym takim kroku komputer oblicza, co zrobią poszczególne obiekty w grze, i odpowiednio je aktualizuje, jeden po drugim. Mógłby to zrobić nawet równolegle, używając wątków, aby być szybszymi, ale jak wkrótce zobaczymy, prędkość nie jest wcale problemem.
Przeciętna procesora powinna wynosić 2 lub GHz, to znaczy 10 9 taktów na sekundę. Jeśli obliczenia 60 timesteps na sekundę, że liście 10 9 cykli / 60 cykli zegara = 16666666 zegara za czas kroku. Przy 70 jednostkach nadal mamy około 2400000 cykli zegara na jednostkę. Gdybyśmy musieli zoptymalizować, moglibyśmy zaktualizować każdą jednostkę w zaledwie 240 cyklach, w zależności od złożoności logiki gry. Jak widać, nasz komputer jest około 10 000 razy szybszy niż to konieczne.
źródło
Oświadczenie: Mój ulubiony rodzaj gier jest oparty na tekście i piszę to jako długoletni programista starego MUD.
Myślę, że ważne pytanie, które musisz sobie zadać, brzmi: czy potrzebujesz w ogóle nici? Rozumiem, że gra graficzna prawdopodobnie ma większe zastosowanie MT, ale myślę, że zależy to również od mechaniki gry. (Warto również wziąć pod uwagę, że dzięki procesorom graficznym, procesorom i wszystkim innym zasobom, które mamy dzisiaj, są znacznie potężniejsze, co sprawia, że obawy o zasoby są tak problematyczne, jak mogłoby się wydawać; w rzeczywistości 100 obiektów jest praktycznie zerowych). Zależy to również od tego, jak zdefiniujesz „wszystkie postacie jednocześnie”. Masz na myśli dokładnie w tym samym czasie? Nie będziesz tego miał, jak słusznie zauważa Peter, więc wszystko to jest bez znaczenia w dosłownym tego słowa znaczeniu; wydaje się tylko w ten sposób.
Zakładając, że przejdziesz do wątków: zdecydowanie nie powinieneś brać pod uwagę 100 wątków (a ja nawet nie zamierzam się zastanawiać, czy to za dużo dla twojego procesora, czy nie; odnoszę się tylko do komplikacji i praktyczności).
Pamiętaj jednak: wielowątkowość nie jest łatwa (jak podkreśla Philipp) i ma wiele problemów. Inni mają znacznie większe doświadczenie (o wiele) niż ja, ale mówię, że oni też sugerowaliby to samo (nawet gdyby byli bardziej zdolni niż ja - szczególnie bez mojej praktyki).
Niektórzy twierdzą, że nie zgadzają się, że wątki nie są korzystne, a niektórzy twierdzą, że każdy obiekt powinien mieć wątek. Ale (i znowu jest to cały tekst, ale nawet jeśli weźmiesz pod uwagę więcej niż jeden wątek, nie musisz - i nie powinien - rozważać go dla każdego obiektu), jak wskazuje Philipp, gry mają tendencję do iteracji po listach. Ale to nie tylko (jak sugeruje, chociaż zdaję sobie sprawę, że on reaguje tylko na twoje parametry tak niewielu obiektów) dla tak niewielu obiektów. W MUD jestem programistą, ponieważ mamy następujące (i to nie wszystko, co dzieje się w czasie rzeczywistym, więc miej to na uwadze):
(Liczba wystąpień jest oczywiście różna - wyższa i niższa)
Telefony komórkowe (NPC, tj. Postać inna niż gracz): 2614; prototypy: 1360 Obiekty: 4457; prototypy: 2281 Pokoje: 7983; prototypy: 7983. Każdy pokój ma zwykle swoją własną instancję, ale mamy też pokoje dynamiczne, to znaczy pokoje w pokoju; lub pokoje wewnątrz telefonu komórkowego, np. żołądek smoka; lub pokoje w obiektach, np. wchodzisz do magicznego obiektu). Należy pamiętać, że te dynamiczne pokoje istnieją na obiekt / pokój / telefon komórkowy, który faktycznie je zdefiniował. Tak, to bardzo przypomina pomysł World of Warcraft (nie gram, ale znajomy kazał mi grać, gdy miałem komputer z systemem Windows) przez pewien czas, z wyjątkiem tego, że mieliśmy go na długo przed stworzeniem World of Warcraft.
Skrypty: 868 (obecnie) (co dziwne, nasze polecenie statystyki nie pokazuje, ile mamy prototypów, więc dodam to). Wszystkie odbywają się w obszarach / strefach, a mamy ich 103. Mamy również specjalne procedury, które działają w różnych momentach. Mamy też inne wydarzenia. Następnie mamy również podłączone gniazda. Telefony poruszają się, wykonują różne czynności (oprócz walki), mają interakcje z graczami i tak dalej. (Podobnie jak inne rodzaje bytów).
Jak sobie z tym wszystkim poradzić bez opóźnień?
gniazda: select (), kolejki (wejście, wyjście, zdarzenia, inne rzeczy), bufory (wejście, wyjście, inne rzeczy) itp. Są one odpytywane 10 razy na sekundę.
postacie, przedmioty, pokoje, walka, wszystko: wszystko w centralnej pętli na różnych pulsach.
My (moja implementacja oparta na dyskusji między założycielem / innym programistą a mną) przeprowadziliśmy obszerne śledzenie połączonych list i testowanie poprawności wskaźnika i mamy więcej niż wystarczającą ilość wolnych zasobów, gdybyśmy rzeczywiście tego potrzebowali. Wszystko to (poza tym, że rozszerzyliśmy świat) istniało lata temu, kiedy było mniej pamięci RAM, mocy procesora, miejsca na dysku twardym itp. I nawet wtedy nie mieliśmy problemów. W opisanych pętlach (skrypty powodują to, podobnie jak resety obszarów / zaludnienia, podobnie jak inne rzeczy), potwory, obiekty (przedmioty) i inne rzeczy są tworzone, uwalniane i tak dalej. Połączenia są również akceptowane, odpytywane i wszystko, czego można oczekiwać.
źródło