( CAVEAT: Estou usando duas aproximações aqui: a primeira leva d como comprimento do arco e a segunda leva como comprimento ortogonal. Ambas as aproximações devem ser boas para valores relativamente pequenos de d, mas não cumprem a pergunta precisa, conforme esclarecido nos comentários.)
A matemática sobre isso, felizmente, é relativamente direta. Primeiro de tudo, podemos encontrar o vetor relativo da nossa posição central para a nossa posição atual:
deltaX = oX-cX;
deltaY = oY-cY;
E uma vez que tenhamos esse vetor relativo, podemos saber o raio do círculo em que estamos trabalhando, encontrando o comprimento dele:
radius = sqrt(deltaX*deltaX+deltaY*deltaY);
Além disso, do nosso vetor relativo, podemos encontrar o ângulo preciso em que a linha de cX a oX está:
curTheta = atan2(deltaX, deltaY);
Agora as coisas ficam um pouco mais complicadas. Antes de tudo, entenda que a circunferência de um círculo - ou seja, o 'comprimento do arco' de um arco com uma medida angular de 2π - é 2πr. Em geral, o comprimento do arco com uma medida angular de θ ao longo de um círculo de raio r é apenas θr. Se usarmos d no seu diagrama como o comprimento do arco, e como conhecemos o raio, podemos encontrar a mudança no teta para nos levar à nova posição apenas dividindo:
deltaTheta = d/radius; // treats d as a distance along the arc
Para o caso em que d precisa ser uma distância linear, as coisas são um pouco mais complicadas, mas felizmente não muito. Lá, d é um lado de um triângulo de isoceles cujos outros dois lados são o raio do círculo (de cX / cY a oX / oY e aX / aY, respectivamente), e dividir esse triângulo de isoceles nos dá dois triângulos retângulos, cada um dos quais tem d / 2 como um lado e raio como hipotenusa; isso significa que o seno da metade do nosso ângulo é (d / 2) / raio e, portanto, o ângulo completo é apenas o dobro disso:
deltaTheta = 2*asin(d/(2*radius)); // treats d as a linear distance
Observe como se você tirasse o asin desta fórmula e cancelasse os 2s, isso seria o mesmo que a última fórmula; é o mesmo que dizer que sin (x) é aproximadamente x para pequenos valores de x, o que é uma aproximação útil para se conhecer.
Agora podemos encontrar o novo ângulo apenas adicionando ou subtraindo:
newTheta = curTheta+deltaTheta; // This will take you to aX, aY. For bX/bY, use curTheta-deltaTheta
Depois de termos o novo ângulo, podemos usar alguns triggers básicos para encontrar nosso vetor relativo atualizado:
newDeltaX = radius*cos(newTheta);
newDeltaY = radius*sin(newTheta);
e da nossa posição central e do nosso vetor relativo, podemos (finalmente) encontrar o ponto alvo:
aX = cX+newDeltaX;
aY = cY+newDeltaY;
Agora, com tudo isso, existem algumas advertências importantes a serem observadas. Por um lado, você notará que essa matemática é principalmente de ponto flutuante e, na verdade, quase precisa ser; tentar usar esse método para atualizar em um loop e arredondar de volta para valores inteiros a cada etapa pode fazer de tudo, desde fazer o seu círculo não fechar (espiralando para dentro ou para fora toda vez que você percorre o loop) até não iniciar no primeiro Lugar, colocar! (Se seu d é muito pequeno, você pode descobrir que as versões arredondadas de aX / aY ou bX / bY estão exatamente onde estava a sua posição inicial oX / oY.) Por outro lado, isso é muito caro, especialmente pelo que está tentando Faz; em geral, se você sabe que seu personagem se moverá em um arco circular, planeje todo o arco com antecedência e nãomarque-o de quadro em quadro como este, pois muitos dos cálculos mais caros aqui podem ser carregados com antecedência para reduzir custos. Outra boa maneira de reduzir os custos, se você realmente deseja atualizar de forma incremental como essa, é não usar trigonometria em primeiro lugar; se d for pequeno e você não precisar que seja exato, mas apenas muito próximo, poderá fazer um 'truque' adicionando um vetor de comprimento d a oX / oY, ortogonal ao vetor em direção ao seu centro (observe que um o vetor ortogonal a (dX, dY) é dado por (-dY, dX)) e depois reduza-o para o comprimento certo. Não vou explicar esse código passo a passo, mas espero que faça sentido, considerando o que você viu até agora. Observe que "reduzimos" o novo vetor delta implicitamente na última etapa,
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
uma distância linear ou é um arco?