Skip to content

213. Turning to face an object in 2D

May 16, 2015

Something like this question came up on the Codea forum. If you are at (x1,y1), and an object (perhaps an enemy) is at (x2,y2), how do you figure out how to rotate a sprite to face that object? What if your sprite is drawn sideways to start with?

You could start with trigonometry, but there is a function built into Codea to calculate this for you.

To do this, we need to put the positions into vec2, eg

OurPos = vec2(x1,y1)
EnemyPos = vec2(x2,y2)

Then we can calculate the angle between them with

angle=math.deg(vec2(0,1):angleBetween(EnemyPos-OurPos))

There is a full code example at the bottom if you’d like to try it, but here is the explanation.

How it works

We are at the point OurPos, and want to rotate to face EnemyPos.

We start by calculating which direction we want to look, by subtracting OurPos from EnemyPos (ie telling us which way we have to move from OurPos to get to enemyPos).

Now we need to turn that direction into a rotation in degrees.

Before we can do that, we need to know which way we are facing before rotating. If we are rotating a sprite that has been drawn facing up the screen, then it is facing the direction (0,1) [I could have written this as (0,3), (0,1.65) etc, all that matters is that x=0 and y is positive, which tells us the direction points vertically up the screen].

So we want to rotate from a direction of (0,1) to a direction equal to the difference between OurPos and enemyPos. And this is exactly what the angleBetween function does, as shown in the formula at the top, and in the code example below. Note we have to convert to degrees afterwards, because angleBetween produces an answer in radians.

What is really nice is that it works for all angles from 0 to 360 without any adjustment, and it allows for the fact that positive rotations are anti clockwise in Codea.

Allowing for different sprite angles

This works for sprites which are drawn facing up the screen. But suppose you have a sprite which is drawn facing to the right? You can handle this a couple of ways. One is to simply add 90 degrees to the formula above, so it rotates the sprite to face up the screen before doing the calculations. Or you can realise that your sprite drawing is facing in the direction (1,0), ie towards +x, and alter the formula at top to

angle=math.deg(vec2(1,0):angleBetween(EnemyPos-OurPos))

So it is quite easy to allow for different starting angles for your sprite.

Code example

A red dot moves across the screen at the top, and the spaceship turns to face it. Touch the screen to change the position of the spaceship.

function setup()
    --make the enemy move left and right at top of screen
    enemy=vec2(100,HEIGHT-100)
    tween(10,enemy,{x=WIDTH-100,HEIGHT-50},
         { easing = tween.easing.linear,loop = tween.loop.pingpong })
    pos=vec2(300,200) --our starting position
end

function draw()
    background(50)
    fill(255,0,0)
    ellipse(enemy.x,enemy.y,50) --draw enemy
    --calculate angle to enemy
    local a=math.deg(vec2(0,1):angleBetween(enemy-pos))
    --draw ourselves as a spaceship
    translate(pos.x,pos.y)
    rotate(a)
    sprite("Space Art:Red Ship",0,0)
end

--touch anywhere on screen to change our own position
function touched(t)
    pos=vec2(t.x,t.y)
end

From → Programming

One Comment

Trackbacks & Pingbacks

  1. Index of posts | coolcodea

Leave a comment