Jak stworzyć cząsteczki, które reagują na gracza i wrogów?

38

Obecnie tworzę grę z własnym silnikiem gry, który napisałem w C ++ i używam najnowszego pakietu SDK directx.

Ta gra to z góry strzelanka kosmiczna (z dość ciekawym zwrotem akcji), a ja chcę uzyskać efekt mgławicy, przez który przeleci gracz. Naprawdę chcę spróbować przykuć miłe wrażenia dotykowe setek cząstek poruszających się na drodze statku gracza, gdy wlatuje w nie. W pewnym sensie cząstki poruszałyby się na drodze gracza w Geomtry Wars na XBLA.

Jestem doświadczonym programistą, jeśli chodzi o C ++. Nie wiem jednak, jak zacząć wdrażać ten efekt. Czy ktoś ma jakieś fajne pomysły lub opcje projektowe, na które chciałbym przyjrzeć się? Nie krępuj się odpowiadać na każdy rodzaj głębi, na jaką masz ochotę.

Matt McDonald
źródło

Odpowiedzi:

65

To fajny pomysł. Będziesz potrzebować jakiegoś gradientu dyfuzji wokół swojego statku. Są trzy modele fizyczne, o których mogę pomyśleć:

  1. Chcesz, aby wyglądało to prawie jak płynne medium, w którym gradient ciśnienia ponownie się równoważy, tj. Gdy miniesz jakieś cząstki, wrócą one z powrotem do twojego śladu (jak woda za łodzią). W tym przypadku pozycje cząstek są absolutne i tylko ich stosunek do gracza tymczasowo modyfikuje ich pozycję renderowania . To trochę tak, jak gdy przesuwasz grubą lupę nad przedmiotami, a dyfrakcja wydaje się sprawiać, że się poruszają - ale tylko do momentu, gdy odsuniesz szkło. W tym przypadku twój statek jest szkłem.

  2. Jeśli chcesz, aby odsunęli się od statku i kontynuowali ruch, gdy się przeprowadzą. To jest jak standardowa fizyka w ogólnie pustej przestrzeni, w której nie ma (lub bardzo małych) gradientów ciśnienia.

  3. Chcesz szybko oddalić cząsteczki od statku, gdy się zbliża, jak w (1) i (2), ale gdy statek zniknie, cząstki będą powoli równoważyć się, aby być w równej odległości po tobie.

Wspólne dla wszystkich trzech rozwiązań : musisz mieć pole dyfuzji, które porusza się wraz ze swoim statkiem. W tym przykładzie nadamy mu okrągły kształt. Następnie wykrywamy wektor, nazywamy go v1, między statkiem a każdą cząsteczką w tym regionie. Odepchnij swoją cząsteczkę wzdłuż tego wektora. To, jak mocno go odepchniesz, będzie zależeć od jego odległości od statku: użyj 1 - v1.magnitude. Ta formuła daje siłę liniową, ale można ją zmodyfikować, aby użyć czegoś innego, jak okrągła krzywa siły, która zmniejsza siłę w kierunku krawędzi. Dzięki temu wyglądałby lepiej, jakby wokół statku znajdował się raczej kulisty niż kołowy gradient ciśnienia.

Dla rozwiązania 1 : Wystarczy teraz zmodyfikować pozycję renderowania tej cząstki (czyli pozycję duszka) przy każdej aktualizacji renderowania , za pomocą tego wektora. Ponieważ robisz to w ten sposób, jest to wyłącznie efekt renderowania i nie ma wpływu na rzeczywistą pozycję cząstki na świecie. Dodajesz więc pozycję świata do przesunięcia renderowania (v1), a teraz masz ładnie przemieszczone cząstki, gdy przechodzisz w ich kierunku lub obok nich, i płynnie cofasz cząsteczki, gdy przechodzisz (za tobą).

Dla rozwiązania 2 : Zamiast po prostu zastosować v1 do pozycji widoku, zastosuj ją przy każdej aktualizacji logiki , do pozycji cząsteczki. Więc p1.position += v1. Więc przykładasz siłę przyspieszającą do cząstki, co przekłada się na prędkość. Prawdopodobnie będziesz chciał, aby prędkość każdej cząstki została wytłumiona, aby stopniowo zwolniły i zatrzymały się po przejściu. Możesz zobaczyć, jak to rozwiązanie spowoduje skupienie cząstek w twojej mgławicy, ponieważ nigdy się nie rozproszą. Nie jestem zbyt realistyczny, jestem pewien, ponieważ mgławice mają w sobie gradienty ciśnienia, bez względu na to, jak słabe w rzeczywistości.

Dla rozwiązania 3: Taki sam jak (2), ale w tym przypadku będziesz musiał ponownie rozproszyć cząstki. Aby to zrobić, jest trochę brutalne podejście, ale ponieważ są to tylko cząstki, a tym samym cukierki, prawdopodobnie nie musisz obejmować dużego obszaru zainteresowania (prawdopodobnie tylko promień playerPosition + maxPlayerSpeedPerTick lub cokolwiek innego obszar prostokątny ogranicza to, do celów logicznych). Każda cząstka przyłoży siłę do drugiej cząstki w obszarze zainteresowania. Zastosują ponownie siły oparte na ich odległościach od siebie. Oblicz wszystkie siły międzycząstkowe w jednym przemiataniu w obszarze zainteresowania, a następnie zastosuj wszystkie siły w jednym przemiataniu. Na koniec upewnij się, że wykonujesz to przetwarzanie siły między cząstkami tylko na cząstkach o zerowej prędkości. A gdy jakaś cząstka osiągnie minimalną prędkość,

Istnieją różne formuły dyfuzyjne itp., Ale myślę, że w tym przypadku proste rozwiązanie działa najlepiej.

Inżynier
źródło
Kolego, niestety obecnie nie mam reputacji, by głosować za twoją odpowiedzią (i mógłbym to zrobić tylko raz, co jest mniej niż na to zasługuje). Absolutnie przybiłeś to, czego szukam w swoim pierwszym rozwiązaniu. Fantastyczna odpowiedź. Szczerze. Dzięki!
Matt McDonald,
Cała przyjemność Matt, to dobre pytanie i warto zgiąć mózg!
Inżynier
Zdecydowałem również, że przy niewielkiej zmianie kodu mogę to zastosować do mniejszych asteroid w obrębie pasa. Dzięki jeszcze raz.
Matt McDonald,