Jak właściwie radzić sobie z kolizją w grze opartej na komponentach?

11

Próbuję owinąć głowę nad sposobami prawidłowego radzenia sobie z kolizją w grze zaprojektowanej wokół komponentów.

Widzę, że w wielu przykładach coś PhysicsComponenttakiego dodaje się do listy komponentów bytu, ale faktyczna implementacja mnie dezorientuje.

Aby to zadziałało, PhysicsComponentmusiałby mieć dostęp do otaczającego świata. To nie ma dla mnie intuicyjnego sensu. Czy składnik nie powinien być nieświadomy nie tylko swojego kontenera (bytu), ale kontenera kontenera (świata)?

Dla mnie brzmi to tak, jakby poziom lub scena powinny utrzymywać listę tych bytów, a każda aktualizacja gry, pętla między bytami, aby ustalić, które kolidują.

Moje pytanie dotyczy po pierwsze, czy jest to dobry projekt, a po drugie, w jaki sposób ustalić, które podmioty mogą kolidować. Podejrzewam, że stałe podmioty mogą implementować pusty interfejs IRigidBody, aby poziom mógł określić, które podmioty na liście obsługują kolizję. Ale czy to łamie projekt komponentu?

Zamiast tego powinny zawierać pusty składnik RigidBody? To może być lepsze, ponieważ nie zawsze może być puste, a to podejście jest bardziej przyszłościowe. Jedynym problemem jest złożoność. Scena musiałaby zapętlać nie tylko każdą jednostkę, ale także jej komponenty, aby ustalić, czy ma ten komponent RigidBody.

Po trzecie, kiedy się zderzają, oba podmioty powinny zostać w jakiś sposób poinformowane i nie jestem pewien, jak to osiągnąć.

Powiedzmy, że obie istoty zawierały HealthComponent, a kiedy zderzyły się, ich zdrowie spadłoby o jakąś dowolną wartość, 5. Przypuszczam, że zajmowanie się tym, gdy wykryje kolizję między dwoma istotami, będzie obowiązkiem sceny.

Ale czy ta scena jest za zbyt odpowiedzialna? Widziałem, jak to wymyka się spod kontroli i staje się niewygodne, gdy scena jest odpowiedzialna za wiele rzeczy, do których podmioty nie powinny (?) Mieć dostępu.

Edycja: pytanie zaktualizowane o więcej szczegółów.

Jason Watson
źródło
4
Ta odpowiedź wydaje się odpowiednia do linku do: gamedev.stackexchange.com/questions/13797/...
Andrew Russell
Połączona odpowiedź Andrew, odpowiedź Jamesa i odpowiedź Nicka Wiggilla zasługują na +1. Pomyśl o komponentach bardziej jak o danych niż o typowej klasie zarówno z danymi, jak i metodami (nie dlatego, że nie będą miały metod, ale nie powinny ponosić dużej odpowiedzialności). Spójrz na system komponentów Artemis ( piemaster.net/2011/07/entity-component-artemis ) na przykład dobrej struktury komponentów.
michael.bartnett

Odpowiedzi:

5

Szczerze mówiąc, od strony projektowania komponentów moje komponenty nie znają się nawzajem, chyba że muszą (i to jest bardzo rzadkie). Nawet wtedy zwykle wolę, aby komponenty rozmawiały z jakimś systemem zarządzania wymienionymi komponentami zamiast bezpośrednio z komponentami. (Interfejs skryptowy wygląda jak obiekt do obiektu, ale nie ma go w silniku, hehe).

W tym celu opowiedziałbym się za tym, co powiedziałeś na początku, i poszedłbym za komponentami fizyki, które istnieją wszędzie tam, gdzie obiekty muszą być testowane pod kątem kolizji. Teraz wyraźnie te obiekty mogą być zmuszone do poinformowania innych komponentów o sobie podczas rozwiązywania kolizji, ale, jak wspomniano, wolę to samo wydarzenie, aby przejść do obiektów przez inny interfejs (albo do menedżera, albo przez system powiadamiania o zdarzeniach, jeśli masz na przykład jedną z nich).

Myślę, że jesteś na dobrej drodze i potrzebujesz tylko „Tak, to brzmi dobrze” Więc… Tak, to brzmi dobrze.

Mam nadzieję że to pomoże!

James
źródło
3

Zwykle silniki gier używają zewnętrznej biblioteki do wykrywania kolizji między jednostkami. W tym scenariuszu tworzy się lub rejestruje te podmioty, które mają składnik PhysicsComponent, w świecie „fizyki”. I ilekroć wykryje kolizję między dwiema jednostkami (A i B), zwykle wywołuje oddzwonienie do jednostki A, informując, że zderzył się z jednostką B, i to samo dla jednostki B, informując, że zderzyła się z jednostką A.

W przypadku 2D dobrze znaną darmową biblioteką fizyki jest Box2D. Warto również przyjrzeć się Chipmunk. W przypadku 3D Bullet jest darmowy (prawdopodobnie najlepszy darmowy, jaki można znaleźć). Havok i PhysX są znane z tego, że są używane w wielu potrójnych grach typu A.

Pogromca bajtów
źródło
2

Problem polega na tym, że wykrywanie kolizji (jest to jedyny powód, dla którego potrzebujesz jednego elementu zawierającego elementy fizyki, aby odwoływać się do innego takiego elementu), odbywa się na wyższym poziomie, zwykle albo bezpośrednio w pętli gry, albo przez funkcja / klasa pomocnika, która to robi. Moja odpowiedź do kogoś kilka tygodni temu mówi o usunięciu bytu na podobnych podstawach i pamiętając, że jeśli kolizja spowoduje zniszczenie jednego z twoich bytów, ta sama odpowiedź w danym kontekście będzie dla ciebie bardzo istotna , ponieważ „siła wyższa” nadal będzie musiała zarządzać oczyszczaniem ciał… że tak powiem.

Robienie czegokolwiek pomiędzy jednostkami samotnie nie jest generalnie wykonalne. Prawie zawsze istnieje serwer proxy dla takich rzeczy, w solidnej architekturze, czy to poprzez bezpośrednie zarządzanie jak w przypadku wykrywania kolizji, czy wysyłanie zdarzeń jak np. system przesyłania wiadomości dla graczy, w którym menedżer przesyłania komunikatów po stronie klienta nasłuchuje wiadomości wysyłanych od graczy i wysyła je na serwer, aby wszyscy mogli je ponownie wysłać.

Inżynier
źródło
2

Mam teraz dokładnie taki sam problem jak ty w projekcie. Postanowiłem poradzić sobie z tym, mając „ColliderComponent”, który utrzymuje ciało od silnika fizyki. Ciała są definiowane zewnętrznie (definicje kształtów, które są ładowane w czasie wykonywania), a następnie dodawane do świata fizyki i do elementów gry, do których należą.

Korzystam z Box2D, gdzie możesz dołączyć „detektor kolizji”, który zostanie powiadomiony przez kolizję. Ponieważ dodałem wskaźnik do mojego „ColliderComponent” do danych użytkownika bodys, mogę uzyskać moje dwa ColliderComponent, które były częścią kolizji.

Tak więc, kiedy dochodzi do kolizji, dzieje się następująco: ColliderComponents, które były częścią kolizji, wyślą wiadomość do swojego właściciela-obiektu (podmiotu gry), który z kolei wyemituje tę wiadomość do wszystkich swoich składników.

Każdy komponent może wówczas zareagować na ten komunikat, więc „komponent zdrowia” może usunąć 5 punktów ze zdrowia itp.

grzmot
źródło
+1: Używam bardzo podobnego podejścia. W jaki sposób określasz wielkość szkód w zależności od rodzaju zderzonych bytów?
Dnia
@ Den Wysyłam różne wiadomości (lub dane wiadomości) w zależności od kolizji. Działa to dla mnie dobrze, ponieważ nie mam wielu różnych spraw do załatwienia.
bummzack,
0

Utwórz system kolizji, który zna „świat” kolizji. Następnie w komponencie kolizji powiedz systemowi kolizji, aby rzucił promień z punktu A do B i zareaguje, jeśli koliduje, czy nie.

Powodzenia. Uważam, że system kolizji jest jedną z bardziej żmudnych części silnika gry.

c2tp
źródło