
-----------------------------------
The_Bean
Tue Mar 25, 2008 9:12 pm

[Tutorial] &quot;Perfect&quot; Following
-----------------------------------
After watching classmates make countless game where you are being chased by something and have to shoot at it, and my recent Geometry Wars game, I have decided to show you how to make those enemies follow perfectly. 

Warning: Math Ahead
It is advised to have Grade 11 academic math before attempting to understand this, but if you think you can do it, go ahead.

Part: 1 - What to get away from!

We all know how to make a ball bounce off the wall. Now people often apply the same idea in trying to get an enemy to follow you or your mouse around the screen.  This is really primitive, but in tile based games works just fine.  But we're not here to talk about those.

I find alot of people using the simple if my x position is greater then my enemies then my enemies += their speed same thing with the y and in the opposite direction. But doing this makes your enemy only able to travel: N NE E SE S SW W NW.  

This is a simple program of that:

 
View.Set ("graphics:max;max,title:Prefect Following,offscreenonly,nobuttonbar")
var xm, ym, bm : int % Mouse variables
var eTaleLength : int := 5 % length of the enemys tale
var eX, eY : array 1 .. eTaleLength of int % enemy variables
var eSpeed : int := 5 % enemy speed
var eAngle : real %enemy angle of travel
eX (eTaleLength) := Rand.Int (eTaleLength, maxx - eTaleLength) % making the enemy appear randomly
eY (eTaleLength) := Rand.Int (eTaleLength, maxy - eTaleLength)

for i : 1 .. eTaleLength - 1 % preseting the the tale to keep from getting errors
    eX (i) := eX (eTaleLength) % makes all start at the same spot
    eY (i) := eY (eTaleLength) %because hes not moving yet :)
end for

proc youLose
    put "He got you"
end youLose

loop
    cls
    Mouse.Where (xm, ym, bm)
    for i : 1 .. eTaleLength - 1 % making the tale move by making it = to the one infront of it
        eX (i) := eX (i + 1)
        eY (i) := eY (i + 1)
    end for
    
    if xm > eX (eTaleLength) then
        eX (eTaleLength) += eSpeed
    elsif xm < eX (eTaleLength) then
        eX (eTaleLength) -= eSpeed
    end if
    if ym > eY (eTaleLength) then
        eY (eTaleLength) += eSpeed
    elsif ym < eY (eTaleLength) then
        eY (eTaleLength) -= eSpeed
    end if
    
    for i : 1 .. eTaleLength % draws the tale and enemy
        Draw.FillOval (eX (i), eY (i), i, i, 7)
    end for
    View.Update
    delay (25)
    exit when hasch % prematurely exits when keyboard is hit (nice for testing)
    if Math.Distance (xm, ym, eX (eTaleLength), eY (eTaleLength)) < eTaleLength then % checks to see if he ketches you (ads a game flare to it)
        youLose %(Jordan YOU LOSE)
        exit
    end if
end loop


Now that you know what you use to be doing and what were getting away from lets get to "Perfect" Following

Part: 2 - The Math

In grade 11 math you go deeper into trig and how to use it. That is exactly what we are going to do here.

(I'm going to * as the degree symbol to make it easier and shorter for me to write)
Firstly if you noticed before the N NE E... are at 0*, 45*, 90* ... so when trying to get something to follow you perfectly it needs to travel in more degrees than just those.

We need to find the degree from your enemy to you

Since were working on the x,y plane we know that  tan Angle =y/x gives you the degree, but the problem is that the origin is in the bottom left and we need the origin to be over the enemy so he will (0,0) and your guy or mouse will be (x,y) so to do this we subtract the enemies x and y from your x and y so your coordinates compared to your enemy are 
(mouseX-enemyX,mouseY-enemyY).
so now we can use tan=y/x
now to put this in turing we need the angle on one side an everything on the other.
Angle := tan inverse y/x
and in turing 
Angle := arctand (y/x)
now putting this in a function 

 
function setAngle (x, y : real) : real
    result arctand(y/x)
end setAngle
enemyAngle := setAngle (mouseX-enemyX,mouseY-enemyY)


But we can't use this just yet!

First there are a couple other things that we need to take care of.
When x=0 meaning that you and the enemy are on the same x coordinate 
you will have y/0 and we know that you can't divide by 0 so when need to take catch that in the function.

 
function setAngle (x, y : real) : real
   if x=0 and y>0 then
      result 90
   elsif x=0 and y0 then
      result 90
   elsif x=0 and y0 and y=0 then
      result 0
   elsif x