My goal is to rotate the enemies in my game to look towards my player. The code for it looks like this:
struct Entity {
glm::vec3 Position;
glm::vec3 Scale;
glm::vec3 Rotation;
};
void turnEnemies() {
// the direction all ships look towards when spawned
glm::vec3 defaultShipForward = glm::vec3( 0.0f, 0.0f, 1.0f );
std::vector<Entity*> ships = ...;
for (int i = 0; i < ships.size(); i++) {
Entity* curShip = ships[i];
if (curShip == m_player) continue;
// I only rotate the ships around the y-axis.
// So I create a rotation matrix to rotate the ships default forward vector towards it's actual one
glm::mat4 rotationMat = glm::rotate( glm::mat4( 1.0f ), curShip->Rotation.y,
glm::vec3( 0.0f, 1.0f, 0.0f ) );
glm::vec3 curShipForward = glm::normalize(rotationMat * glm::vec4(defaultShipForward, 1.0f));
// get the vector from the current ships position toward the player
glm::vec3 vecToPlayer = glm::normalize( m_player->Position - ships[i]->Position );
float turnAngle = getAngleBetweenVectorsDeg( curShipForward, vecToPlayer );
ships[i]->Rotation.y += turnAngle;
}
}
I implemented the following variants I found online for calculating the angle:
float getAngleBetweenVectorsDeg( glm::vec3 _vec1, glm::vec3 _vec2 ) {
return acos( glm::dot( _vec1, _vec2 ) );
}
float getAngleBetweenVectorsDeg( glm::vec3 _vec1, glm::vec3 _vec2 ) {
return atan2( glm::length( glm::cross( _vec1, _vec2 ) ), glm::dot( _vec1, _vec2 ) );
}
With the acos solution, the rotation becomes undefined. The atan results in weird rotations, where one enemy rotates when the player moves forwards, the other when he moves backwards.