Como chegar a um ângulo escolhendo a direção de rotação mais curta

Eu tenho um personagem no meu jogo que deve girar suavemente para chegar a um ângulo desejado. Considere o angle como o ângulo atual e o touchAngle como o ângulo desejado, que é sempre entre 0 e 360. Eu quero adicionar + 1 / -1 ao ângulo atual em cada atualização do jogo para chegar ao touchAngle desejado. O problema é primeiro, deve escolher a direção e deve estar entre 0 e 360. este é o meu pseudo código:

 int touchAngle; float angle; public void update() { if ((int)angle != touchAngle) angle += ??? } 

Como você tem valores sempre normalizados no intervalo [0 360] isso não deve ser muito difícil. Você só precisa distinguir dois casos diferentes:

 angle < touchAngle angle > touchAngle 

no primeiro caso, queremos girar no sentido anti-horário para que a atualização tenha que ser angle =+ 1 (supondo que você queira transformar 1 de cada ciclo de atualização). No segundo caso, queremos girar no sentido horário para que a atualização seja o angle -= 1 .

O problema é que nem sempre é o caminho mais curto para rodar. Por exemplo, se:

 angle == 359 touchAngle == 1 

nós não queremos fazer todo o caminho 358, 357, 356 … em vez disso, queremos girar no sentido anti-horário para apenas 2 unidades: 360, 1. Isso pode ser alcançado comparando a distância entre os ângulos abs(angle - touchAngle) .

Se esse valor for maior que 180 , significa que estamos indo na direção errada, então temos que fazer o caminho

 if(angle < touchAngle) { if(abs(angle - touchAngle)<180) angle += 1; else angle -= 1; } else { if(abs(angle - touchAngle)<180) angle -= 1; else angle += 1; } 

claro que tudo isso até ((int)angale != touchAngle) . Eu poderia ter cometido erros com os casos, mas este é o princípio.

Geralmente você quer trazer o tempo para a equação, de modo que você possa suavemente mudar o ângulo ao longo do time . A maioria das configurações tem uma maneira de obter o tempo necessário para renderizar o quadro anterior e a maneira típica de fazer isso é dizer …

 int touchAngle; float angle; float deltaTime; //Time it took to render last frame, typically in miliseconds float amountToTurnPerSecond; public void update() { if((int)angle != touchAngle) angle += (deltaTime * amountToTurnPerSecond); } 

Isso fará com que, a cada segundo, seu ângulo seja alterado por amountToTurnPerSecond , mas amountToTurnPerSecond lentamente, em cada quadro, a quantidade correta de alterações para que fique suave. Algo a se notar sobre isso é que você não vai acabar normalmente no touchAngle maior parte do tempo, então verificar se você vai ao invés e ao invés disso definir o touchAngle seria uma boa idéia.

Editar para acompanhar o comentário:

Eu acho que a maneira mais fácil de atingir a direção correta por turno é na verdade não usar ângulos. Você precisa obter a direção relativa do seu toque para o seu personagem em um espaço 2D. Normalmente, você leva o toque do espaço da canvas para o espaço do mundo e, em seguida, faz os cálculos lá (pelo menos é o que fiz no passado). Comece por colocar o seu toque no espaço do mundo e, em seguida, use o produto vetorial cruzado para determinar a direção. Isso parece com o seguinte …

 character position = cx, cy target position = tx, ty current facing direction of character = rx, ry 

Primeiro nós calculamos a distância entre o personagem e a posição alvo:

 dx = tx - cx dy = ty - cy 

Isso não só nos dá a distância de nós, mas essencialmente nos diz que se estivéssemos em 0, 0, qual quadrante no espaço 2d seria o alvo?

Em seguida, fazemos um produto cruzado:

 cross_product = dx * ry - dy * rx 

Se isso for positivo, você vai para um lado, se for negativo, vai para o outro. A razão pela qual isso funciona é que, se a distância é, por exemplo (-5, 2) , sabemos que se estamos olhando diretamente para o norte, o ponto é para a esquerda 5 e para a frente 2. Então, viramos à esquerda.