5SD033 Missile Tracking and Rotation

This week’s post will detail how I, with the help of Adrian Hedqvist, created a new projectile that tracks enemies and changes rotation based on target position.  To get an idea of how positions work in our game, read http://tollyx.net/game/2016/02/10/moving-in-circles.html for details on player position.

Problem Tracking

One of the game’s powerups is a heat-seeking missile, intended to track the nearest enemy and strike them without any need for aiming from the player, beyond positioning. Current projectile objects are created by taking the player’s current position and rotation of their firing barrel in degrees,  with 90 degrees added to the projectile’s rotation so the projectile does not appear on its side when fired. It would then move each time the game updated in the direction it had been rotated, until it either hit an enemy or moved offscreen.

To create a tracking missile, I would need to make a new object that inherited the properties of said projectile (a rotation, a speed, an effect when hit) and locate  which enemy is the closest to the firing position. It would also need to properly rotate the new projectile’s sprite to “aim” towards the enemy.

Missile Commands

Adrian had already created a function within  our enemy manager that tracked the nearest enemy, by utilizing trigonometry. Specifically, finding the distance between two positions drawn directly between the two points, via tangents (and utilizing functions within the math.h library).

296px-Trigonometric_functions_and_inverse2.svg

Where 1 is the length between the x positions, x is the length between the y, and the square root of the two positions multiplied then added to each other is the distance. We have vectors holding each current object of enemy ships, which we iterate through checking these distances.

 


    auto it = vecPtrEnemyShip.begin();
    while (it != vecPtrEnemyShip.end())
    {
        sf::Vector2f enPos = (*it)->getPosition();
        sf::Vector2f deltaPos = pos - enPos;
        float distance = sqrt(deltaPos.x * deltaPos.x + deltaPos.y * deltaPos.y);

        if (closestDist >= distance)
        {
            closestDist = distance;
            closest = (*it);
        }

        ++it;

Angle tangle

But now that we knew what the closest ship was, how did I aim the already fired projectiles towards them, have them move where they needed to, and continue updating that direction when the enemy ship moved?

The answer was simple (after some more hints by Adrian). He had already created a turret class that needed to rotate as it fired towards targets, though their projectiles did not track the enemy. All that was needed was to continue using tangents, though specifically the inverse arctan, to acquire the angle from the last positions we had checked between the projectile and the enemy.

float deltaX = getPosition().x - enemyship->getPosition().x;
float deltaY = getPosition().y - enemyship->getPosition().y;
setRotation(atan2(deltaY, deltaX) * 180 / M_PI +180);
projectileSprite.setRotation(getRotation() + 90);

 

The arctan result is then multiplied in the above code, by 180 divided by Pi, plus 180. This is because the arctan function does not provide results in degrees, but gradiants. This new rotation is then added to by 90 once actually entered into sprite’s position data before all drawing on screen is updated. The reason for the addition is that SFML starts counting angles from the upper portion of a circle (what would be 90 degrees) , instead of the side (0).

The new rotation of the sprite is updated every time the missile is, ensuring the missile always points towards its target.

 

 

About Karl Malm

2015 Programming