Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save dermotbalson/849d86ab727b58b39a8ec17ca6f1905c to your computer and use it in GitHub Desktop.
Save dermotbalson/849d86ab727b58b39a8ec17ca6f1905c to your computer and use it in GitHub Desktop.
3D box
--# Main
displayMode(FULLSCREEN)
function setup()
size,radius=200,10
startPos=vec3(size/2,size/2,-size/2) --assumes centre of box is (0,0,0)
CreateScene(size,radius,startPos)
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
PushBall(v)
notStarted=false
end
end
function CreateScene(size,radius,pos) --size is size of 3D box
--make two boxes end to end using 5 lines
boxSize=100 --size of virtual box
local s=boxSize
boxes={}
boxes[1]=physics.body(EDGE,vec2(-s,-s/2),vec2(s,-s/2))
boxes[2]=physics.body(EDGE,vec2(-s,s/2),vec2(s,s/2))
boxes[3]=physics.body(EDGE,vec2(-s,-s/2),vec2(-s,s/2))
boxes[4]=physics.body(EDGE,vec2(0,-s/2),vec2(0,s/2))
boxes[5]=physics.body(EDGE,vec2(s,-s/2),vec2(s,s/2))
for _,b in pairs(boxes) do
b.restitution=1
b.friction=0
end
circles={}
for i=1,2 do
local p=physics.body(CIRCLE,10)
if i==1 then p.x,p.y=-s/2,0 else p.x,p.y=s/2,0 end
p.restitution=1
p.bullet=true
circles[i]=p
end
physics.gravity(0,0) --turn off gravity
physics.continuous=true
scaling=boxSize/size
--create visible 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))
end
function PushBall(v)
circles[1]:applyLinearImpulse(vec2(v.x,v.y)*scaling)
circles[2]:applyLinearImpulse(vec2(v.x,v.z)*scaling)
end
function GetPos()
return vec3(boxSize/2+circles[1].x,circles[1].y,circles[2].y)/scaling
end
function draw()
background(220)
perspective(90)
local p=GetPos()
camera(0,0,0,p.x,p.y,p.z)
box:draw()
pushMatrix()
translate(p:unpack())
ball:draw()
popMatrix()
ortho()
viewMatrix(matrix())
stroke(0)
strokeWidth(1)
local x,y=WIDTH-70,70
local s=50
local ss=s/scaling/size
line(x-s,y-s,x+s,y-s)
line(x-s,y+s,x+s,y+s)
line(x-s,y-s,x-s,y+s)
line(x+s,y-s,x+s,y+s)
fill(255,0,0,150)
ellipse(x+p.x*ss,y+p.y*ss,radius*2*ss)
text("XY",x-s+20,y+s-15)
y=180
line(x-s,y-s,x+s,y-s)
line(x-s,y+s,x+s,y+s)
line(x-s,y-s,x-s,y+s)
line(x+s,y-s,x+s,y+s)
ellipse(x+p.x*ss,y+p.z*ss,radius*2*ss)
text("XZ",x-s+20,y+s-15)
if notStarted then
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.
The two boxes below show the two physics planes used
to handle collisions with the sides of the box
]]
,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