Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Last active June 5, 2016 12:52
Show Gist options
  • Save dermotbalson/34d83800a16632cf5f91d8d845bac3f4 to your computer and use it in GitHub Desktop.
Save dermotbalson/34d83800a16632cf5f91d8d845bac3f4 to your computer and use it in GitHub Desktop.
3D box 2
--# Main
displayMode(FULLSCREEN)
function setup()
size,radius=200,10
pos=vec3(0,0,0) --assumes centre of box is (0,0,0)
CreateScene()
notStarted=true
end
function touched(t)
if t.state==ENDED then
local v=vec3(math.random()*6-3,math.random()*6-3,math.random()*6-3):normalize()*5
velocity=velocity+v
notStarted=false
end
end
function CreateScene() --size is size of 3D box
local img=readImage("SpaceCute:Background")--:copy(4,4,62,62)
box=CreateBlock(size,size,size,color(255),vec3(0,0,0),img)
ball=CreateSphere(radius,readImage("Cargo Bot:Starry Background"),color(255))
velocity=vec3(0,0,0)
end
function AdjustPos()
local p=pos+velocity
--check for collisions with each axis wall
local f=0
--x
if p.x-radius<-size/2 then --collided with left wall
f=(-size/2-p.x+radius)/velocity.x --backtrack by this fraction of the last movement
velocity.x=-velocity.x --reverse x velocity
elseif p.x+radius>size/2 then --right wall
f=(p.x+radius-size/2)/velocity.x
velocity.x=-velocity.x
end
--y
if p.y-radius<-size/2 then
f=(-size/2-p.y+radius)/velocity.y
velocity.y=-velocity.y
elseif p.y+radius>size/2 then
f=(p.y+radius-size/2)/velocity.y
velocity.y=-velocity.y
end
--z
if p.z-radius<-size/2 then
f=(-size/2-p.z+radius)/velocity.z
velocity.z=-velocity.z
elseif p.z+radius>size/2 then
f=(p.z+radius-size/2)/velocity.z
velocity.z=-velocity.z
end
pos=pos+velocity*(1-f)
end
function draw()
background(220)
perspective(90)
AdjustPos() print(pos)
camera(0,0,0,pos.x,pos.y,pos.z)
box:draw()
pushMatrix()
translate(pos:unpack())
ball:draw()
popMatrix()
if notStarted then
ortho()
viewMatrix(matrix())
text(
[[You are at the centre of a box with a red ball.
You can't see anything because the ball is around you
Touch the screen to push the ball in a random direction
and the camera will follow its movement.
Touch the screen to push it again.]],WIDTH/2,HEIGHT/2)
end
end
--# Utility
function CreateBlock(w,h,d,col,pos,tex) --width,height,depth,colour,position,texture
local x,X,y,Y,z,Z=pos.x-w/2,pos.x+w/2,pos.y-h/2,pos.y+h/2,pos.z-d/2,pos.z+d/2
local v={vec3(x,y,Z),vec3(X,y,Z),vec3(X,Y,Z),vec3(x,Y,Z),vec3(x,y,z),vec3(X,y,z),vec3(X,Y,z),vec3(x,Y,z)}
local vert={v[1],v[2],v[3],v[1],v[3],v[4],v[2],v[6],v[7],v[2],v[7],v[3],v[6],v[5],v[8],v[6],v[8],v[7],
v[5],v[1],v[4],v[5],v[4],v[8],v[4],v[3],v[7],v[4],v[7],v[8],v[5],v[6],v[2],v[5],v[2],v[1]}
local texCoords
if tex then
local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
texCoords={t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],
t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3]}
end
local n={vec3(0,0,1),vec3(1,0,0),vec3(0,0,-1),vec3(-1,0,0),vec3(1,0,0),vec3(-1,0,0)}
local norm={}
for i=1,6 do for j=1,6 do norm[#norm+1]=n[i] end end
local ms = mesh()
ms.vertices = vert
ms.normals=norm
if tex then ms.texture,ms.texCoords = tex,texCoords end
ms:setColors(col or color(255))
return ms
end
function CreateSphere(r,tex,col,nx,ny)
local vertices,tc = Sphere_OptimMesh(nx or 40,ny or 20)
vertices = Sphere_WarpVertices(vertices)
for i=1,#vertices do vertices[i]=vertices[i]*r end
local ms = mesh()
ms.vertices=vertices
if tex then ms.texture,ms.texCoords=tex,tc end
ms:setColors(col or color(255))
return ms
end
function Sphere_OptimMesh(nx,ny)
local v,t={},{}
local k,s,x,y,x1,x2,i1,i2,sx,sy=0,1,0,0,{},{},0,0,nx/ny,1/ny
local c = vec3(1,0.5,0)
local m1,m2
for y=0,ny-1 do
local nx1 = math.floor( nx * math.abs(math.cos(( y*sy-0.5)*2 * math.pi/2)) )
if nx1<6 then nx1=6 end
local nx2 = math.floor( nx * math.abs(math.cos(((y+1)*sy-0.5)*2 * math.pi/2)) )
if nx2<6 then nx2=6 end
x1,x2 = {},{}
for i1 = 1,nx1 do x1[i1] = (i1-1)/(nx1-1)*sx end x1[nx1+1] = x1[nx1]
for i2 = 1,nx2 do x2[i2] = (i2-1)/(nx2-1)*sx end x2[nx2+1] = x2[nx2]
local i1,i2,n,nMax,continue=1,1,0,0,true
nMax = nx*2+1
while continue do
m1,m2=(x1[i1]+x1[i1+1])/2,(x2[i2]+x2[i2+1])/2
if m1<=m2 then
v[k+1],v[k+2],v[k+3]=vec3(x1[i1],sy*y,1)-c,vec3(x1[i1+1],sy*y,1)-c,vec3(x2[i2],sy*(y+1),1)-c
t[k+1],t[k+2],t[k+3]=vec2(-x1[i1]/2,sy*y) ,vec2(-x1[i1+1]/2,sy*y),vec2(-x2[i2]/2,sy*(y+1))
if i1<nx1 then i1 = i1 +1 end
else
v[k+1],v[k+2],v[k+3]=vec3(x1[i1],sy*y,1)-c,vec3(x2[i2],sy*(y+1),1)-c,vec3(x2[i2+1],sy*(y+1),1)-c
t[k+1],t[k+2],t[k+3]=vec2(-x1[i1]/2,sy*y),vec2(-x2[i2]/2,sy*(y+1)),vec2(-x2[i2+1]/2,sy*(y+1))
if i2<nx2 then i2 = i2 +1 end
end
if i1==nx1 and i2==nx2 then continue=false end
k,n=k+3,n+1
if n>nMax then continue=false end
end
end
return v,t
end
function Sphere_WarpVertices(verts)
local m = matrix(0,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0)
local vx,vy,vz,vm
for i,v in ipairs(verts) do
vx,vy = v[1], v[2]
vm = m:rotate(180*vy,1,0,0):rotate(180*vx,0,1,0)
vx,vy,vz = vm[1],vm[5],vm[9]
verts[i] = vec3(vx,vy,vz)
end
return verts
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment