Zakrzywiony ruch między dwoma punktami

15

Jaka jest dobra technika umożliwiająca obiektowi przemieszczanie się między punktami w ładnym zakrzywionym ruchu?

Pozycja końcowa może również być w ruchu, na przykład trajektoria pocisku samonaprowadzającego.

anonimowa
źródło

Odpowiedzi:

11

Zakładając, że chcesz, aby była to klatka po klatce (w której cel mógłby się nawet poruszać), a nie wstępnie obliczona trajektoria, jest to naprawdę niewiarygodnie proste:

W każdej ramce porównaj wektor prędkości pocisku z wektorem ( cel pozycji - pocisk pozycji ) ; to znaczy wektor wskazujący od pocisku do celu. Każda klatka, jeśli dwa wektory nie mają tego samego kierunku, następnie obróć nieco wektor prędkości w kierunku drugiego wektora, więc każda klatka pocisk przybliża się nieco do celu.

Możesz określić, czy obracać się w prawo, czy w lewo, patrząc na znak iloczynu krzyżowego między dwoma wektorami.


[Edytuj] Kod XNA (nie mam XNA do przetestowania tego):

//Once a frame:

//Get vector spanning from missile to target
Vector2 vectorToTarget = target.Position - missile.Position;

//Convert to Vector3 to do cross-product
Vector3 vectorToTarget3 = new Vector3(vectorToTarget, 0);
Vector3 missileVelocity3 = new Vector3(missile.Velocity, 0);

//Rotate clockwise/counter-clockwise is determined by sign of cross-product
int crossProductSign = Vector3.Cross(missileVelocity3, vectorToTarget3).Z;

//Positive cross-product means rotate counter-clockwise, negative is clockwise
double rotationAngle = 0;
if(crossProductSign > 0)
    rotationAngle = -0.05;
else if(crossProductSign < 0)
    rotationAngle = 0.05;

//I'm not sure how to do rotation in XNA, but the internets tell me it's something like this:
missile.velocity = Vector2.Transform(missile.velocity, Matrix.CreateRotationZ(rotationAngle))

Zauważ, że ponieważ rotationAnglema tylko trzy możliwe wartości, wszystkie możliwe wartości Matrix.CreateRotationZ(rotationAngle)mogą być buforowane, więc nie musisz wywoływać jej w każdej ramce.

BlueRaja - Danny Pflughoeft
źródło
Czy możesz podać jakiś pseudo kod, ponieważ jestem nowy w tym wszystkim. Obecnie pracuję tylko w 2. wymiarze, aby usunąć pewne komplikacje.
anonimowy
@anonymouse: jasne, spróbuj tego
BlueRaja - Danny Pflughoeft
15

Istnieją dwie możliwe techniki:

Pierwsza technika polega na przeprowadzeniu symulacji opartej na ramkach . Jest to dobre, jeśli wykonujesz coś w rodzaju pocisku samonaprowadzającego, który nie musi trafiać dokładnie w cel.

W takim przypadku chcesz śledzić pozycję i prędkość obiektu. Każda klatka patrzy na kierunek do celu i bieżący kierunek ruchu i odpowiednio dostosowuje prędkość.

Jeśli natychmiast zmienisz prędkość, twój pocisk zawsze trafi w cel. Ale jeśli dostosujesz prędkość o niewielką wartość w każdej klatce, twój pocisk skręci w kierunku celu - a jeśli zakrzywi się wystarczająco wolno, cel może go uniknąć.

Drugą techniką jest użycie metody parametrycznej . Jest to przydatne do animowania rzeczy, w których chcesz precyzyjnie i przewidywalnie trafić w cel. W takim przypadku zwykle bierzesz „czas” za parametr i nadajesz mu jakąś funkcję.

Szczególnie przydatnym zestawem funkcji są równania ruchu, których nauczyłeś się w fizyce liceum. Stosując je do obu osi, można uzyskać trajektorie balistyczne. Przy odrobinie matematyki możesz określić początkowe parametry trafienia w cel - nawet w ruchomy, jeśli porusza się on w sposób przewidywalny.

XNA zapewnia również szereg funkcji interpolacji i ruchu zakrzywionego. Zajrzyj do dokumentacji dla Vector2 i dlaMathHelper . Zapewniają niektóre funkcje interpolacji, których można używać, a nawet łączyć, aby robić ciekawe rzeczy. Na przykład wystrzelenie pocisku: Lerp(interpolacja liniowa) pozycji pocisku od punktu początkowego do pozycji docelowej, a także przesunięcie tej pozycji docelowej od jakiegoś początkowego celu do rzeczywistej (zmieniającej się) pozycji celu. Zapewni to przyjemny efekt „blokowania”.

(Istnieją również pewne funkcje do tworzenia krzywych, na przykład: CatmulRom, Hermite. Prawdopodobnie trudniej jest je z powodzeniem zastosować do ruchomego celu.)

Jeśli spojrzysz na „łagodzenie” (w kontekście animacji), możesz uzyskać bardziej interesujące funkcje interpolacji, które mogą dać ciekawe efekty, takie jak przyspieszenie.

Teraz - możesz powiedzieć, że ta technika daje dziwne wyniki, gdy twój cel się porusza. Jednak w praktyce, dopóki twój pocisk porusza się szybciej niż twój cel, zwykle wygląda dobrze. Jeśli jest to problem, prawdopodobnie i tak powinieneś użyć techniki opartej na ramkach.

Andrew Russell
źródło
3

Możesz poszukać fal sinusoidalnych lub krzywych Beziera . Nie wiem, czy podejście do fali sinusoidalnej jest normalne, ale nie rozumiem, dlaczego byłoby tak słabo.

Kaczka komunistyczna
źródło
Używanie krzywych Beziera z B-splajnami pozwala na dość dokładne przedstawienie dowolnej krzywej. Jeśli potrzebujesz precyzji, splajny sześcienne są nieco dokładniejsze. Należy pamiętać, że czasami niedokładność jest pożądanym akcentem organiczności.
doppelgreener
+1 dla krzywych Beziera. Dla opisanego zastosowania jest to prawdopodobnie najłatwiejszy i najbardziej kontrolowany.
ggambett
1

Możesz rzucić okiem na Zachowania sterujące, zdefiniowane przez Craiga Reynoldsa: http://red3d.com/cwr/steer/

Jest to często używane w AI, aby NPC zbliżali się do celu.

emartel
źródło