3D block engine

Here is a little 3D block engine I made, thanks @Ignatz for your excellent tutorial explaining the basic principles of 3D.


--# Main
-- 3D
displayMode(OVERLAY)

function setup()
    Zangle = 0
    FieldOfView=45
    CamHeight=300
    Angle=0
    blocktypes={"Planet Cute:Stone Block","Planet Cute:Dirt Block","Planet Cute:Grass Block"}
    blocks = {}
    worldwidth = 20
    worldlength = 20
    worldheight = 5
    for x = 1, worldwidth do
        blocks[x]={}
        for y = 1, worldlength do
            blocks[x][y]={}
            maxheight = math.random(worldheight-3,worldheight)
            for z = 1,maxheight do
                if z == maxheight and maxheight > 2 then
                    createblock(x,y,z,3)
                    -- grass
                elseif z == 1 then
                    createblock(x,y,z,1)
                    -- stone
                else
                    createblock(x,y,z,2)
                    -- dirt
                end
            end
        end
    end

    ground = Floor(-101,-51,-101,
    (worldwidth+1)*101,(worldlength+1)*101,"SpaceCute:Background")
    camX,camY,camZ, camfocusX,camfocusY,camfocusZ = 0,(worldheight+10)*101,0,0,0,0
    parameter.watch("FPS")
    --[[
    parameter.integer("camX",-worldwidth*101 ,worldwidth*101,0)
    parameter.integer("camZ",-worldlength*101,worldlength*101,0)
    --]]
    print("Swipe to look around.")
end

function draw()
    FPS=1/DeltaTime
    background(0)
    perspective(FieldOfView, WIDTH/HEIGHT)
    camera(camX,camY,camZ, camfocusX, camfocusY, camfocusZ, 1, 0,0)
    -- pushMatrix()        
    for x =1, #blocks do
        for y =1, #blocks[x] do
            for z =1, #blocks[x][y] do
                blocks[x][y][z]:draw()
            end
        end
    end
    ground:draw()
end

function touched(touch)
    camX = camX - touch.deltaY *4
    camZ = camZ - touch.deltaX *4
end

function createblock(x,y,z,t)
    blocks[x][y][z] = 
    Block(100.1*(x-worldwidth/2-1.5),100.1*(z-1),100.1*(y-worldlength/2-1.5),
    100,100,100,blocktypes[t],
    {0.03,0.24,0.97,0.69})
end







--# Block
Block = class()

function Block:init(x,y,z,w,h,d,t,r,o)
    self.x = x
    self.y = y
    self.z = z
    self.width = w -- width
    self.height = h -- height
    self.depth = d -- depth
    self.texture = t
    self.texR = r or {0,0,1,1}
    self.opacity = o or 255
    self.block = self:createblock()
    
end

function Block:createblock()
    local w,h,d = self.width,self.height,self.depth
    -- right = +
    -- up = +
    -- front = +
    --table of the verticies of a cube
    --x ,y, z
    local v = 
    {
    vec3(-0.5*w +self.x,-0.5*h +self.y,0.5*d +self.z), -- left  bottom front --+
    vec3(0.5*w +self.x,-0.5*h +self.y,0.5*d +self.z), --  right bottom front +-+
    vec3(0.5*w +self.x,0.5*h +self.y,0.5*d +self.z), --   right top    front +++
    vec3(-0.5*w +self.x,0.5*h +self.y,0.5*d +self.z), --  left  top    front -++
    
    vec3(-0.5*w +self.x,-0.5*h +self.y,-0.5*d +self.z), --left  bottom back  ---
    vec3(0.5*w +self.x,-0.5*h +self.y,-0.5*d +self.z), -- right bottom back  +--
    vec3(0.5*w +self.x,0.5*h +self.y,-0.5*d +self.z), --  right top    back  ++-
    vec3(-0.5*w +self.x,0.5*h +self.y,-0.5*d +self.z), -- left  top    back  -+-
    }
    
    local cubeverts =
    {
    -- front face
      v[1], v[2], v[3], v[1], v[3], v[4],
    
    -- right face
      v[2], v[6], v[7], v[2], v[7], v[3],
    
    -- back face
      v[6], v[5], v[8], v[6], v[8], v[7],
    
    -- left face
      v[5], v[1], v[4], v[5], v[4], v[8],
    
    -- top face
      v[4], v[3], v[7], v[4], v[7], v[8],
    
    -- bottom face
      v[5], v[6], v[2], v[5], v[2], v[1],   
    }
    
    
    local BL=vec2(self.texR[1],self.texR[2]) --bottom left
    local BR=vec2(self.texR[3],self.texR[2]) --bottom right  
    local TR=vec2(self.texR[3],self.texR[4]) --top right
    local TL=vec2(self.texR[1],self.texR[4]) --top left
    
    
    local cubetexCoords = {}
    for i=1,6 do
        table.insert(cubetexCoords,BL)
        table.insert(cubetexCoords,BR)
        table.insert(cubetexCoords,TR)
        table.insert(cubetexCoords,BL)
        table.insert(cubetexCoords,TR)
        table.insert(cubetexCoords,TL)
    end

    local ms = mesh()
    ms.vertices = cubeverts
    
    ms.texture = self.texture
    ms.texCoords = cubetexCoords
    ms:setColors(255,255,255,self.opacity)    
    return ms
end

function Block:draw()
    self.block:draw()
end



--# Floor
Floor = class()

function Floor:init(x,y,z,w,l,t)
    self.x = x
    self.y = y
    self.z = z
    self.width = w --x axis
    self.length = l --z axis
    self.texture = t
    self.floor = self:createfloor()
end

function Floor:draw()
    self.floor:draw()
end

function Floor:createfloor()
    local x,y,z,w,l = self.x,self.y,self.z,self.width,self.length
    local v = 
    {
    vec3(x +0.5*w, y, z+0.5*l), --right front
    vec3(x +-0.5*w, y,z+0.5*l), --left front
    vec3(x +0.5*w, y, z+-0.5*l), -- right back
    vec3(x +-0.5*w, y, z+-0.5*l) -- left back
    }
    local floorverts = --mesh is split from left front to right back
    {
    v[2],v[1],v[3],
    v[2],v[4],v[3]
    }
    
    local tcoords = 
    {
    vec2(0,0),
    vec2(1,0),
    vec2(1,1),
    vec2(0,0),
    vec2(0,1),
    vec2(1,1)
    }
    
    local r,g = color(255,0,0),color(0,255,0)
    
    local floormesh = mesh()
    floormesh.vertices =floorverts
    floormesh:setColors(255,255,255,255)
    floormesh.texture =self.texture
    floormesh.texCoords = tcoords
    return floormesh
end

Very nice job!

@Zoyt thanks

@Coder nice! And now… shadows?

could something like maincraft be done in codea? I ask because the fps is already at 30… but maybe there are sone tricks to optimize. worth to try, isnt it? :slight_smile:

Terraria maybe, it seems like there’s an FPS issue in MCPE as is, I don’t think there’s enough techno-sorcery here to make something of that scale work in codea. Then again, I’ve been surprised by the ingenuity (and crazy optimization tricks) of the codea user-base before, so I’m probably 100% wrong XD

I could make it faster by using one mesh for all the blocks rather than one mesh for each block.