Created
August 4, 2012 06:44
-
-
Save simsaens/3255183 to your computer and use it in GitHub Desktop.
Brickout Enhanced
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
--# Ball | |
---------------- | |
-- Ball Class -- | |
---------------- | |
Ball = class() | |
function Ball:init() | |
self.pos = vec2(WIDTH / 2, 41) | |
self.radius = 10 | |
self.vel = vec2(0, 7) | |
end | |
function Ball:draw() | |
local alpha = 255 | |
fill(253, 255, 0, alpha) | |
noStroke() | |
ellipse(self.pos.x, self.pos.y, 2 * self.radius) | |
-- Draw a trail | |
local trailPos = self.pos - self.vel | |
if ballIsMoving == true then | |
for i = 1,5 do | |
alpha = alpha / 2 | |
fill(253,255,0,alpha) | |
ellipse(trailPos.x,trailPos.y,2 * self.radius) | |
trailPos = trailPos - self.vel | |
end | |
end | |
end | |
function Ball:update() | |
self.pos = self.pos + self.vel | |
if (self.pos.x + self.radius) >= WIDTH then | |
self.pos.x = WIDTH - self.radius | |
self.vel.x = -self.vel.x | |
sound(SOUND_JUMP) | |
elseif (self.pos.x - self.radius) <= 0 then | |
self.pos.x = self.radius | |
self.vel.x = -self.vel.x | |
sound(SOUND_JUMP) | |
elseif (self.pos.y + self.radius) >= HEIGHT then | |
self.pos.y = HEIGHT - self.radius | |
self.vel.y = -self.vel.y | |
sound(SOUND_JUMP) | |
elseif (self.pos.y - self.radius) <= 0 then | |
self.pos.y = self.radius | |
self.vel.y = -self.vel.y | |
sound(SOUND_EXPLODE) | |
return false | |
end | |
return true | |
end | |
function Ball:left() | |
return self.pos.x - self.radius | |
end | |
function Ball:right() | |
return self.pos.x + self.radius | |
end | |
function Ball:top() | |
return self.pos.y + self.radius | |
end | |
function Ball:bottom() | |
return self.pos.y - self.radius | |
end | |
--# Bat | |
--------------- | |
-- Bat Class -- | |
--------------- | |
Bat = class() | |
function Bat:init() | |
self.pos = vec2(350, 20) | |
self.size = vec2(85, 20) | |
end | |
function Bat:draw() | |
fill(255, 255, 255, 255) | |
noStroke() | |
rectMode(CENTER) | |
ellipse(self.pos.x - self.size.x / 2, self.pos.y, 22) | |
ellipse(self.pos.x + self.size.x / 2, self.pos.y, 22) | |
rect(self.pos.x, self.pos.y, self.size.x, self.size.y) | |
end | |
function Bat:collide(ball) | |
if ball:left() <= self:right() and | |
ball:right() >= self:left() and | |
ball:top() >= self:bottom() and | |
ball:bottom() <= self:top() then | |
sound(SOUND_JUMP) | |
ball.vel.y = -ball.vel.y | |
-- change the x velocity depending on where the ball hit the bat | |
ball.pos.y = self:top() + ball.radius | |
pos = ball.pos.x - self.pos.x | |
ball.vel.x = pos / 10 | |
return true | |
end | |
return false | |
end | |
function Bat:left() | |
return self.pos.x - self.size.x / 2 | |
end | |
function Bat:right() | |
return self.pos.x + self.size.x / 2 | |
end | |
function Bat:top() | |
return self.pos.y + self.size.y / 2 | |
end | |
function Bat:bottom() | |
return self.pos.y - self.size.y / 2 | |
end | |
--# Block | |
----------------- | |
-- Block Class -- | |
----------------- | |
Block = class() | |
function Block:init(x, y, col) | |
self.mesh = mesh() | |
self.pos = vec2(x, y) | |
self.size = vec2(60,30) | |
self.colour = col | |
self.mesh:addRect( self.pos.x, self.pos.y, | |
self.size.x, self.size.y ) | |
local dark = self.colour:mix( color(0,0,0), 0.8 ) | |
self.mesh:color( 1, self.colour ) | |
self.mesh:color( 2, dark ) | |
self.mesh:color( 3, dark ) | |
self.mesh:color( 4, self.colour ) | |
self.mesh:color( 5, dark ) | |
self.mesh:color( 6, self.colour ) | |
-- Highlight | |
local idx = self.mesh:addRect( self.pos.x, | |
self.pos.y + self.size.y * 0.5 - 1, | |
self.size.x, 2 ) | |
self.mesh:setRectColor( idx, 255,255,255,90 ) | |
end | |
function Block:draw() | |
fill(self.colour) | |
noStroke() | |
rectMode(CENTER) | |
--rect(self.pos.x, self.pos.y, self.size.x, self.size.y) | |
self.mesh:draw() | |
end | |
function Block:collide(ball) | |
if ball:left() <= self:right() and | |
ball:right() >= self:left() and | |
ball:top() >= self:bottom() and | |
ball:bottom() <= self:top() then | |
sound(SOUND_BLIT) | |
if ball.pos.y <= self:top() and ball.pos.y >= self:bottom() then | |
ball.vel.x = -ball.vel.x | |
else | |
ball.vel.y = -ball.vel.y | |
end | |
return true | |
end | |
return false | |
end | |
function Block:left() | |
return self.pos.x - self.size.x / 2 | |
end | |
function Block:right() | |
return self.pos.x + self.size.x / 2 | |
end | |
function Block:top() | |
return self.pos.y + self.size.y / 2 | |
end | |
function Block:bottom() | |
return self.pos.y - self.size.y / 2 | |
end | |
--# Emitter | |
Emitter = class() | |
function Emitter:init(args) | |
self.particleMesh = mesh() | |
self.particleMesh.texture = args.tex | |
self.minLife = args.minLife or 1 | |
self.maxLife = args.maxLife or 1 | |
self.spread = args.spread or 360 | |
self.angle = args.angle or 0 | |
self.minSpeed = args.minSpeed or 10 | |
self.maxSpeed = args.maxSpeed or 50 | |
self.minSize = args.minSize or 10 | |
self.maxSize = args.maxSize or 15 | |
self.growth = args.growth or 1 | |
self.startColor = args.startColor or color(255, 255, 255, 255) | |
self.endColor = args.endColor or color(0, 0, 0, 0) | |
self.streak = args.streak or false | |
self.streakMult = args.streakMult or 2 | |
self.accel = args.accel or vec2(0,0) | |
self.rAccel = args.rAccel or vec2(0,0) | |
self.particles = {} | |
self.pCount = 0 | |
for i = 1,100 do | |
table.insert(self.particles, Particle()) | |
end | |
end | |
function Emitter:emit(pos,count) | |
for i = 1,#self.particles do | |
local p = self.particles[i] | |
if p.dead then | |
self.pCount = math.max(i, self.pCount) | |
p.dead = false | |
p.pos = pos | |
p.life = math.random(self.minLife, self.maxLife) | |
p.size = math.random(self.minSize, self.maxSize) | |
p.maxLife = p.life | |
p.vel = vec2(0, math.random(self.minSpeed, self.maxSpeed)) | |
p.vel = p.vel:rotate(math.rad(self.angle + | |
math.random(-self.spread/2, | |
self.spread/2))) | |
count = count - 1 | |
if count == 0 then return end | |
end | |
end | |
end | |
function Emitter:draw() | |
-- update | |
self.particleMesh:clear() | |
for i = 1,self.pCount do | |
local p = self.particles[i] | |
if not p.dead then | |
p.prevPos = p.pos | |
p.pos = p.pos + p.vel * DeltaTime | |
p.vel = p.vel + (self.accel + | |
vec2(math.random(-self.rAccel.x, | |
self.rAccel.x), | |
math.random(-self.rAccel.y, | |
self.rAccel.y))) | |
* DeltaTime | |
p.life = math.max(0, p.life - DeltaTime) | |
p.size = p.size + DeltaTime * self.growth | |
if p.life == 0 then p.dead = true end | |
local interp = p.life / p.maxLife | |
p.col.r = interp * self.startColor.r + | |
(1-interp) * self.endColor.r | |
p.col.g = interp * self.startColor.g + | |
(1-interp) * self.endColor.g | |
p.col.b = interp * self.startColor.b + | |
(1-interp) * self.endColor.b | |
p.col.a = interp * self.startColor.a + | |
(1-interp) * self.endColor.a | |
local ind = self.particleMesh:addRect(p.pos.x, | |
p.pos.y, | |
p.size, p.size) | |
self.particleMesh:setRectColor(ind, p.col) | |
if self.streak then | |
local dir = (p.pos - p.prevPos) | |
local len = dir:len() | |
local pos = (p.pos + p.prevPos) * 0.5 | |
local ang = math.atan2(dir.y, dir.x) | |
self.particleMesh:setRect(ind, pos.x, pos.y, | |
p.size * self.streakMult, | |
p.size, ang) | |
end | |
end | |
end | |
self.particleMesh:draw() | |
end | |
Particle = class() | |
function Particle:init() | |
self.pos = vec2(0,0) | |
self.prevPos = vec2(0,0) | |
self.vel = vec2(0,0) | |
self.life = 0 | |
self.maxLife = 0 | |
self.dead = true | |
self.col = color(0, 0, 0, 255) | |
self.size = 0 | |
end | |
--# Levels | |
------------------ | |
-- Levels array -- | |
------------------ | |
levels = { | |
{{0,0,1,1,1,1,1,1,0,0},{0,1,1,0,0,0,0,1,1,0},{0,0,1,1,1,1,1,1,0,0}, | |
{0,0,1,1,1,1,1,1,0,0},{0,1,1,0,0,0,0,1,1,0},{0,0,1,1,1,1,1,1,0,0}}, | |
{{1,1,1,1,1,1,1,1,1,1},{1,0,0,1,0,0,1,0,0,1},{0,1,1,0,1,1,0,1,1,0}, | |
{0,1,1,0,1,1,0,1,1,0},{1,0,1,1,0,0,1,0,0,1},{1,1,1,1,1,1,1,1,1,1}}, | |
{{0,0,0,1,1,1,1,0,0,0},{0,0,1,1,1,1,1,1,0,0},{1,1,1,1,1,1,1,1,1,1}, | |
{1,1,1,1,1,1,1,1,1,1},{0,1,1,1,1,1,1,1,1,0},{0,0,1,1,1,1,1,1,0,0}}, | |
{{1,0,1,1,1,1,1,1,0,1},{1,1,1,0,1,1,0,1,1,1},{1,0,1,1,0,0,1,1,0,1}, | |
{1,0,1,1,0,0,1,1,0,1},{1,1,1,0,1,1,0,1,1,1},{1,0,1,1,1,1,1,1,0,1}}, | |
{{1,1,1,1,1,1,1,1,1,1},{1,0,1,1,0,0,1,1,0,1},{1,1,0,0,1,1,0,0,1,1}, | |
{1,1,0,0,1,1,0,0,1,1},{1,0,1,1,0,0,1,1,0,1},{1,1,1,1,1,1,1,1,1,1}} | |
} | |
--# Main | |
------------------------- | |
-- Main game functions -- | |
------------------------- | |
supportedOrientations(LANDSCAPE_ANY) | |
bg = mesh() | |
bat = nil | |
ball = nil | |
blocks = {} | |
emitter = nil | |
score = 0 | |
lives = 3 | |
ballIsMoving = false | |
lastDelta = 0 | |
gameover = false | |
won = false | |
level = 1 | |
maxlevel = table.maxn(levels) | |
-- Use this function to perform your initial setup | |
function setup() | |
ball = Ball() | |
ball.vel.x = math.random(-3,3) | |
bat = Bat() | |
makeBG() | |
makeBlocks() | |
makeEmitter() | |
print("Tap the bat to lanch the ball.") | |
print("Drag om the screen to move the paddle") | |
print("When the game is over tap the screen to restart.") | |
end | |
-- Make background mesh | |
function makeBG() | |
bg:addRect(WIDTH/2,HEIGHT/2,WIDTH,HEIGHT) | |
local light = color(42, 47, 56, 255) | |
local dark = color(22, 23, 25, 255) | |
bg:color( 1, light ) | |
bg:color( 2, dark ) | |
bg:color( 3, dark ) | |
bg:color( 4, light ) | |
bg:color( 5, dark ) | |
bg:color( 6, light ) | |
end | |
-- Make a particle emitter for effects | |
function makeEmitter() | |
emitter = Emitter( { | |
tex = "Cargo Bot:Star", | |
startColor = color(255,255,255,255), | |
endColor = color(255,255,0,0), | |
minSize = 4, | |
maxSize = 8, | |
minSpeed = 100, | |
maxSpeed = 150, | |
accel = vec2(0,-700), | |
rAccel = vec2(500,500), | |
streak = false | |
} ) | |
end | |
-- create table of blocks from level array | |
function makeBlocks() | |
for i = 1, 6 do | |
c = getColourForRow(i) | |
for j = 1, 10 do | |
if levels[level][i][j] > 0 then | |
table.insert(blocks, Block(30 + (j * 62), HEIGHT - (i * 32 + 35), c)) | |
end | |
end | |
end | |
end | |
-- get colour for current row | |
function getColourForRow(row) | |
colChanger = row * 35 | |
if level % 4 == 1 then | |
c = color(colChanger,0,255,255) | |
elseif level % 4 == 2 then | |
c = color(255,colChanger,0,255) | |
elseif level % 4 == 3 then | |
c = color(255,0,colChanger,255) | |
else | |
c = color(0,255,colChanger,255) | |
end | |
return c | |
end | |
-- Stop ball and put it back on bat | |
function resetBall() | |
ballIsMoving = false | |
ball.pos.x = bat.pos.x | |
ball.pos.y = 41 | |
end | |
-- Reset game to original state | |
function resetGame() | |
score = 0 | |
lives = 3 | |
level = 1 | |
blocks = {} | |
makeBlocks() | |
gameover = false | |
won = false | |
end | |
-- Level up | |
function nextLevel() | |
score = score + 100 * lives * level | |
--ball.vel.y = ball.vel.y + 0.5 | |
resetBall() | |
if level < maxlevel then | |
level = level + 1 | |
makeBlocks() | |
else | |
won = true | |
end | |
end | |
-- Lose a life | |
function loseLife() | |
resetBall() | |
lives = lives - 1 | |
if lives == 0 then | |
gameover = true | |
end | |
end | |
-- This function gets called once every frame | |
function draw() | |
background(0, 0, 0, 255) | |
bg:draw() | |
noSmooth() | |
-- Update the ball | |
if ballIsMoving then | |
if ball:update() == false then | |
loseLife() | |
end | |
else | |
ball.pos.x = bat.pos.x | |
end | |
-- Check collision with the bat | |
if bat:collide(ball) == false then | |
-- Check collision with the blocks | |
-- no need to do this if ball has hit bat. | |
-- Still does a lot of unecessary checks | |
for i = 1, table.maxn(blocks) do | |
if blocks[i]:collide(ball) then | |
-- Emit particles | |
emitter:emit( blocks[i].pos, 10 ) | |
table.remove(blocks, i) | |
score = score + 100 | |
if table.maxn(blocks) == 0 then | |
nextLevel() | |
end | |
break | |
end | |
end | |
end | |
-- Draw game objects | |
bat:draw() | |
ball:draw() | |
for i = 1, table.maxn(blocks) do | |
blocks[i]:draw() | |
end | |
-- Draw score and lives | |
stroke(255, 255, 255, 255) | |
strokeWidth(2) | |
number(10, HEIGHT - 10, score, 10) | |
number(WIDTH - 30, HEIGHT - 10, "x"..lives, 8) | |
noStroke() | |
fill(253, 255, 0, 255) | |
ellipse(WIDTH - 50, HEIGHT - 19, 20) | |
-- Draw win/lose screen | |
if gameover then | |
gameText("LOSE",350,400) | |
elseif won then | |
gameText("WIN",340,400) | |
end | |
emitter:draw() | |
end | |
function touched(touch) | |
if CurrentTouch.state == BEGAN or | |
CurrentTouch.state == MOVING then | |
lastDelta = CurrentTouch.deltaX | |
if gameover == false and won == false then | |
-- If bat is touched launch ball | |
if ballIsMoving == false then | |
if CurrentTouch.x < bat:right() + 10 and | |
CurrentTouch.x > bat:left() - 10 and | |
CurrentTouch.y < bat:top() + 20 and | |
CurrentTouch.y > bat:bottom() then | |
if ballIsMoving == false then | |
ballIsMoving = true | |
end | |
end | |
else | |
-- Otherwise move the bat | |
bat.pos.x = bat.pos.x + lastDelta | |
-- Clamp the bat position | |
bat.pos.x = math.min( bat.pos.x, WIDTH - bat.size.x/2 ) | |
bat.pos.x = math.max( bat.size.x/2, bat.pos.x ) | |
end | |
elseif gameover == true or won == true then | |
-- If centre of screen is touched restart game | |
if CurrentTouch.tapCount == 1 then | |
resetGame() | |
end | |
end | |
end | |
lastDelta = 0 | |
end | |
-- Write game text | |
function gameText(str, x, y) | |
pushStyle() | |
textMode(CENTER) | |
fill(255, 255, 255, 255) | |
font("ArialRoundedMTBold") | |
fontSize(48) | |
text(str,x,y) | |
popStyle() | |
end | |
--# Numbers | |
----------------------------------- | |
-- Functions for drawing numbers -- | |
----------------------------------- | |
-- Draw a number. x, y is top left | |
function number(x, y, n, w) | |
l = string.len(n) | |
for i = 1, l do | |
drawDigit(x + ((i - 1) * (w * 1.5)), y, string.sub(n, i, i), w) | |
end | |
end | |
-- Draw a single digit | |
function drawDigit(x, y, n, w) | |
h = 2 * w | |
if string.match(n, "1") then | |
line(x + (w / 2), y, x + (w / 2), y - h) | |
elseif string.match(n, "2") then | |
line(x, y, x + w, y) | |
line(x + w, y, x + w, y - (h / 2)) | |
line(x + w, y - (h / 2), x, y - (h / 2)) | |
line(x, y - (h / 2), x, y - h) | |
line(x, y - h, x + w, y - h) | |
elseif string.match(n, "3") then | |
line(x, y, x + w, y) | |
line(x + w, y, x + w, y - h) | |
line(x + w, y - h, x, y - h) | |
line(x, y - (h / 2), x + w, y - (h / 2)) | |
elseif string.match(n, "4") then | |
line(x, y, x, y - (h / 2)) | |
line(x, y - (h / 2), x + w, y - (h / 2)) | |
line(x + w, y, x + w, y - h) | |
elseif string.match(n, "5") then | |
line(x + w, y, x, y) | |
line(x, y, x, y - (h / 2)) | |
line(x, y - (h / 2), x + w, y - (h / 2)) | |
line(x + w, y - (h / 2), x + w, y - h) | |
line(x + w, y - h, x, y - h) | |
elseif string.match(n, "6") then | |
line(x + w, y, x, y) | |
line(x, y, x, y - h) | |
line(x, y - h, x + w, y - h) | |
line(x + w, y - h, x + w, y - (h / 2)) | |
line(x + w, y - (h / 2), x, y - (h / 2)) | |
elseif string.match(n, "7") then | |
line(x, y, x + w, y) | |
line(x + w, y, x + w, y - h) | |
elseif string.match(n, "8") then | |
line(x, y, x + w, y) | |
line(x + w, y, x + w, y - h) | |
line(x + w, y - h, x, y - h) | |
line(x, y - h, x, y) | |
line(x, y - (h / 2), x + w, y - (h / 2)) | |
elseif string.match(n, "9") then | |
line(x + w, y - (h / 2), x, y - (h / 2)) | |
line(x, y - (h / 2), x, y) | |
line(x, y, x + w, y) | |
line(x + w, y, x + w, y - h) | |
line(x + w, y - h, x, y - h) | |
elseif string.match(n, "0") then | |
line(x, y, x + w, y) | |
line(x + w, y, x + w, y - h) | |
line(x + w, y - h, x, y - h) | |
line(x, y - h, x, y) | |
elseif string.match(n, "x") then | |
line(x, y - (w / 3), x + w, y - (h + 1)) | |
line(x + w, y - (w / 3), x, y - (h + 1)) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment