I couldn't resist to sit down with paper and pencil to analyze the problem from a mathematical point of view (my engineer soul calling), and when I solved it I coded the small demo attached here:
Code: Select all
option explicit
#include "fbgfx.bi"
#define SCR_W 640
#define SCR_H 480
#define SCR_B 16
const BULLET_SPEED as single = 3.7
const PLAYER_SPEED as single = 2.4
const PLAYER_ACCEL as single = 0.15
type OBJECT
active as integer
x as single
y as single
vx as single
vy as single
end type
declare function get_fire_angle(byval src as OBJECT ptr, byval dest as OBJECT ptr, byval speed as single) as double
declare sub rest(byval t as single)
'':::::
function get_fire_angle(byval src as OBJECT ptr, byval dest as OBJECT ptr, byval speed as single) as double
dim as single t, dx, dy, delta, cosine, sine
speed *= speed
dx = dest->x - src->x
dy = dest->y - src->y
delta = (speed * ((dx * dx) + (dy * dy))) - (((dest->vx * dy) - (dest->vy * dx)) * ((dest->vx * dy) - (dest->vy * dx)))
t = -(dest->vx * dx) - (dest->vy * dy) - sqr(delta)
t /= ((dest->vx * dest->vx) + (dest->vy * dest->vy) - speed)
cosine = dx + (dest->vx * t)
sine = dy + (dest->vy * t)
function = atan2(-sine, cosine)
end function
'':::::
sub rest(byval t as single)
dim as single start
start = timer
while timer < start + t: wend
end sub
'':::::
dim as OBJECT turret, bullet, player
dim as integer page
dim as single angle
screenres SCR_W, SCR_H, SCR_B, 2
randomize(timer)
player.x = rnd*SCR_W
player.y = rnd*SCR_H
turret.x = SCR_W / 2
turret.y = SCR_H / 2
do
screenset page, page xor 1
page xor= 1
cls
circle(player.x, player.y), 4, rgb(255, 255, 255),,, 1, F
circle(turret.x, turret.y), 4, rgb(255, 128, 0),,, 1, F
if (bullet.active) then
circle(bullet.x, bullet.y), 4, rgb(255, 0, 0),,, 1, F
bullet.x += bullet.vx
bullet.y += bullet.vy
end if
if (multikey(SC_LEFT) and (player.vx > -PLAYER_SPEED)) then player.vx -= PLAYER_ACCEL
if (multikey(SC_RIGHT) and (player.vx < PLAYER_SPEED)) then player.vx += PLAYER_ACCEL
if (multikey(SC_UP) and (player.vy > -PLAYER_SPEED)) then player.vy -= PLAYER_ACCEL
if (multikey(SC_DOWN) and (player.vy < PLAYER_SPEED)) then player.vy += PLAYER_ACCEL
player.x += player.vx
player.y += player.vy
rest 0.02
angle = get_fire_angle(@turret, @player, BULLET_SPEED)
line(turret.x, turret.y)-(turret.x + (cos(angle) * SCR_W), turret.y - (sin(angle) * SCR_W)), rgb(128, 0, 0)
if (multikey(SC_SPACE)) then
bullet.x = turret.x
bullet.y = turret.y
bullet.vx = cos(angle) * BULLET_SPEED
bullet.vy = -sin(angle) * BULLET_SPEED
bullet.active = 1
end if
loop while not multikey(SC_ESCAPE)
The get_fire_angle() function always succeeds as long as the bullet speed is always higher than the player speed (it would not make sense anyway in this case as if the bullet is slower than the player it can never catch him)
Hope you can make good use of this code :)
Now I'm going back to my thesis...
EDIT: optimized and cleaned up code a bit