Thought i should post this, ive only spent a day on it but im already quite happy with the results
None of graphics have been done yet, im proceeding onto them now, and hence i want to post this before putting my own stamp on it, and without textures etc
It requires LuaPlayer Euphoria
also it can be heavily optimise, but its already producing fairly large maps, although other things still need added such as ai etc
things such as recalculating values can be cleaned out
also im only currently culling inside large blocks with integer heights,
im added a quick map randomiser, so you can tweak the size yourself
ive also included a map i created myself, which can be used to see the steps etc
Oh btw theres some bad clipping, (famous on the psp)
ive tried tessellating the blocks, but theres was improvement
A fews things im still wondering about is
lighting
(doubt if GLSL [shaders], are supported)
the for loops for generating the cubes, currently if its not integers, i have to do a second check to ensure any remainder is done,
is there a better method
also i heard you should only set the perspective when you need to, ie outside loops (this is from a c/c++ tutorial), but all lua examples i see it inside the loop?
heres the link
http://www.ghoti.nl/PSPtutorial1.php
he also says he has a way to fix clipping of large triangles, but doesnt reveal it. But the GOW devs said the method they found best was just to tessellate it
finally just a note, this is just educational for me, i doubt if it will be turned into a game, although im aiming towards it
i already have a script which exports 3d max models as an array with textures etc. so the blocky look simplistic look was a design decision, and i have a collision engine for such models. I just decided blocks as i wanted to create limits
red = Color.new(255, 0, 0)
green = Color.new(0, 255, 0)
blue = Color.new(0, 0, 255)
black = Color.new(0, 0, 0)
white = Color.new(255, 255, 255)
gray = Color.new(128, 128, 128)
cyan = Color.new(100, 255, 255)
block = Color.new(55, 65, 75)--Color.new(31, 31, 31)
topblock = Color.new(30, 35, 40)
planecol = Color.new(60, 105, 155)--Color.new(61, 61, 61)
navygreen=Color.new(95, 185, 35)
navyred=Color.new(130, 0, 45)
RAD=Gu.PI/180
Player={t={x=15,y=5,z=15},r={x=0,y=0,z=0}}
s=0.25
c=0.1
World ={
Map={
{1,1,1,1,1,1,1,1,1,1,1,1}, -- Z increas Down, X increases Right
{1,c,c,c,c,c,c,c,c,c,c,1},
{1,c,s,s*2,0,0,0,10,c,0,c,1},
{1,c,0,s*3,1,0,0,10,c,0,c,1},
{1,c,0,c,2,0,0,1,c,0,c,1},
{1,c,0,c,1,0,0,1,c,0,c,1},
{1,c,0,c,1,0,0,1,c,0,c,1},
{1,c,0,c,1,1,1,1,c,0,c,1},
{1,c,0,c,c,c,c,c,c,0,c,1},
{1,c,0,0,0,0,0,0,0,0,c,1},
{1,c,c,c,c,c,c,c,c,c,c,1},
{1,1,1,1,1,1,1,1,1,1,1,1}
}
}
--- Comment out between here and
World.Map={}
for y=1,10 do
World.Map[y]={}
for x=1,10 do
ht=math.random(0,15)-10
if ht<0 then ht=0 end
World.Map[y][x]=ht
end
end
--- here, for some stairway action
World.h=table.getn(World.Map)
World.w=table.getn(World.Map[1])
World.ts=5
function DrawCube(col, w,h,d, col2,tu,tr,td,tl)
if not col2 then local col2=col end
obj = {
-- Top Face
{topblock, w, h*World.ts, d},
{topblock, 0, h*World.ts, d},
{topblock, 0, h*World.ts, 0},
{topblock, 0, h*World.ts, 0},
{topblock, w, h*World.ts, 0},
{topblock, w, h*World.ts, d}
}
tu=math.floor(tu);td=math.floor(td);tl=math.floor(tl);tr=math.floor(tr)
for y=tu,h do
y=y*World.ts
-- Front Face
table.insert(obj, {col2, 0, y-World.ts, 0})
table.insert(obj, {col2, w, y-World.ts, 0})
table.insert(obj, {col, w, y, 0})
table.insert(obj, {col, w, y, 0})
table.insert(obj, {col, 0, y, 0})
table.insert(obj, {col2, 0, y-World.ts, 0})
end
for y=tl,h do
y=y*World.ts
-- Left Face
table.insert(obj, {col2, 0, y-World.ts, 0})
table.insert(obj, {col, 0, y, 0})
table.insert(obj, {col, 0, y, d})
table.insert(obj, {col, 0, y, d})
table.insert(obj, {col2, 0, y-World.ts, d})
table.insert(obj, {col2, 0, y-World.ts, 0})
end
for y=td,h do
y=y*World.ts
-- Back Face
table.insert(obj, {col, w, y, d})
table.insert(obj, {col2, w, y-World.ts, d})
table.insert(obj, {col2, 0, y-World.ts, d})
table.insert(obj, {col2, 0, y-World.ts, d})
table.insert(obj, {col, 0, y, d})
table.insert(obj, {col, w, y, d})
end
for y=tr,h do
y=y*World.ts
-- Right Face
table.insert(obj, {col, w, y, d})
table.insert(obj, {col, w, y, 0})
table.insert(obj, {col2, w, y-World.ts, 0})
table.insert(obj, {col2, w, y-World.ts, 0})
table.insert(obj, {col2, w, y-World.ts, d})
table.insert(obj, {col, w, y, d})
end
-- fixes remaider of tile if not interger
if h ~= math.floor(h) then
y=math.floor(h)*World.ts
rem=h*World.ts-y
-- Front Face
table.insert(obj, {col2, 0, y, 0})
table.insert(obj, {col2, w, y, 0})
table.insert(obj, {col, w, y+rem, 0})
table.insert(obj, {col, w, y+rem, 0})
table.insert(obj, {col, 0, y+rem, 0})
table.insert(obj, {col2, 0, y, 0})
-- Left Face
table.insert(obj, {col2, 0, y, 0})
table.insert(obj, {col, 0, y+rem, 0})
table.insert(obj, {col, 0, y+rem, d})
table.insert(obj, {col, 0, y+rem, d})
table.insert(obj, {col2, 0, y, d})
table.insert(obj, {col2, 0, y, 0})
-- Back Face
table.insert(obj, {col, w, y+rem, d})
table.insert(obj, {col2, w, y, d})
table.insert(obj, {col2, 0, y, d})
table.insert(obj, {col2, 0, y, d})
table.insert(obj, {col, 0, y+rem, d})
table.insert(obj, {col, w, y+rem, d})
-- Right Face
table.insert(obj, {col, w, y+rem, d})
table.insert(obj, {col, w, y+rem, 0})
table.insert(obj, {col2, w, 0, 0})
table.insert(obj, {col2, w, y, 0})
table.insert(obj, {col2, w, y, d})
table.insert(obj, {col, w, y+rem, d})
end
-- Bottom Face
--{col, 0, 0, 0},
--{col, 0, 0, d},
--{col, w, 0, d},
--{col, w, 0, d},
--{col, w, 0, 0},
--{col, 0, 0, 0},
------------------------------------------------------------ Now starts at top back right instead of bottom front left
return obj
end
function RetT(pt)
return math.floor(pt/World.ts)
end
function Collide(x,z)
if World.Map[RetT(z-1)][RetT(x+1)]*World.ts > Player.t.y+2 or
World.Map[RetT(z+1)][RetT(x+1)]*World.ts > Player.t.y+2 or
World.Map[RetT(z-1)][RetT(x-1)]*World.ts > Player.t.y+2 or
World.Map[RetT(z+1)][RetT(x-1)]*World.ts > Player.t.y+2 then return true end
end
function MovePlayer()
local rad=Player.r.y*RAD
local Zmov=math.cos(rad)
local Xmov=-math.sin(rad)
Player.flr=math.max(World.Map[RetT(Player.t.z-1)][RetT(Player.t.x-1)],World.Map[RetT(Player.t.z-1)][RetT(Player.t.x+1)],World.Map[RetT(Player.t.z+1)][RetT(Player.t.x+1)],World.Map[RetT(Player.t.z+1)][RetT(Player.t.x-1)])
if pad:up() then
if not Collide(Player.t.x, Player.t.z-Zmov) then Player.t.z = Player.t.z-Zmov end
if not Collide(Player.t.x-Xmov, Player.t.z) then Player.t.x = Player.t.x-Xmov end
elseif pad:down() then
if not Collide(Player.t.x, Player.t.z+Zmov) then Player.t.z = Player.t.z+Zmov end
if not Collide(Player.t.x+Xmov, Player.t.z) then Player.t.x = Player.t.x+Xmov end
end
if pad:left() then
if not Collide(Player.t.x, Player.t.z+Xmov) then Player.t.z = Player.t.z+Xmov end
if not Collide(Player.t.x-Zmov, Player.t.z) then Player.t.x = Player.t.x-Zmov end
elseif pad:right() then
if not Collide(Player.t.x, Player.t.z-Xmov) then Player.t.z = Player.t.z-Xmov end
if not Collide(Player.t.x+Zmov, Player.t.z) then Player.t.x = Player.t.x+Zmov end
end
--if pad:r() then Player.t.y=Player.t.y+1
--elseif pad:l() then Player.t.y=Player.t.y-1 end
if pad:l() and Player.t.y == Player.flr*World.ts then Player.t.y=Player.t.y+World.ts+1 end
if Player.t.y > Player.flr*World.ts then Player.t.y=Player.t.y-1 else Player.t.y = Player.flr*World.ts end
if pad:square() then Player.r.y=Player.r.y-5 end
if pad:circle() then Player.r.y=Player.r.y+5 end
if Player.r.y >= 360 then Player.r.y = 0 elseif Player.r.y < 0 then Player.r.y = 360+Player.r.y end
if pad:triangle() then Player.r.x=Player.r.x-5 end
if pad:cross() then Player.r.x=Player.r.x+5 end
if Player.r.x >= 50 then Player.r.x = 50 elseif Player.r.x < -50 then Player.r.x = -50 end
end
Scene={}
plane={}
for x=1,World.w do
for y=1,World.h do
table.insert(plane, {planecol, (x+1)*World.ts,0,(y+1)*World.ts})
table.insert(plane, {planecol, x*World.ts,0,(y+1)*World.ts})
table.insert(plane, {planecol, x*World.ts,0,y*World.ts})
table.insert(plane, {planecol, x*World.ts,0,y*World.ts})
table.insert(plane, {planecol, (x+1)*World.ts,0,y*World.ts})
table.insert(plane, {planecol, (x+1)*World.ts,0,(y+1)*World.ts})
end
end
for x=1,World.w do
for z=1,World.h do
if World.Map[z][x] > 0 then
if World.Map[z-1] then tu =World.Map[z-1][x] else tu =0 end
if World.Map[z+1] then td =World.Map[z+1][x] else td =0 end
if World.Map[z][x+1] then tr =World.Map[z][x+1] else tr =0 end
if World.Map[z][x-1] then tl =World.Map[z][x-1] else tl =0 end
--print(tu,td,tr,tl)
table.insert(Scene, {x*World.ts,z*World.ts,DrawCube(block, World.ts,World.Map[z][x],World.ts, black, tu,tr,td,tl)})
end
end
end
--check scene size
verts=0
for s=1,table.getn(Scene) do
verts=verts+table.getn(Scene[s][3])
end
print(verts)
while true do
pad = Controls.read()
MovePlayer()
Gu.start3d()
-- clear screen
Gu.clearDepth(0);
Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT)
-- setup projection and view matrices
Gum.matrixMode(Gu.PROJECTION)
Gum.loadIdentity()
Gum.perspective(75, 16/9, 1, 100)
--transform world
Gum.matrixMode(Gu.VIEW)
Gum.loadIdentity()
Gum.rotateXYZ(Player.r.x*RAD, Player.r.y*RAD, Player.r.z*RAD);
Gum.translate(-Player.t.x,-Player.t.y-5,-Player.t.z)
-- setup matrix for cube
Gum.matrixMode(Gu.MODEL)
Gum.loadIdentity()
Gu.disable(Gu.TEXTURE_2D)
Gum.drawArray(Gu.TRIANGLES, Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_3D, plane)
for s=1,table.getn(Scene) do
Gum.translate(Scene[s][1],0,Scene[s][2])
Gum.drawArray(Gu.TRIANGLES, Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_3D, Scene[s][3])
Gum.translate(-Scene[s][1],0,-Scene[s][2])
end
Gu.end3d()
Player.t.old={x=Player.t.x,y=Player.t.y,z=Player.t.z}
if Controls.read():start() then
break
end
screen:clear()
screen.waitVblankStart()
screen.flip()
end