# How to make a terrain?

With grass textures

Not very specific.
Do you mean in a 3D or 2D enviroment? Or perhaps even in a 2.5D env.?

And even so; do you want it to be a automatic generated terrain or a map like a game level?

This is a very big question and I am not really sure why I dived into it, but oh well I might just post this now. It’s better then nothing

@akaJag 3D environment
game level map
if you could post quickly, thanks very much

What? Do you just expect a chunk of code delivered in your lap?
Nonono, I’d say you give yourself time and learn about this so you’ll be enough experienced for doing this on your own.

Well to be true, your question was “How to make a terrain?” and to be fair I have no clue so you’ll have to wait 'til someone else answers.

@akaJag this is some of my code for the terrain and hills

```function setup()
LoadImages()
end

function setup2()
parameter.integer("Viewpoint",-2000,2000,20)
speed,angle=0,0
ds,da=0,0
posX,posY,posZ=-20,0,10 --starting position
rad=math.pi/180
meshTable={}
meshTable[1],meshTable[2]={},{}
AddLevel(-500,0,0,1000,1000,gravel,.1)
HM={} --holds height maps, one for each terrain area we build -- NEW
--add a terrain area --NEW
AddTerrain({x=-400,y=0.5,z=100,width=800,depth=800,tileSize=50,minY=10,maxY=100,random=false,
noiseLevel=.2,noiseStep=.5,img=grass,scaleFactor=.3,heightMaps=HM})
--add 200 trees
for i=1,200 do
local x=math.random(-375,375)
local z=math.random(150,750)
local w=math.random(20,60)
AddItem(x,0,z,w,tree) --rotating to face us
end
count=0
FPS=60
end

function draw()
if imageStatus~="Ready" then return end
count=count+1
background(220)
perspective(45,WIDTH/HEIGHT)
if Viewpoint<10 then Viewpoint=10 end
angle=angle+da*DeltaTime
posX,posZ=posX+ds*DeltaTime*math.sin(angle*rad),posZ+ds*DeltaTime*math.cos(angle*rad)
local h0=posY  --NEW
posY=math.max(Viewpoint,HeightAtPos(posX,posZ)+10) --NEW
local h1=posY  --NEW
--try to look up if climbing or down if descending --NEW
if posY==Viewpoint then lookY=20 else lookY=(h1-h0)*100/ds+10 end
--look in the same direction as we are facing
lookX,lookY,lookZ=posX+1000*math.sin(angle*rad),20,posZ+1000*math.cos(angle*rad)
camera(posX,posY,-posZ,lookX,lookY,-lookZ, 0,1,0)
if count%20==1 then
table.sort(meshTable[2],
function(a,b) return
vec2(posX,-posZ):dist(vec2(a.pos.x,-a.pos.z))>vec2(posX,-posZ):dist(vec2(b.pos.x,-b.pos.z)) end)
end
for k=1,2 do
for i,m in pairs(meshTable[k]) do
--rotate free standing objects if required, so they face us
if m.rotate==true then
pushMatrix()
translate(m.pos.x,m.pos.y,-m.pos.z)
local dx,dz=m.pos.x-posX,-m.pos.z+posZ
local ang=math.atan(dx/-dz)/rad
rotate(-ang,0,1,0)
m:draw()
popMatrix()
elseif m.ang==nil then m:draw()
else
pushMatrix()
translate(m.pos.x,m.pos.y,-m.pos.z)
rotate(-m.ang,0,1,0)
m:draw()
popMatrix()
end
end
end
ortho() --this is needed to get text written on the screen
viewMatrix(matrix()) --and this
FPS=FPS*.9+.1/DeltaTime
pushStyle()
fill(0)
fontSize(18)
strokeWidth(3)
textMode(CORNER)
text("FPS: "..string.format("%d",FPS),50,HEIGHT-50)
text("x="..string.format("%  d",posX),50,HEIGHT-70)
text("y="..string.format("%  d",posY),50,HEIGHT-90)
text("z="..string.format("%  d",posZ),50,HEIGHT-110)
popStyle()
end

-- x,z = bottom left corner
-- y = height around the edges
-- w,d = width and depth of area to be terrained (pixels)
-- p = pixels per tile
-- f = minimum height (pixels), can be lower than y
-- h = max height (pixels)
-- r = whether to randomise terrain each run (true/false)
-- n = noise level (bigger numbers result in bumpy terrain, smaller gives smoother results)
-- tbl = table of heights, if provided
-- img = image or string name of image (do not include library name)
-- sc = image scaling factor (see above) 0-1
-- hm = height map storing heights of each point in
-- ns = the fraction by which noise level increases for each tile as we go deeper into the terrain
--      eg a value of 0.3 means that the outside ring of tiles has nil noise (as always, so these tiles
--      exactly meet the surface around), the next ring of tiles has noise of 0.3 of the full level,
--      the third ring of tiles has noise of 0.6, and so on, up to a maximum of 1.0. The bigger ns, the
--      the more you will get cliffs at the edges of the terrain

function AddTerrain(...)
local x,y,z,w,d,p,f,h,r,n,tbl,img,sc,hm,ns=Params(
{"x","y","z","width","depth","tileSize","minY","maxY","random","noiseLevel",
"heightTable","img","scaleFactor","heightMaps","noiseStep"},arg)
local nw,nd=math.floor(w/p),math.floor(d/p) --number of tiles in each direction
--if no table of heights provided, generate one with noise
if tbl==nil then
n=n or 0.2 --default noise level
tbl1,tbl2={},{}
--noise starts at 0 on the outside, increases by the step as we move inward, max of 1
--noise is nil at edge, increases by 30% per tile inwards, to 100%
local min,max=9999,0
--if user wants a random result each time. add a random number to the noise results
if r==true then rnd=math.random(1,10000) else rnd=0 end
for i=1,nw+1 do
tbl1[i],tbl2[i]={},{}
for j=1,nd+1 do
--noise fraction for this tile, based on how close to the edge it is
--this formula counts how many rows in from the edge this tile is
tbl1[i][j]=math.min(1,math.min(i-1,j-1,nw+1-i,nd+1-j)*ns)
--the noise itself
tbl2[i][j]=noise(rnd+i*n, rnd+j*n)
--keep track of min and max values of noise
if tbl2[i][j]max then max=tbl2[i][j] end
end
end
--now go back through the whole array and scale it
--we know the user wants values between f and h
--we know our noise varies between min and max
--so now we pro rate all our values so they vary between f and h, based on the noise values
for i=1,nw+1 do
for j=1,nd+1 do
local f1=y
--pro rate
local f2=f+(h-f)*(tbl2[i][j]-min)/(max-min)
--now apply noise fraction, to reduce noise around the edges
tbl2[i][j]=f1*(1-tbl1[i][j])+f2*tbl1[i][j]
end
end
end
--store details for later use in determining height
table.insert(hm,{x1=x,z1=z,x2=x+w,z2=z+d,p=p,t=tbl2})
--create the vectors and mesh
local nx,nz=w/img.width/sc,d/img.height/sc
v,t={},{}
for i=1,nw do
for j=1,nd do
local x1,x2=x+(i-1)*p,x+i*p  local x3,x4=x2,x1
local y1,y2,y3,y4=tbl2[i][j],tbl2[i+1][j],tbl2[i+1][j+1],tbl2[i][j+1]
local z1,z3=z+(j-1)*p,z+j*p  local z2,z4=z1,z3
v[#v+1]=vec3(x1,y1,-z1) t[#t+1]=vec2(0,0)  --bottom left
v[#v+1]=vec3(x2,y2,-z2) t[#t+1]=vec2(nx,0)  --bottom right
v[#v+1]=vec3(x3,y3,-z3) t[#t+1]=vec2(nx,nz)  --top right
v[#v+1]=vec3(x3,y3,-z3) t[#t+1]=vec2(nx,nz)  --top right
v[#v+1]=vec3(x4,y4,-z4) t[#t+1]=vec2(0,nz)  --top left
v[#v+1]=vec3(x1,y1,-z1) t[#t+1]=vec2(0,0)  --bottom left
end
end
local m=mesh()
m.texture=img
m.vertices=v
m:setColors(color(255))
m.texCoords=t
m.pos=vec3(x,y,z)
m.shader = shader(autoTilerShader.vertexShader, autoTilerShader.fragmentShader)
table.insert(meshTable[1],m)
end

--calculates height at x,z
function HeightAtPos(x,z)
--identify the location and calculate height
local h=0 --set default as 0
for i,v in pairs(HM) do  --look in each terrain area
if x>=v.x1 and x<=v.x2 and z>=v.z1 and z<=v.z2 then --if in this area...
--calc which square we are in
local mx,mz=1+math.floor((x-v.x1)/v.p),1+math.floor((z-v.z1)/v.p)
--use bilinear interpolation (most common method) for interpolating 4 corner values
local px,pz=1+(x-v.x1)/v.p-mx,1+(z-v.z1)/v.p-mz
h=v.t[mx][mz]*(1-px)*(1-pz)+
v.t[mx+1][mz]*px*(1-pz)+
v.t[mx+1][mz+1]*px*pz+
v.t[mx][mz+1]*(1-px)*pz
break
end
end
return h
end

function AddItem(x,y,z,w,i,r) --centred on x
y=HeightAtPos(x,z)
local h=i.height*w/i.width
local m=mesh()
m.texture=i
local v,t={},{}
v,t=AddImage(-w/2,0,0,w,h,0,v,t)
m.pos=vec3(x,y,z)
if r~=nil then m.ang=r else m.rotate=true end
m.vertices=v
m:setColors(color(255))
m.texCoords=t
table.insert(meshTable[2],m)
end

function AddImage(x,y,z,w,h,d,v,t)
v[#v+1]=vec3(x,y,z)  t[#t+1]=vec2(0,0)
v[#v+1]=vec3(x+w,y,z-d)  t[#t+1]=vec2(1,0)
v[#v+1]=vec3(x+w,y+h,z-d)  t[#t+1]=vec2(1,1)
v[#v+1]=vec3(x+w,y+h,z-d)  t[#t+1]=vec2(1,1)
v[#v+1]=vec3(x,y+h,z)  t[#t+1]=vec2(0,1)
v[#v+1]=vec3(x,y,z)  t[#t+1]=vec2(0,0)
return v,t
end

function AddLevel(x,y,z,w,d,i,s)
local m=mesh()
m.texture=i
local v,t={},{}
local nx,nz=w/i.width/s,d/i.height/s
v[#v+1]=vec3(x,y,-z)  t[#t+1]=vec2(0,0)
v[#v+1]=vec3(x+w,y,-z)  t[#t+1]=vec2(nx,0)
v[#v+1]=vec3(x+w,y,-z-d)  t[#t+1]=vec2(nx,nz)
v[#v+1]=vec3(x+w,y,-z-d)  t[#t+1]=vec2(nx,nz)
v[#v+1]=vec3(x,y,-z-d)  t[#t+1]=vec2(0,nz)
v[#v+1]=vec3(x,y,-z)  t[#t+1]=vec2(0,0)
m.vertices=v
m:setColors(color(255))
m.texCoords=t
m.pos=vec3(x,y,z)
m.shader = shader(autoTilerShader.vertexShader, autoTilerShader.fragmentShader)
table.insert(meshTable[1],m)
end

``````

that like hurts to watch D:

Try this tutorial (the code above comes from there)

http://coolcodea.wordpress.com/2013/05/27/665-3d-terrain-hills/

@Kingamer I fixed your code formatting. If you want to paste code you can either surround your code with tilde `~~~` characters (three above and three below). Or you can use html `pre` tags. If you use `pre lang="lua"` you get syntax highlighting.

@KinGamer - actually, I just realised you’ve already got (my) code that produces 3D grass terrain.

What more do you want?

@Ignatz it doesn’t work on my ipad mini. There are no errors, but whenever I try to debug it freezes. But it doesn’t freeze on my other game I have created.

I am trying this code and it works if you own the images in Documents (downloading and writing does seems to work at all) but there must be something weird with the textures, the ground hills meshes are not being painted…