1369
« on: December 28, 2006 »
Okay this is something I've been at for a while now and I think I'm finally on to something,
Originally my 3D engines where a marriage between the old familiar WORMS demo and the 3D CUBE demo that were included in the PS2 yabasic. Basically the collision map (grid(x, y) in the WORMS demo) held the centre point for the cube which was replotted and redrawn for each grid entry that was considered a wall. That technique yielded some results (25 fps on the PS2 when the grid was a 16x16 array). The were however some short-commings with this approach. The cubes often vanished when you stood with your shoulder to the wall such that your line of sight was paralelle with the wall, this left half the screen taken up with the background when surely there should have been a wall.
This time I have opted for a different approach. The collision map is only used for detecting collisions and a polygon mesh is used to define the rooms appearance. It was necessary to weed out the non visible walls. To achieve this I calculated the crossproduct of each point relative to both the left extreme of vision and the right extreme of vision. Any wall which had one point within the field of view and one point outside the FOV would have to be cropped. Now we cast out two rays (one for each extreme of vision) & calculate the intersection points. Up to now everything is done in 2D. All that is left is to rotate whats the scene, add a vertical dimension and apply perspective.
I haven't yet checked out the fps for this algorithm but it doesn't suffer any slowdown (at least not noticeably). I still have to sort out a bug in the lighting effects and everything still has to be cleaned up a lot. But it works... Now where do I go from here?
init_game()
label game
draw_grid(grid)
ctrl = peek("port1")
if (ctrl <> 0) ctrl_user(ctrl)
goto game
sub draw_grid(grid) local x, y, w
if (intro <= 3) then
setrgb 1, 255, 255, 000
text 0,240, message$(intro), "cc"
count = count + 1
if (count > display) then
count = 0
intro = intro + 1
fi
fi
setdispbuf draw
draw = 1 - draw
setdrawbuf draw
horizon =-256*tn(rotx(0))*2
setrgb 1, 255,255,255
setrgb 2, 255,255,255
setrgb 3, 000,000,000
gtriangle -320,-256 to 320,-256 to 320,horizon
setrgb 2, 000,000,000
gtriangle -320,-256 to -320,horizon to 320,horizon
setrgb 1, 255,000,000
setrgb 2, 255,000,000
setrgb 3, 000,000,000
gtriangle -320,256 to 320,256 to 320,horizon
setrgb 2, 000,000,000
gtriangle -320,256 to -320,horizon to 320,horizon
for w = 1 to walls
if (tz(w,1) > 0) and (tz(w,3) > 0) then
lt1 = lt1(w)
lt2 = lt2(w)
setrgb 1, red(w)*lt1, grn(w)*lt1, blu(w)*lt1
setrgb 2, red(w)*lt1, grn(w)*lt1, blu(w)*lt1
setrgb 3, red(w)*lt2, grn(w)*lt2, blu(w)*lt2
gtriangle tx(w,1),ty(w,1) to tx(w,2),ty(w,2) to tx(w,3),ty(w,3)
setrgb 2, red(w)*lt2, grn(w)*lt2, blu(w)*lt2
gtriangle tx(w,1),ty(w,1) to tx(w,4),ty(w,4) to tx(w,3),ty(w,3)
fi
next
for y = 1 to gridy
for x = 0 to gridx
if (grid(x, y) <> 0) then
if (grid(x, y) = wall) then setrgb 1, 100, 100, 100
elsif (grid(x, y) = door) then setrgb 1, 200, 120, 080
fi
fill box x*m-300, y*m-240 to x*m+m-300, y*m+m-240
fi
next
next
setrgb 1, 000,000,255
fill circle posx(0)*m-300, posy(0)*m-240, m/2
end sub
sub rota_grid()
cx = -cs(rotx(0))
sx = -sn(rotx(0))
cy = -cs(roty(0))
sy = -sn(roty(0))
cz = -ct(rotz(0))
sz = -tn(rotz(0))
posx = posx(0)*m
posy = posy(0)*m
posz = posz(0)*m
for w = 1 to walls
px = ix1(w)*m-posx
py = iy1(w)*m-posy
pz =-m/2-posz
nx = cz*px + sz*py
ny = cz*py - sz*px
nz = cy*pz + sy*nx
tx = cy*nx - sy*pz
ty = cx*ny + sx*nz
tz = cx*nz - sx*ny
tx(w,1) = tx*400/ tz
ty(w,1) = ty*400/ tz
tz(w,1) = tz
pz = m/2-posz
nz = cy*pz + sy*nx
tx = cy*nx - sy*pz
ty = cx*ny + sx*nz
tz = cx*nz - sx*ny
tx(w,2) = tx*400/ tz
ty(w,2) = ty*400/ tz
tz(w,2) = tz
px = ix2(w)*m-posx
py = iy2(w)*m-posy
pz = m/2-posz
nx = cz*px + sz*py
ny = cz*py - sz*px
nz = cy*pz + sy*nx
tx = cy*nx - sy*pz
ty = cx*ny + sx*nz
tz = cx*nz - sx*ny
tx(w,3) = tx*400/ tz
ty(w,3) = ty*400/ tz
tz(w,3) = tz
pz =-m/2-posz
nz = cy*pz + sy*nx
tx = cy*nx - sy*pz
ty = cx*ny + sx*nz
tz = cx*nz - sx*ny
tx(w,4) = tx*400/ tz
ty(w,4) = ty*400/ tz
tz(w,4) = tz
next
end sub
sub cast_rays()
leftz = rotz(0) - 32 : if (leftz < 000) leftz = leftz + 255
rigtz = rotz(0) + 32 : if (rigtz > 255) rigtz = rigtz - 255
posx = posx(0)
posy = posy(0)
cs_lz = cs(leftz)
sn_lz = sn(leftz)
cs_rz = cs(rigtz)
sn_rz = sn(rigtz)
cslz = cs(leftz) + posx
snlz = sn(leftz) + posy
csrz = cs(rigtz) + posx
snrz = sn(rigtz) + posy
for w = 1 to walls
cp1(w) = 0
cp1 = (posx-wx1(w))*(snlz-wy1(w)) - (cslz-wx1(w))*(posy-wy1(w))
if (cp1 > 0) then
cp2 = (posx-wx1(w))*(snrz-wy1(w)) - (csrz-wx1(w))*(posy-wy1(w))
if (cp2 < 0) then
cp1(w) = 1
ix1(w) = wx1(w)
iy1(w) = wy1(w)
fi
fi
cp2(w) = 0
cp1 = (posx-wx2(w))*(snlz-wy2(w)) - (cslz-wx2(w))*(posy-wy2(w))
if (cp1 > 0) then
cp2 = (posx-wx2(w))*(snrz-wy2(w)) - (csrz-wx2(w))*(posy-wy2(w))
if (cp2 < 0) then
cp2(w) = 1
ix2(w) = wx2(w)
iy2(w) = wy2(w)
fi
fi
if (cp1(w) = 0) then
if (wx1(w) = wx2(w)) then
opp = wx1(w) - posx
adj = opp/cs_lz*sn_lz + posy
if (adj > wy1(w)) and (adj < wy2(w)) then
ix1(w) = wx1(w)
iy1(w) = adj
elsif (adj < wy1(w)) and (adj > wy2(w)) then
ix1(w) = wx1(w)
iy1(w) = adj
fi
elsif (wy1(w) = wy2(w)) then
adj = wy1(w) - posy
opp = adj/sn_lz*cs_lz + posx
if (opp > wx1(w)) and (opp < wx2(w)) then
ix1(w) = opp
iy1(w) = wy1(w)
elsif (opp < wx1(w)) and (opp > wx2(w)) then
ix1(w) = opp
iy1(w) = wy1(w)
fi
fi
fi
if (cp2(w) = 0) then
if (wx1(w) = wx2(w)) then
opp = wx2(w) - posx
adj = opp/cs_rz*sn_rz + posy
if (adj > wy1(w)) and (adj < wy2(w)) then
ix2(w) = wx2(w)
iy2(w) = adj
elsif (adj < wy1(w)) and (adj > wy2(w)) then
ix2(w) = wx2(w)
iy2(w) = adj
fi
elsif (wy1(w) = wy2(w)) then
adj = wy2(w) - posy
opp = adj/sn_rz*cs_rz + posx
if (opp > wx1(w)) and (opp < wx2(w)) then
ix2(w) = opp
iy2(w) = wy2(w)
elsif (opp < wx1(w)) and (opp > wx2(w)) then
ix2(w) = opp
iy2(w) = wy2(w)
fi
fi
fi
for l = 1 to light
opp = ix1(w)-lx(l)
adj = iy1(w)-ly(l)
hyp1 = sqrt(sqr(opp)+sqr(adj))/lit(l)
lt1(w) = 1/hyp1 + lt1(w)
opp = ix2(w)-lx(l)
adj = iy2(w)-ly(l)
hyp2 = sqrt(sqr(opp)+sqr(adj))/lit(l)
lt2(w) = 1/hyp2 + lt2(w)
next
lt1(w) = lt1(w) / 4
lt2(w) = lt2(w) / 4
if (lt1(w) > 1) lt1(w) = 1
if (lt2(w) > 1) lt2(w) = 1
? lt1(w),lt2(w)
next
?
end sub
sub ctrl_user(ctrl) local dirx, diry, torx, torz, newx, newy
if (and(ctrl, ctrl(cr)) <> 0) then torz = 10*rpm
elsif (and(ctrl, ctrl(sq)) <> 0) then torz =-10*rpm
fi
if (and(ctrl, ctrl(tr)) <> 0) then torx = 10*rpm
elsif (and(ctrl, ctrl(ex)) <> 0) then torx =-10*rpm
fi
rotz(0) = rotz(0) + torz
if (rotz(0) < 000) then rotz(0) = rotz(0) + 255
elsif (rotz(0) > 255) then rotz(0) = rotz(0) - 255
fi
rotx(0) = rotx(0) + torx
if (rotx(0) > 128) then rotx(0) = 128
elsif (rotx(0) < 000) then rotx(0) = 000
fi
if (and(ctrl, ctrl(up)) <> 0) then
dirx = cs(rotz(0))
diry = sn(rotz(0))
elsif (and(ctrl, ctrl(dn)) <> 0) then
dirx =-cs(rotz(0))
diry =-sn(rotz(0))
fi
if (and(ctrl, ctrl(rt)) <> 0) then
dirx = ct(rotz(0)) + dirx
diry = tn(rotz(0)) + diry
elsif (and(ctrl, ctrl(lf)) <> 0) then
dirx =-ct(rotz(0)) + dirx
diry =-tn(rotz(0)) + diry
fi
dirx = dirx*mps/4
diry = diry*mps/4
newx = posx(0) + dirx
newy = posy(0) + diry
hit = grid(newx, newy)
if (hit = door) then
source = grid
grid = des(node(newx, newy))
load_grid(grid)
newx = posx(0)
newy = posy(0)
elsif (hit <> flor) then
newx = posx(0)
newy = posy(0)
fi
posx(0) = newx
posy(0) = newy
cast_rays()
rota_grid()
end sub
sub load_grid(grid) local x, y, w, g
find_grid(grid)
read gridx, gridy
redim grid(gridx, gridy), node(gridx, gridy)
for y = 1 to gridy read g
for x = 0 to gridx grid(x, y) = 0 : node(x, y) = 0
if (and(g, ctrl(x)) <> 0) grid(x, y) = wall
next
next
read doors : if (doors <> 0) load_door(doors)
read light : if (light <> 0) load_ligt(light)
read bots : if (bots <> 0) load_bots(bots)
for d = 0 to doors
if (des(d) = source) then
posx = dropx(d)
posy = dropy(d)
fi
next
posx(0) = posx + 0.5
posy(0) = posy + 0.5
read walls
redim wx1(walls), wy1(walls), wx2(walls), wy2(walls)
redim ix1(walls), iy1(walls), ix2(walls), iy2(walls)
redim red(walls), grn(walls), blu(walls)
redim lt1(walls), lt2(walls)
redim cp1(walls), cp2(walls)
redim tx(walls,4), ty(walls,4), tz(walls,4)
for w = 1 to walls read wx1(w), wy1(w), wx2(w), wy2(w) next
for w = 1 to walls read red(w), grn(w), blu(w) next
end sub
sub load_bots(bots)
end sub
sub load_door(doors) redim des(doors), dropx(doors), dropy(doors)
for d = 1 to doors read dx, dy, dropx(d), dropy(d), des(d)
grid(dx, dy) = door
node(dx, dy) = d
next
end sub
sub load_ligt(light)
redim lx(light), ly(light), lit(light)
for l = 1 to light read lx(l), ly(l), lit(l) next
end sub
sub find_grid(grid) on grid goto 01,02,03,04
01 restore grid_01 : return
02 restore grid_02 : return
03 restore grid_03 : return
04 restore grid_04 : return
end sub
sub init_game() local p, n, d, deg, degree
m = 10
km = 1000*m
secs = 50
mins = 60*secs
hour = 60*mins
mps = m/secs
kph = km/hour
rpm = 255/mins
degree = pi / 128
dim cs(255), sn(255), tn(255), ct(255)
for d = 0 to 255 deg = d*degree
cs(d) = cos(deg)
sn(d) = sin(deg)
ct(d) = cos(deg+pi/2)
tn(d) = sin(deg+pi/2)
next
dim ctrl(16)
n = 1
for p = 1 to 16 ctrl(p) = n : n = n*2 next
up = 05
rt = 06
dn = 07
lf = 08
tr = 13
cr = 14
ex = 15
sq = 16
flor = 0
wall = 1
door = 2
redim posx(1), posy(1), posz(1)
redim rotx(1), roty(1), rotz(1)
redim dropx(1), dropy(1)
dropx(0) = 8
dropy(0) = 8
grid = 01
load_grid(grid)
open window 640,512
window origin "cc"
intro = 0
count = 0
display = 8*secs
dim message$(3)
message$(0) = "Don't be afraid. Stick your chin up ..."
message$(1) = "Press [Triangle] to look up"
message$(2) = "Now step foward and claim your destiny ..."
message$(3) = "Press [D-Pad] to move around"
end sub
label grid_01
data 16,16
data 65535,32769,32769,32769,32769,32769,32769,32769
data 32769,32769,32769,32769,32769,32769,32769,65535
data 1
data 16,08,15,08,02
data 4
data 0.5,0.5,1.5, 16.5,0.5,1.5, 16.5,16.5,1.5, 0.5,16.5,1.5
data 0
data 9
data 01,01,08,01, 08,01,17,01, 17,01,17,08, 17,08,17,09
data 17,09,17,17, 17,17,08,17, 08,17,01,17, 01,17,01,08
data 01,08,01,01
data 255,255,255, 255,255,255, 255,255,255, 150,120,080
data 255,255,255, 255,255,255, 255,255,255, 255,255,255
data 255,255,255
label grid_02
data 16,16
data 65535,32769,32769,32769,32769,32769,32769,32769
data 32769,32769,32769,32769,32769,32769,32769,65535
data 2
data 01,08,02,08,01, 16,08,15,08,03
data 4
data 8.5,0.5,1.5, 16.5,8.5,1.5, 8.0,16.5,1.5, 0.5,8.5,1.5
data 0
data 10
data 01,01,08,01, 08,01,17,01, 17,01,17,08, 17,08,17,09
data 17,09,17,17, 17,17,08,17, 08,17,01,17, 01,17,01,09
data 01,09,01,08, 01,08,01,01
data 255,255,255, 255,255,255, 255,255,255, 150,120,080
data 255,255,255, 255,255,255, 255,255,255, 255,255,255
data 150,120,080, 255,255,255
label grid_03
data 16,16
data 65535,32769,32769,32769,32769,32769,32769,32769
data 32769,32769,32769,32769,32769,32769,32769,65535
data 2
data 01,08,02,08,02, 16,08,15,08,04
data 4
data 0.5,0.5,1.5, 16.5,0.5,1.5, 16.5,16.5,1.5, 0.5,16.5,1.5
data 0
data 10
data 01,01,08,01, 08,01,17,01, 17,01,17,08, 17,08,17,09
data 17,09,17,17, 17,17,08,17, 08,17,01,17, 01,17,01,09
data 01,09,01,08, 01,08,01,01
data 255,255,255, 255,255,255, 255,255,255, 150,120,080
data 255,255,255, 255,255,255, 255,255,255, 255,255,255
data 150,120,080, 255,255,255
label grid_04
data 16,16
data 65535,32769,32769,32769,32769,32769,32769,32769
data 32769,32769,32769,32769,32769,32769,32769,65535
data 1
data 01,08,02,08,03
data 4
data 8.5,0.5,1.5, 16.5,8.5,1.5, 8.0,16.5,1.5, 0.5,8.5,1.5
data 0
data 9
data 01,01,08,01, 08,01,17,01, 17,01,17,08, 17,08,17,17
data 17,17,08,17, 08,17,01,17, 01,17,01,09, 01,09,01,08
data 01,08,01,01
data 255,255,255, 255,255,255, 255,255,255, 255,255,255
data 255,255,255, 255,255,255, 255,255,255, 150,120,080
data 255,255,255