( ПРЕДУПРЕЖДЕНИЕ: я использую здесь два приближения: первое принимает d в качестве длины дуги, а второе принимает ее в качестве ортогональной длины. Оба этих приближения должны быть хороши для относительно небольших значений d, но они не удовлетворяют точный вопрос, уточненный в комментариях.)
Математика в этом, к счастью, относительно проста. Прежде всего, мы можем найти относительный вектор от нашей центральной позиции к нашей текущей позиции:
deltaX = oX-cX;
deltaY = oY-cY;
И когда у нас есть этот относительный вектор, мы можем узнать радиус круга, над которым мы работаем, найдя его длину:
radius = sqrt(deltaX*deltaX+deltaY*deltaY);
Более того, из нашего относительного вектора мы можем найти точный угол, под которым находится линия от cX до oX:
curTheta = atan2(deltaX, deltaY);
Теперь все становится немного сложнее. Прежде всего, следует понимать, что окружность круга, то есть «длина дуги» дуги с угловой мерой 2π, составляет 2πr. В общем, длина дуги дуги с угловой мерой θ вдоль окружности радиуса r равна просто θr. Если бы мы использовали d на вашей диаграмме в качестве длины дуги, и, поскольку мы знаем радиус, мы можем найти изменение в тэте, чтобы получить нас в новой позиции, просто разделив:
deltaTheta = d/radius; // treats d as a distance along the arc
Для случая, когда d должно быть линейным расстоянием, все немного сложнее, но, к счастью, немного. Здесь d - это одна сторона равнобедренного треугольника, две другие стороны которого являются радиусом окружности (от cX / cY до oX / oY и aX / aY соответственно), и деление этого равнобедренного треугольника дает нам два прямоугольных треугольника, каждый из которых имеет d / 2 в качестве одной стороны и радиус в качестве гипотенузы; это означает, что синус половины нашего угла равен (d / 2) / радиусу, и поэтому полный угол всего в два раза больше этого:
deltaTheta = 2*asin(d/(2*radius)); // treats d as a linear distance
Обратите внимание, что если вы удалите asin из этой формулы и отмените 2, это будет то же самое, что и последняя формула; это то же самое, что сказать, что sin (x) приблизительно равен x для малых значений x, что полезно знать.
Теперь мы можем найти новый угол, просто сложив или вычтя:
newTheta = curTheta+deltaTheta; // This will take you to aX, aY. For bX/bY, use curTheta-deltaTheta
Как только у нас будет новый угол, мы можем использовать базовый триггер, чтобы найти наш обновленный относительный вектор:
newDeltaX = radius*cos(newTheta);
newDeltaY = radius*sin(newTheta);
и из нашей центральной позиции и нашего относительного вектора мы можем (наконец) найти целевую точку:
aX = cX+newDeltaX;
aY = cY+newDeltaY;
Теперь, со всем этим, есть некоторые большие предостережения, о которых нужно знать. Во-первых, вы заметите, что эта математика в основном с плавающей запятой, и на самом деле она почти обязана; Попытка использовать этот метод для обновления в цикле и округления до целочисленных значений на каждом шаге может сделать все, начиная от того, что ваш круг не замыкается (либо вращается внутрь, либо наружу каждый раз, когда вы проходите цикл), до того, как он не запустился в первом цикле. место! (Если ваш d слишком маленький, то вы можете обнаружить, что округленные версии aX / aY или bX / bY находятся именно там, где была ваша начальная позиция oX / oY.) С другой стороны, это очень дорого, особенно из-за того, что он пытается делать; в общем, если вы знаете, что ваш персонаж будет двигаться по дуге окружности, вы должны планировать всю дугу заранее, а неОтметьте это от кадра к кадру, как это, так как многие из самых дорогих вычислений здесь могут быть загружены заранее, чтобы сократить расходы. Еще один хороший способ сократить расходы, если вы действительно хотите производить поэтапное обновление, как это, - это вообще не использовать триг; если d мало, и вам не нужно, чтобы он был точным, а просто очень близким, то вы можете сделать «трюк», добавив вектор длины d к oX / oY, ортогональный к вектору к вашему центру (обратите внимание, что вектор, ортогональный (dX, dY), определяется как (-dY, dX)), а затем сжимается до нужной длины. Я не буду объяснять этот код шаг за шагом, но, надеюсь, он будет иметь смысл, учитывая то, что вы видели до сих пор. Обратите внимание, что на последнем шаге мы неявно сокращаем новый дельта-вектор,
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
линейное расстояние или дуга?