( CAVEAT: Używam tutaj dwóch aproksymacji: pierwsza przyjmuje d jako długość łuku, a druga przyjmuje ją jako długość ortogonalną. Oba te aproksymacje powinny być dobre dla stosunkowo małych wartości d, ale nie spełniają dokładne pytanie wyjaśnione w komentarzach).
Na szczęście matematyka na ten temat jest stosunkowo prosta. Przede wszystkim możemy znaleźć wektor względny od naszej pozycji środkowej do naszej aktualnej pozycji:
deltaX = oX-cX;
deltaY = oY-cY;
Po uzyskaniu tego wektora względnego możemy poznać promień okręgu, nad którym pracujemy, znajdując jego długość:
radius = sqrt(deltaX*deltaX+deltaY*deltaY);
Co więcej, z naszego wektora względnego możemy znaleźć dokładny kąt, w którym linia od cX do oX ma:
curTheta = atan2(deltaX, deltaY);
Teraz sprawy stają się trochę trudniejsze. Przede wszystkim zrozum, że obwód koła - to znaczy „długość łuku” łuku o miary kątowej 2π - wynosi 2πr. Zasadniczo długość łuku łuku o wymiarze kątowym θ wzdłuż okręgu o promieniu r wynosi tylko θr. Gdybyśmy użyli litery d na twoim diagramie jako długości łuku, a ponieważ znamy promień, możemy znaleźć zmianę w theta, aby doprowadzić nas do nowej pozycji, po prostu dzieląc:
deltaTheta = d/radius; // treats d as a distance along the arc
W przypadku, gdy d musi być odległością liniową, rzeczy są nieco bardziej skomplikowane, ale na szczęście niewiele. Tam, d jest jedną stroną trójkąta izoceles, którego pozostałe dwa boki są promieniem koła (odpowiednio od cX / cY do oX / oY i aX / aY), a podzielenie tego trójkąta izocelowego daje nam dwa trójkąty prawe, z których każdy ma d / 2 jako jedną stronę i promień jako przeciwprostokątną; oznacza to, że sinus połowy naszego kąta wynosi (d / 2) / promień, a zatem pełny kąt jest tylko dwa razy większy:
deltaTheta = 2*asin(d/(2*radius)); // treats d as a linear distance
Zauważ, że jeśli wziąłeś asin z tej formuły i anulowałeś 2s, byłoby to takie samo jak w ostatnim wzorze; jest to to samo, co stwierdzenie, że sin (x) wynosi w przybliżeniu x dla małych wartości x, co jest przydatnym przybliżeniem do poznania.
Teraz możemy znaleźć nowy kąt, po prostu dodając lub odejmując:
newTheta = curTheta+deltaTheta; // This will take you to aX, aY. For bX/bY, use curTheta-deltaTheta
Po uzyskaniu nowego kąta możemy użyć podstawowego wyzwalacza, aby znaleźć nasz zaktualizowany wektor względny:
newDeltaX = radius*cos(newTheta);
newDeltaY = radius*sin(newTheta);
a z naszej pozycji środkowej i naszego wektora względnego możemy (w końcu) znaleźć punkt docelowy:
aX = cX+newDeltaX;
aY = cY+newDeltaY;
Teraz, mając to wszystko na uwadze, należy pamiętać o kilku dużych zastrzeżeniach. Po pierwsze, zauważysz, że matematyka jest w większości zmiennoprzecinkowa i faktycznie musi być; próba użycia tej metody do aktualizacji w pętli i zaokrąglania z powrotem do wartości całkowitych na każdym kroku może zrobić wszystko, od sprawienia, że koło się nie zamyka (spirala do wewnątrz lub na zewnątrz za każdym razem, gdy okrążasz pętlę), po to, aby nie zacząć od pierwszego miejsce! (Jeśli twoje d jest zbyt małe, możesz odkryć, że zaokrąglone wersje aX / aY lub bX / bY są dokładnie tam, gdzie była twoja pozycja początkowa oX / oY.) Po drugie, jest to bardzo drogie, szczególnie za to, co próbuje zrobić; ogólnie, jeśli wiesz, że twoja postać będzie poruszać się po łuku kołowym, powinieneś zaplanować cały łuk z wyprzedzeniem, a niezaznaczaj go od ramki do ramki w ten sposób, ponieważ wiele z najdroższych obliczeń tutaj można załadować z przodu, aby obniżyć koszty. Innym dobrym sposobem na obniżenie kosztów, jeśli naprawdę chcesz aktualizować stopniowo w ten sposób, jest nie używanie triggera; jeśli d jest małe i nie potrzebujesz go dokładnie, ale po prostu bardzo blisko, możesz zrobić „lewę”, dodając wektor długości d do oX / oY, prostopadły do wektora w kierunku środka (zwróć uwagę, że a wektor ortogonalny do (dX, dY) jest podawany przez (-dY, dX)), a następnie zmniejszony do odpowiedniej długości. Nie będę wyjaśniać tego kodu krok po kroku, ale mam nadzieję, że będzie miał sens, biorąc pod uwagę to, co do tej pory widziałeś. Zauważ, że „zmniejszamy” nowy wektor delta domyślnie w ostatnim kroku,
deltaX = oX-cX; deltaY = oY-cY;
radius = sqrt(deltaX*deltaX+deltaY*deltaY);
orthoX = -deltaY*d/radius;
orthoY = deltaX*d/radius;
newDeltaX = deltaX+orthoX; newDeltaY = deltaY+orthoY;
newLength = sqrt(newDeltaX*newDeltaX+newDeltaY*newDeltaY);
aX = cX+newDeltaX*radius/newLength; aY = cY+newDeltaY*radius/newLength;
d
odległość jest liniowa czy jest to łuk?