# 3D hills

``````
--# Main
-- 3D
displayMode(OVERLAY)
displayMode(FULLSCREEN)
function setup()
noisepos = math.random(100)
noisescale=1/9
p=pinch()
touches={}
parameter.watch("lengthOf(touches)")
parameter.integer("Angle",0,360)
Zangle = 0
FieldOfView=45
-- CamHeight=300
hillHeight=math.random(4,15)
Angle=0
blocktypes={"Planet Cute:Stone Block","Planet Cute:Dirt Block",
"Planet Cute:Grass Block","Planet Cute:Water Block"}
blocks = {}
worldwidth = 15
worldlength = 15
worldheight = 5
for x = 1, worldwidth do
blocks[x]={}
for y = 1, worldlength do
blocks[x][y]={}
maxheight =
math.ceil((noise(x*noisescale+noisepos,y*noisescale+noisepos)+math.random(1))*hillHeight)
if maxheight < 1 then print(maxheight) end
--print(maxheight)
for z = 1,maxheight do

if z == maxheight then
if z < 5 then
createblock(x,y,z,4)
-- water
else
createblock(x,y,z,3)
-- grass
end
--[
--elseif z ==1  then
--createblock(x,y,z,1)
-- stone
elseif z >= maxheight-2 then
createblock(x,y,z,2)
-- dirt
--]]
--elseif x == 1 or x == worldwidth or y == worldlength or y == 1 then
-- createblock(x,y,z,2)
end

end
end
end

ground = Floor(-101,-51,-101,
(worldwidth+1)*101,(worldlength+1)*101,"SpaceCute:Background")
camX,camY,camZ, camfocusX,camfocusY,camfocusZ = -1000,(hillHeight+10)*101+100,0,0,300,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)
--camY = camY
--camY=math.max(0,camY)
perspective(FieldOfView, WIDTH/HEIGHT)
camera(camX,camY *(p.zoom /2),camZ, camfocusX, camfocusY, camfocusZ, 1, 0,0)
rotate(Angle, 0,1,0)
-- pushMatrix()
--[[
for x =1, #blocks do
for y =1, #blocks[x] do
for z =1, #blocks[x][y] do
if blocks[x][y][z] then
blocks[x][y][z]:draw()
end
end
end
end
--]]
for k,v in pairs(blocks) do
for k2,v2 in pairs(blocks[k]) do
for k3,v3 in pairs(blocks[k][k2]) do
blocks[k][k2][k3]:draw()
end
end
end
ground:draw()
p:processTouches()
end

function touched(touch)
if touch.state==ENDED then touches[touch.id]=nil else touches[touch.id]=touch end
if lengthOf(touches) == 1 then
print("1")
camX = camX - touch.deltaY *4
camZ = camZ - touch.deltaX *4
-- Angle = Angle + touch.deltaX
else

end
p:touched(touch)

end

function createblock(x,y,z,t)
blocks[x][y][z] =
Block(100.1*(x-worldwidth/2-1.5),50.1*(z-1),100.1*(y-worldlength/2-1.5),
100,50,100,blocktypes[t],
-- {0.03,0.30,0.97,0.65})
{0.1,0.4,0.9,0.65})
end

function lengthOf(t)
local l = 0
for k,v in pairs(t) do
l = l + 1
end
return l
end

pinch=class()

function pinch:init()
self.tb={} -- this table will hold touch info
self.zoom=1 --set the initial zoom
end

--this function doesn't call itself. Only the touched
--function in Main does that, but we will get that
--function to call this one, and pass the touch info across
function pinch:touched(touch)
--when touch ends, clear table and set distances to nil
if touch.state==ENDED then self.tb=nil self.tb={} self.d1=nil self.d2=nil
--if we are touching, add touch to tb, store x and y
else table.insert(self.tb,{x=touch.x,y=touch.y}) end
end

--draw in Main will call this function, to see if we
--need to pinch/zoom
function pinch:processTouches()
if #self.tb==2 and lengthOf(touches)==2 then -- continue if we had two touches
--set the two vectors for the two fingers
local v1=vec2(self.tb[1].x,self.tb[1].y)
local v2=vec2(self.tb[2].x,self.tb[2].y)
self.d1=v1:dist(v2) -- calculate the distance between
end
--if we've got a previous measurement, check if its
--changed and set the zoom
if self.d2~=nil then self.zoom=self.zoom*self.d1/self.d2 end
--store the current distance and clear the array
self.d2=self.d1
self.tb={}
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 sideBL=vec2(0.1,0.05)
local sideBR=vec2(0.99,0.05)
local sideTR=vec2(0.99,0.25)
local sideTL=vec2(0.1,0.25)

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, 4 do
table.insert(cubetexCoords,sideBL)
table.insert(cubetexCoords,sideBR)
table.insert(cubetexCoords,sideTR)
table.insert(cubetexCoords,sideBL)
table.insert(cubetexCoords,sideTR)
table.insert(cubetexCoords,sideTL)
end
for i=1,2 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 floormesh = mesh()
floormesh.vertices =floorverts
floormesh:setColors(255,255,255,255)
floormesh.texture =self.texture
floormesh.texCoords = tcoords
return floormesh
end

``````

Sorry the code is quite inefficient as it creates a mesh for every single block

The code doesnâ€™t work as is. Slap a `touches = {}` at the start of setup and it should be all good.

Sorry,that was a multitouch feature that I was trying out