3D controls and movement in a 3D land

Speaks for itself


--# Main
-- Main
displayMode(FULLSCREEN)
function setup()
    parameter.integer("angle",0,360)
    parameter.watch("1/DeltaTime")
    t={}
    for i=1,20 do
        t[i]=Tree(math.random(-200,200),0,math.random(-200,200),"Documents:tree",5)
    end
    fdist=-300
    camPos=vec2(0,fdist)
    camFocus=vec2(0,0)
    f=Floor(0,0,0,500)
    j=Joystick(200,200,100)
    vel=0
end

function draw()
    vel=vec2(-j.vel.x,j.vel.y):rotate(math.rad(angleBetween(camPos,camFocus)-90))
    camPos = camPos +vel/50
    camFocus = camFocus +vel/50
    pushMatrix()
    perspective(45,WIDTH/HEIGHT)
    camera(camPos.x,50,camPos.y,camFocus.x,50,camFocus.y,0,1,0)
    background(100)
    --[
    for i=1,#t do
        t[i]:draw()
    end
    --]]
    f:draw()
    popMatrix()
    ortho()
    viewMatrix(matrix())
    j:draw()
    fill(255)
    fontSize(30)
    font("AmericanTypewriter-Bold")
    textMode(CENTER)
    textAlign(CENTER)
text("swipe the right side of the screen to look around\
and use the joystick to move",
    WIDTH/2,100)
end

function touched(touch)
    if touch.x<WIDTH/2 then j:touched(touch) else
        local offset=camFocus-camPos
        local new=offset:rotate(math.rad(touch.deltaX))
        camFocus=camPos+new
    end
end

function angleBetween(ptA,ptB)
    local angle=math.deg(math.atan2(ptA.y-ptB.y,ptA.x-ptB.x))
    angle = angle + 90
    return angle
end






--# Tree
Tree = class()

function Tree:init(x,y,z,img,SF)
    self.x = x
    self.y=y
    self.z=z
    self.texture=readImage("Documents:tree")
    self.width=self.texture.width/SF
    self.height=self.texture.height/SF
    self.mesh=self:setup()
    local d={v=[[
//
// A basic vertex shader
//

//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;

//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;

//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    //Pass the mesh color to the fragment shader
    vColor = color;
    vTexCoord = texCoord;
    
    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}
]],f=[[
//
// A basic fragment shader
//

//Default precision qualifier
precision highp float;

//This represents the current texture on the mesh
uniform lowp sampler2D texture;
uniform highp float alpha;
//The interpolated vertex color for this fragment
varying lowp vec4 vColor;

//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;

void main()
{
    //Sample the texture at the interpolated coordinate
    lowp vec4 col = texture2D( texture, vTexCoord ) * vColor;
    if (col.a <=alpha) discard;
    //Set the output color to the texture color
    gl_FragColor = col;
}
]]}
    self.mesh.shader=shader(d.v,d.f)
    self.mesh.shader.alpha=0.5
end

function Tree:draw()
    self.mesh:draw()
end

function Tree:setup()
    local x,y,z,w,h=self.x,self.y,self.z,self.width,self.height
    local v={}
    --[[
    3,4
    1,2
    --]]
    v[1]=vec3(x-w/2,y,z)
    v[2]=vec3(x+w/2,y,z)
    v[3]=vec3(x-w/2,y+h,z)
    v[4]=vec3(x+w/2,y+h,z)
    
    v[5]=vec3(x,y,z-w/2)
    v[6]=vec3(x,y,z+w/2)
    v[7]=vec3(x,y+h,z-w/2)
    v[8]=vec3(x,y+h,z+w/2)
    
    local verts={}
    table.insert(verts,v[1])
    table.insert(verts,v[2])
    table.insert(verts,v[3])
    table.insert(verts,v[2])
    table.insert(verts,v[3])
    table.insert(verts,v[4])
    
    table.insert(verts,v[5])
    table.insert(verts,v[6])
    table.insert(verts,v[7])
    table.insert(verts,v[6])
    table.insert(verts,v[7])
    table.insert(verts,v[8])
    
    local bl=vec2(0,0)
    local br=vec2(1,0)
    local tl=vec2(0,1)
    local tr=vec2(1,1)
    
    local tcoords={}
    
    for i=1,2 do
        table.insert(tcoords,bl)
        table.insert(tcoords,br)
        table.insert(tcoords,tl)
        
        table.insert(tcoords,br)
        table.insert(tcoords,tl)
        table.insert(tcoords,tr)
    end
    
    local m=mesh()
    m.vertices=verts
    m:setColors(color(255,255,255,255))
    m.texture=self.texture
    m.texCoords=tcoords
    return m
end

--# Floor
Floor = class()

function Floor:init(x,y,z,w,l,t)
    self.x = x --center
    self.y = y
    self.z = z
    self.width = w --x axis
    self.length = l or w --z axis
    self.texture = t or readImage("SpaceCute:Background")
    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

--# Joystick
Joystick = class()

function Joystick:init(x,y,r)
    self.x = x
    self.y=y
    self.rad=r
    self.stickX=x
    self.stickY=y
    self.touchInRange=false
    self.angle=0
    self.magnitude=0
    self.vel=vec2(0,0)
end

function Joystick:draw()
    self.vel=vec2(-self.magnitude,0):rotate(math.rad(self.angle))
    pushStyle()
    noFill()
    stroke(255, 255, 255, 255)
    strokeWidth(50)
    ellipseMode(RADIUS) 
   -- ellipse(self.x,self.y,self.rad)
    
    line(self.x,self.y,self.stickX,self.stickY)
    fill(255, 0, 0, 255)
    noStroke()
    ellipse(self.stickX,self.stickY,self.rad/2)
end

function Joystick:touched(touch)
    local tpos=vec2(touch.x,touch.y)
    if touch.state==BEGAN then self.touchInRange = (tpos:dist(vec2(self.x,self.y))<self.rad*2)end 
    if self.touchInRange then
        tAngle=angleBetween(tpos,vec2(self.x,self.y))
        self.angle=tAngle
        
        local stickpos=vec2(-self.rad,0)
        if tpos:dist(vec2(self.x,self.y))<self.rad then
            stickpos=tpos-vec2(self.x,self.y)--stickpos:rotate(math.rad(tAngle))
            self.magnitude=tpos:dist(vec2(self.x,self.y))
        else
            stickpos=stickpos:rotate(math.rad(tAngle))
            self.magnitude=self.rad
        end
        self.stickX,self.stickY=self.x+stickpos.x,self.y+stickpos.y
    end
    if touch.state==ENDED then
        self.stickX,self.stickY=self.x,self.y
        self.angle=0
        self.magnitude=0
    end
    return self.touchInRange
end

function angleBetween(ptA,ptB)
    local angle=math.deg(math.atan2(ptA.y-ptB.y,ptA.x-ptB.x))
    angle = angle + 180--90
    return angle
end


@coder could be great, but error (missing texture).
thanks.

Sorry. Just use any tree texture

works well after replacing tree images (use planet cute tree)

Wow! This is amazing! I wish I could do stuff like this.