-----------------------------------
The_Bean
Tue Mar 25, 2008 9:12 pm
[Tutorial] "Perfect" 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