Skip to content

Instantly share code, notes, and snippets.

@simsaens
Created August 4, 2012 06:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simsaens/3255183 to your computer and use it in GitHub Desktop.
Save simsaens/3255183 to your computer and use it in GitHub Desktop.
Brickout Enhanced
--# 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