04-06-2005, 07:15 PM
OK, I have never done an arcade style game before (most of my experience has been in 'practical' programming) so I am coming here on bended knees seeking advice.
Since this is my first 'arcade' game, I thought I'd do something simple. The code below should be obvious to anyone above the age of 25. :-) What I need help on is collision detection of two objects in bounded rectangles. I've seen a lot of the algorithms online for this and they are simple, but they don't seem to work for this instance because the rectangles I am working with are rotating.
My first idea was to take the object rectangle, rotate it back to the zero angle, move it to the origin, rotate all other objects by the same angle, translate them by the same amount, and then check vertices. If there is a collision, negate the move (or register a hit). This seems like it might be a little slow.
Any wise words of experience here? Is this the way to go, or is there a better way?
Since this is my first 'arcade' game, I thought I'd do something simple. The code below should be obvious to anyone above the age of 25. :-) What I need help on is collision detection of two objects in bounded rectangles. I've seen a lot of the algorithms online for this and they are simple, but they don't seem to work for this instance because the rectangles I am working with are rotating.
My first idea was to take the object rectangle, rotate it back to the zero angle, move it to the origin, rotate all other objects by the same angle, translate them by the same amount, and then check vertices. If there is a collision, negate the move (or register a hit). This seems like it might be a little slow.
Any wise words of experience here? Is this the way to go, or is there a better way?
Code:
option explicit
'$include once: "fbgfx.bi"
const kScreen_Width = 800
const kScreen_Height = 600
const TankScale = kScreen_Width / 40
const FALSE = 0
const TRUE = NOT FALSE
const Pi = 3.14159265359
const FR = 60 'target Frame Rate
const IFR = 1/FR 'inverse Frame Rate
Type Tank
tx as single 'x coord
ty as single 'y coord
ta as single 'angle
ts as single 'speed
tr as single 'turn rate
tf as byte 'has a live bullet i.e. IsFired
th as byte 'is the tank hit?
tc as integer 'tank's color
tn as integer 'tank's score
bx as single 'bullet's x
by as single 'bullet's y
ba as single 'bullet's angle
bs as single 'bullet's speed
bm as integer 'number of frames bullets live
bl as integer 'frames bullet has left
end type
declare sub DrawTank (ByRef tTank as Tank)
declare sub AdjustTank (ByRef tTank as Tank)
SCREENRES kScreen_Width,kScreen_Height, 32, 2 ,1
dim Tank1 as Tank
dim Tank2 as Tank
'Initalize Tanks
with Tank1
.tx = kScreen_Width * .75
.ty = kScreen_Height / 2
.ta = Pi
.ts = kScreen_Width/(FR*10) 'full screen in 10 seconds
.tr = 2*Pi/(FR*3) 'a full rotation every 3 seconds
.tf = FALSE
.th = FALSE
.tc = RGB(255,0,255)
.tn = 0
.bs = .ts * 2 'bullets move twice as fast as tank
.bm = FR * 2 'bullets live for approx 2 seconds
end with
with Tank2
.tx = kScreen_Width * .25
.ty = kScreen_Height / 2
.ta = 0
.ts = kScreen_Width/(FR*10) 'full screen in 10 seconds
.tr = 2*Pi/(FR*3) 'a full rotation every 3 seconds
.tf = FALSE
.th = FALSE
.tc = RGB(255,255,0)
.tn = 0
.bs = .ts * 2 'bullets move twice as fast as tank
.bm = FR * 2 'bullets live for approx 2 seconds
end with
dim m as double
dim t as double
SCREENSET 1, 0
'just to check fps
dim f as integer
f=0
m = timer
do
'to hold around 60 fps
t = timer
'tank1 controls
with Tank1
if MULTIKEY(SC_UP) then
.tx += cos(.ta) * .ts
.ty += sin(.ta) * .ts
end if
if multikey(SC_LEFT) then
.ta -= .tr
end if
if multikey(SC_RIGHT) then
.ta += .tr
end if
end with
'uhm..... well... Tank2 controls
with Tank2
if MULTIKEY(SC_W) then
.tx += cos(.ta) * .ts
.ty += sin(.ta) * .ts
end if
if multikey(SC_A) then
.ta -= .tr
end if
if multikey(SC_D) then
.ta += .tr
end if
end with
'draw screen
cls
DrawTank Tank1
DrawTank Tank2
AdjustTank Tank1
AdjustTank Tank2
SCREENCOPY
f += 1
do while t + IFR > timer: loop
LOOP WHILE NOT MULTIKEY(SC_ESCAPE)
t = f/(timer-m)
cls
? t
screencopy
do while inkey$<>"":loop
sleep
end
sub DrawTank (ByRef tTank as Tank)
'Draw the tank on a 16x16
dim P(15,1) as single
dim i as integer
dim c as single
dim s as single
dim tmpX as single
dim tmpY as single
P(0,0) = -TankScale: P(0,1) = -7/8*TankScale
P(1,0) = 5/8*TankScale: P(1,1) = -7/8*TankScale
P(2,0) = 5/8*TankScale: P(2,1) = -3/8*TankScale
P(3,0) = 3/8*TankScale: P(3,1) = -3/8*TankScale
P(4,0) = 3/8*TankScale: P(4,1) = -1/8*TankScale
P(5,0) = TankScale: P(5,1) = -1/8*TankScale
P(6,0) = TankScale: P(6,1) = 1/8*TankScale
P(7,0) = 3/8*TankScale: P(7,1) = 1/8*TankScale
P(8,0) = 3/8*TankScale: P(8,1) = 3/8*TankScale
P(9,0) = 5/8*TankScale: P(9,1) = 3/8*TankScale
P(10,0) = 5/8*TankScale: P(10,1) = 7/8*TankScale
P(11,0) = -TankScale: P(11,1) = 7/8*TankScale
P(12,0) = -TankScale: P(12,1) = 3/8*TankScale
P(13,0) = -5/8*TankScale: P(13,1) = 3/8*TankScale
P(14,0) = -5/8*TankScale: P(14,1) = -3/8*TankScale
P(15,0) = -TankScale: P(15,1) = -3/8*TankScale
c = cos(tTank.ta)
s = sin(tTank.ta)
'used lines over images because it is easier to rotate
'using an elementary matrix
for i = 0 to 15
tmpX = c*P(i,0) - s * P(i,1)
tmpY = s*P(i,0) + c * P(i,1)
P(i,0) = tmpX + tTank.tx
P(i,1) = tmpY + tTank.ty
next i
line (P(15,0),P(15,1)) - (P(0,0),P(0,1)),tTank.tc
for i = 1 to 15
line - (P(i,0),P(i,1)),tTank.tc
next i
'paint (tTank.tx,tTank.ty),tTank.tc
end sub
sub AdjustTank (ByRef tTank as Tank)
with tTank
if .tx < -TankScale then .tx = kScreen_Width + TankScale
if .tx > kScreen_Width + TankScale then .tx = -TankScale
if .ty < -TankScale then .ty = kScreen_Height + TankScale
if .ty > kScreen_Height + TankScale then .ty = -TankScale
if .ta > 2*Pi then .ta -= 2*Pi
if .ta < 0 then .ta += 2*Pi
if .tf then
if .ba > 2*Pi then .ba -= 2*Pi
if .ba < 0 then .ba += 2*Pi
end if
end with
end sub