Created
October 7, 2013 00:45
-
-
Save NathanFlurry/6861006 to your computer and use it in GitHub Desktop.
Today, I wanted to learn in depth how to use the 3D aspect of Codea, so I embarked on making a simple 3D prototype of my game StackIt. Please note, there's tons of bugs, but I needed to keep working on the actual StackIt, so I stopped the development there.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--# Main | |
displayMode(FULLSCREEN) | |
supportedOrientations(PORTRAIT_ANY) | |
function setup() | |
bg = getGradient(vec2(WIDTH,HEIGHT),color(0,90,255),color(50,190,255)) | |
Game:init() | |
end | |
-- This function gets called once every frame | |
function draw() | |
background(0, 0, 0) | |
pushMatrix() | |
translate(WIDTH/2,HEIGHT/2,-10) | |
bg:draw() | |
popMatrix() | |
Game:draw() | |
end | |
function touched(t) | |
if Game.touched then | |
Game:touched(t) | |
end | |
end | |
shader = shader([[ | |
attribute vec4 position; | |
attribute vec3 normal; | |
attribute vec3 color; | |
uniform mat4 modelViewProjection; | |
varying vec3 eyenormal; | |
varying vec3 diffuse; | |
void main(void) | |
{ | |
eyenormal = mat3(modelViewProjection) * normal; | |
diffuse = color; | |
gl_Position = modelViewProjection * position; | |
} | |
]], [[ | |
uniform highp vec3 light; | |
varying mediump vec3 eyenormal; | |
varying lowp vec3 diffuse; | |
void main(void) | |
{ | |
highp vec3 N = normalize(eyenormal); | |
highp vec3 L = normalize(light); | |
highp vec3 E = vec3(0, 0, 1); | |
highp vec3 H = normalize(L + E); | |
highp float df = max(0.0, dot(N, L)) * 0.3; | |
highp float sf = max(0.0, dot(N, H)); | |
sf = pow(sf, 250.0); | |
if(abs(N.z) < 0.2) sf = sf + (1.0 - abs(N.z)*(1.0/0.2)); | |
sf = sf * 0.5; | |
lowp vec3 color = vec3(1,1,1) * 0.7 * diffuse + df * diffuse + sf * vec3(1,1,1); | |
gl_FragColor = vec4(min(1.0,color.x), min(1.0,color.y), min(1.0,color.z), 1.0); | |
} | |
]] | |
) | |
--# Game | |
Game = class() | |
function Game:init() | |
self.paddle = Paddle() | |
self.oManager = ObjectManager() | |
end | |
function Game:draw() | |
pushMatrix() | |
perspective(45, WIDTH/HEIGHT) | |
camera(0,500,-500, 0,0,0, 0,1,0) | |
-- Paddle | |
self.paddle:draw() | |
self.oManager:draw() | |
popMatrix() | |
-- HUD | |
ortho() | |
viewMatrix(matrix()) | |
fill(255) | |
font("MyriadPro-Bold") | |
fontSize(30) | |
--text("Hello", WIDTH/2, HEIGHT - 30) | |
end | |
function Game:touched(t) | |
self.paddle:touched(t) | |
end | |
--# Paddle | |
Paddle = class() | |
function Paddle:init() | |
self.x = 0 | |
self.y = 0 | |
self.size = vec3(125,25,125) | |
self.m = getCube() | |
self.m.colors = shadeCube(color(255)) | |
end | |
function Paddle:draw() | |
if self.x < -WIDTH/2 then self.x = -WIDTH/2 | |
elseif self.x > WIDTH/2 then self.x = WIDTH/2 | |
elseif self.y < -HEIGHT/2 then self.y = -HEIGHT/2 | |
elseif self.y > HEIGHT/2 then self.y = HEIGHT/2 end | |
pushMatrix() | |
resetMatrix() | |
translate(-self.x,0,self.y) | |
scale(self.size.x,self.size.y,self.size.z) | |
self.m:draw() | |
popMatrix() | |
end | |
function Paddle:touched(t) | |
self.x = self.x + t.deltaX | |
self.y = self.y + t.deltaY | |
end | |
--# ObjectManager | |
ObjectManager = class() | |
function ObjectManager:init() | |
self.oList = {} | |
self.colors = { | |
color(165,195,255), | |
color(255,240,45), | |
color(255,110,85), | |
color(185,130,210), | |
color(160,255,165), | |
color(255,255,155), | |
color(255,170,250) | |
} | |
self.range = WIDTH/2 | |
self:addObject() | |
self.oSpawnTimer = Timer(4, function() self:addObject() end) | |
end | |
function ObjectManager:draw() | |
self.oSpawnTimer:update() | |
for i,o in ipairs(self.oList) do | |
o:draw() | |
if o.height < -HEIGHT then | |
table.remove(self.oList,i) | |
end | |
end | |
end | |
function ObjectManager:addObject() | |
local o = Object() | |
o.x = (math.random()-.5)*self.range | |
o.y = (math.random()-.5)*self.range | |
o.m.colors = shadeCube(self.colors[math.random(#self.colors)]) | |
table.insert(self.oList,o) | |
end | |
--# Object | |
Object = class() | |
function Object:init() | |
self.x = 0 | |
self.y = 0 | |
self.height = HEIGHT*.3 | |
self.speed = 1 | |
self.size = vec3(25,25,25) | |
self.landingNode = nil | |
self.id = math.random() | |
self.m = getCube() | |
end | |
function Object:draw() | |
if not self.landingNode then | |
self.height = self.height - self.speed | |
self:testCollisions() | |
else | |
self.x = Game.paddle.x + self.landingNode.x | |
self.y = Game.paddle.y + self.landingNode.y | |
end | |
shadowBlur = self.height/10 | |
pushMatrix() | |
resetMatrix() | |
translate(-self.x,self.height,self.y) | |
scale(self.size.x,self.size.y,self.size.z) | |
self.m:draw() | |
popMatrix() | |
if self.x > Game.paddle.x-Game.paddle.size.x/2 and self.x < Game.paddle.x+Game.paddle.size.x/2 and self.y > Game.paddle.y-Game.paddle.size.x/2 and self.y < Game.paddle.y+Game.paddle.size.x/2 and self.height > 0 then | |
pushMatrix() | |
pushStyle() | |
resetMatrix() | |
translate(-self.x,Game.paddle.size.y/2+1,self.y) | |
rotate(90,1,0,0) | |
scale(shadowBlur) | |
fill(0,0,0,50) | |
noStroke() | |
rect(-self.size.x/2/shadowBlur,-self.size.y/2/shadowBlur,self.size.x/shadowBlur,self.size.y/shadowBlur) | |
popStyle() | |
popMatrix() | |
end | |
end | |
function Object:testCollisions() | |
for i,v in ipairs(Game.oManager.oList) do | |
local xO = math.abs(self.x-v.x) < (self.size.x+v.size.x)/2 | |
local yO = math.abs(self.y-v.y) < (self.size.z+v.size.z)/2 | |
local zO = math.abs(self.height-v.height) < (self.size.y+v.size.y)/2 | |
if self.id ~= v.id and (xO and yO and zO) then | |
self.landingNode = vec2(self.x-Game.paddle.x,self.y-Game.paddle.y) | |
end | |
end | |
local xO = math.abs(self.x-Game.paddle.x) < (self.size.x+Game.paddle.size.x)/2 | |
local yO = math.abs(self.y-Game.paddle.y) < (self.size.z+Game.paddle.size.z)/2 | |
local zO = self.height < (self.size.y+Game.paddle.size.y)/2 | |
if xO and yO and zO then | |
self.landingNode = vec2(self.x-Game.paddle.x,self.y-Game.paddle.y) | |
end | |
end | |
--# Timer | |
Timer = class() | |
function Timer:init(interval,callback) | |
self.interval = interval | |
self.callback = callback | |
self.time = 0 | |
self.occurances = 0 | |
self.paused = false | |
end | |
function Timer:update() | |
if self.paused ~= true then | |
self.time = self.time + DeltaTime | |
if self.time >= self.interval then | |
self.occurances = self.occurances + 1 | |
self.time = 0 | |
if type(self.callback) == "function" then | |
self.callback(self.occurances) | |
end | |
return true | |
else | |
return false | |
end | |
end | |
end | |
function Timer:reset() | |
self.time = 0 | |
self.occurances = 0 | |
end | |
function Timer:pause() | |
self.paused = true | |
end | |
function Timer:resume() | |
self.paused = false | |
end | |
function Timer:isPaused() | |
return self.paused | |
end | |
function Timer:getTime() | |
return self.time | |
end | |
function Timer:getCount() | |
return self.occurances | |
end | |
--# Functions | |
-- Test 3D Bounds | |
function testCollisions(b1p,b1s,b2p,b2s) | |
local xO = math.abs(b1p.x-Game.paddle.x) < (self.size.x+Game.paddle.size.x)/2 | |
local yO = math.abs(b1p.y-Game.paddle.y) < (self.size.z+Game.paddle.size.z)/2 | |
local zO = self.height < (self.size.y+Game.paddle.size.y)/2 | |
if self.id ~= Game.paddle.id and (xO and yO and zO) then | |
self.landingNode = vec2(self.x-Game.paddle.x,self.y-Game.paddle.y) | |
end | |
end | |
-- Explode table | |
function _values(t) | |
local i = 0 | |
return function() i = i + 1; return t[i] end | |
end | |
function _explodeNext(iter, t) | |
local v = iter(t) | |
if v ~= nil then | |
return v, _explodeNext(iter, t) | |
else | |
return | |
end | |
end | |
function explodeTable(t) | |
local iter = _values(t) | |
return _explodeNext(iter, t) | |
end | |
-- Unreference table | |
function cleanTable(t) | |
local nt = {} | |
for i,v in pairs(t) do | |
if type(v) == "table" then | |
nt[i] = cleanTable(v) | |
else | |
nt[i] = v | |
end | |
end | |
return nt | |
end | |
-- Gradient | |
function getGradient(size,color1,color2) | |
local m = mesh() | |
m.setSize = function(size) | |
m.vertices = { | |
vec2(-size.x/2,-size.y/2), | |
vec2(-size.x/2,size.y/2), | |
vec2(size.x/2,-size.y/2), | |
vec2(size.x/2,size.y/2), | |
vec2(-size.x/2,size.y/2), | |
vec2(size.x/2,-size.y/2) | |
} | |
end | |
m.setGradient = function(color1,color2) | |
m.colors = { | |
color2, | |
color1, | |
color2, | |
color1, | |
color1, | |
color2 | |
} | |
end | |
m.setSize(size) | |
m.setGradient(color1,color2) | |
return m | |
end | |
-- 3D Cubes | |
function getCube() | |
local m = mesh() | |
m.vertices, m.texCoords = getCubeVerts() | |
return m | |
end | |
function getCubeVerts() | |
local vertices = { | |
vec3(-0.5, -0.5, 0.5), -- Left bottom front | |
vec3( 0.5, -0.5, 0.5), -- Right bottom front | |
vec3( 0.5, 0.5, 0.5), -- Right top front | |
vec3(-0.5, 0.5, 0.5), -- Left top front | |
vec3(-0.5, -0.5, -0.5), -- Left bottom back | |
vec3( 0.5, -0.5, -0.5), -- Right bottom back | |
vec3( 0.5, 0.5, -0.5), -- Right top back | |
vec3(-0.5, 0.5, -0.5), -- Left top back | |
} | |
-- now construct a cube out of the vertices above | |
local cubeverts = { | |
vertices[1], vertices[2], vertices[3], | |
vertices[1], vertices[3], vertices[4], | |
vertices[2], vertices[6], vertices[7], | |
vertices[2], vertices[7], vertices[3], | |
vertices[6], vertices[5], vertices[8], | |
vertices[6], vertices[8], vertices[7], | |
vertices[5], vertices[1], vertices[4], | |
vertices[5], vertices[4], vertices[8], | |
vertices[4], vertices[3], vertices[7], | |
vertices[4], vertices[7], vertices[8], | |
vertices[5], vertices[6], vertices[2], | |
vertices[5], vertices[2], vertices[1], | |
} | |
local texvertices = { vec2(0.03,0.24), | |
vec2(0.97,0.24), | |
vec2(0.03,0.69), | |
vec2(0.97,0.69) } | |
local cubetexCoords = { | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
} | |
return cubeverts, cubetextCoords | |
end | |
-- Shade cube | |
function shadeCube(oC) | |
local sA = 100 | |
local c = {} | |
-- Far | |
for i = 1,6 do | |
table.insert(c,color(oC.r-sA,oC.g-sA,oC.b-sA)) | |
end | |
-- Left | |
for i = 1,6 do | |
table.insert(c,color(oC.r-sA,oC.g-sA,oC.b-sA)) | |
end | |
-- Close | |
for i = 1,6 do | |
table.insert(c,color(oC.r-sA/2,oC.g-sA/2,oC.b-sA/2)) | |
end | |
-- Right | |
for i = 1,6 do | |
table.insert(c,color(oC.r+sA/4,oC.g+sA/4,oC.b+sA/4)) | |
end | |
-- Top | |
for i = 1,6 do | |
table.insert(c,oC) | |
end | |
-- Bottom | |
for i = 1,6 do | |
table.insert(c,color(oC.r-sA,oC.g-sA,oC.b-sA)) | |
end | |
return c | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment