Last active
January 2, 2016 02:29
-
-
Save pepinganos/8237374 to your computer and use it in GitHub Desktop.
Board game for Codea. beta 1.0
This file contains 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
--# HighScores | |
HighScore = class() | |
function HighScore:init(score, balls) | |
self.score = score | |
self.balls = balls | |
end | |
function HighScore:getValues() | |
return self.score, self.balls | |
end | |
highScores = {} | |
function setMaxScore(i, s) | |
saveLocalData(i.."score", s) | |
end | |
function setMaxBalls(i, b) | |
saveLocalData(i.."balls", b) | |
end | |
function getMaxScore(i) | |
return readLocalData(i.."score", 0) | |
end | |
function getMaxBalls(i) | |
return readLocalData(i.."balls", 0) | |
end | |
function saveHighScores() | |
for i = 1, 25 do | |
s, b = highScores[i]:getValues() | |
saveLocalData(i.."score", s) | |
saveLocalData(i.."balls", b) | |
end | |
end | |
function loadHighScores() | |
for i = 1, 25 do | |
s = readLocalData(i.."score", 0) | |
b = readLocalData(i.."balls", 0) | |
highScores[i] = HighScore(s, b) | |
end | |
end | |
--# Level | |
Level = class() | |
size = {} | |
function Level:init(duration, colors, ballsOfEach, boardSize) | |
self.duration = duration | |
self.colors = colors | |
self.ballsOfEach = ballsOfEach | |
self.cols = size[boardSize][1] | |
self.rows = size[boardSize][2] | |
end | |
function Level:getValues() | |
return self.duration, self.colors, self.ballsOfEach, self.cols, self.rows | |
end | |
size[1] ={10,7} | |
size[2] ={12,8} | |
size[3] ={14,9} | |
size[4] ={15,10} | |
size[5] ={16,11} | |
size[6] ={18,12} | |
size[7] ={20,14} | |
size[8] ={21,15} | |
size[9] ={22,16} | |
level = {} | |
-- WORLD 1 | |
table.insert(level, Level(120, 4, 12, 1)) | |
table.insert(level, Level(120, 4, 16, 1)) | |
table.insert(level, Level(120, 4, 18, 2)) | |
table.insert(level, Level(120, 4, 20, 2)) | |
table.insert(level, Level(120, 4, 22, 2)) | |
table.insert(level, Level(120, 4, 23, 3)) | |
table.insert(level, Level(120, 4, 25, 3)) | |
table.insert(level, Level(120, 4, 29, 3)) | |
table.insert(level, Level(120, 4, 30, 4)) | |
table.insert(level, Level(120, 4, 34, 4)) | |
table.insert(level, Level(120, 4, 35, 5)) | |
table.insert(level, Level(120, 4, 36, 5)) | |
table.insert(level, Level(120, 4, 40, 5)) | |
table.insert(level, Level(120, 4, 41, 6)) | |
table.insert(level, Level(120, 4, 45, 6)) | |
table.insert(level, Level(120, 4, 49, 6)) | |
table.insert(level, Level(120,4,50,7)) | |
table.insert(level, Level(120,4,57,7)) | |
table.insert(level, Level(120,4,64,7)) | |
table.insert(level, Level(120,4,65,8)) | |
table.insert(level, Level(120,4,70,8)) | |
table.insert(level, Level(120,4,73,8)) | |
table.insert(level, Level(120,4,75,9)) | |
table.insert(level, Level(120,4,79,9)) | |
table.insert(level, Level(120,4,82,9)) | |
-- WORLD 2 | |
table.insert(level, Level(120, 5, 11, 1)) | |
table.insert(level, Level(120, 5, 12, 1)) | |
table.insert(level, Level(120, 5, 13, 2)) | |
table.insert(level, Level(120, 5, 15, 2)) | |
table.insert(level, Level(120, 5, 17, 2)) | |
table.insert(level, Level(120, 5, 18, 3)) | |
table.insert(level, Level(120, 5, 20, 3)) | |
table.insert(level, Level(120, 5, 22, 3)) | |
table.insert(level, Level(120, 5, 23, 4)) | |
table.insert(level, Level(120, 5, 26, 4)) | |
table.insert(level, Level(120, 5, 27, 5)) | |
table.insert(level, Level(120, 5, 30, 5)) | |
table.insert(level, Level(120, 5, 33, 5)) | |
table.insert(level, Level(120, 5, 34, 6)) | |
table.insert(level, Level(120, 5, 35, 6)) | |
table.insert(level, Level(120, 5, 36, 6)) | |
table.insert(level, Level(120, 5, 38, 7)) | |
table.insert(level, Level(120, 5, 40, 7)) | |
table.insert(level, Level(120, 5, 45, 7)) | |
table.insert(level, Level(120, 5, 47, 8)) | |
table.insert(level, Level(120, 5, 49, 8)) | |
table.insert(level, Level(120, 5, 51, 8)) | |
table.insert(level, Level(120, 5, 52, 9)) | |
table.insert(level, Level(120, 5, 57, 9)) | |
table.insert(level, Level(120, 5, 60, 9)) | |
-- WORLD 3 | |
table.insert(level, Level(120, 6, 9, 1)) | |
table.insert(level, Level(120, 6, 11, 1)) | |
table.insert(level, Level(120, 6, 13, 2)) | |
table.insert(level, Level(120, 6, 14, 2)) | |
table.insert(level, Level(120, 6, 15, 2)) | |
table.insert(level, Level(120, 6, 18, 3)) | |
table.insert(level, Level(120, 6, 19, 3)) | |
table.insert(level, Level(120, 6, 20, 3)) | |
table.insert(level, Level(120, 6, 23, 4)) | |
table.insert(level, Level(120, 6, 24, 4)) | |
table.insert(level, Level(120, 6, 27, 5)) | |
table.insert(level, Level(120, 6, 28, 5)) | |
table.insert(level, Level(120, 6, 29, 5)) | |
table.insert(level, Level(120, 6, 31, 6)) | |
table.insert(level, Level(120, 6, 34, 6)) | |
table.insert(level, Level(120, 6, 35, 6)) | |
table.insert(level, Level(120, 6, 38, 7)) | |
table.insert(level, Level(120, 6, 40, 7)) | |
table.insert(level, Level(120, 6, 45, 7)) | |
table.insert(level, Level(120, 6, 47, 8)) | |
table.insert(level, Level(120, 6, 49, 8)) | |
table.insert(level, Level(120, 6, 51, 8)) | |
table.insert(level, Level(120, 6, 52, 9)) | |
table.insert(level, Level(120, 6, 55, 9)) | |
table.insert(level, Level(120, 6, 67, 9)) | |
-- WORLD 4 | |
table.insert(level, Level(120, 7, 7, 1)) | |
table.insert(level, Level(120, 7, 8, 1)) | |
table.insert(level, Level(120, 7, 8, 2)) | |
table.insert(level, Level(120, 7, 9, 2)) | |
table.insert(level, Level(120, 7, 10, 2)) | |
table.insert(level, Level(120, 7, 11, 3)) | |
table.insert(level, Level(120, 7, 12, 3)) | |
table.insert(level, Level(120, 7, 13, 3)) | |
table.insert(level, Level(120, 7, 14, 4)) | |
table.insert(level, Level(120, 7, 15, 4)) | |
table.insert(level, Level(120, 7, 16, 5)) | |
table.insert(level, Level(120, 7, 17, 5)) | |
table.insert(level, Level(120, 7, 18, 5)) | |
table.insert(level, Level(120, 7, 19, 6)) | |
table.insert(level, Level(120, 7, 20, 6)) | |
table.insert(level, Level(120, 7, 21, 6)) | |
table.insert(level, Level(120, 7, 22, 7)) | |
table.insert(level, Level(120, 7, 23, 7)) | |
table.insert(level, Level(120, 7, 24, 7)) | |
table.insert(level, Level(120, 7, 26, 8)) | |
table.insert(level, Level(120, 7, 27, 8)) | |
table.insert(level, Level(120, 7, 28, 8)) | |
table.insert(level, Level(120, 7, 29, 9)) | |
table.insert(level, Level(120, 7, 30, 9)) | |
table.insert(level, Level(120, 7, 31, 9)) | |
-- WORLD 5 | |
table.insert(level, Level(120, 8, 7, 1)) | |
table.insert(level, Level(120, 8, 8, 1)) | |
table.insert(level, Level(120, 8, 9, 2)) | |
table.insert(level, Level(120, 8, 10, 2)) | |
table.insert(level, Level(120, 8, 11, 2)) | |
table.insert(level, Level(120, 8, 12, 3)) | |
table.insert(level, Level(120, 8, 13, 3)) | |
table.insert(level, Level(120, 8, 14, 3)) | |
table.insert(level, Level(120, 8, 15, 4)) | |
table.insert(level, Level(120, 8, 16, 4)) | |
table.insert(level, Level(120, 8, 17, 5)) | |
table.insert(level, Level(120, 8, 18, 5)) | |
table.insert(level, Level(120, 8, 20, 5)) | |
table.insert(level, Level(120, 8, 22, 6)) | |
table.insert(level, Level(120, 8, 24, 6)) | |
table.insert(level, Level(120, 8, 25, 6)) | |
table.insert(level, Level(120, 8, 26, 7)) | |
table.insert(level, Level(120, 8, 27, 7)) | |
table.insert(level, Level(120, 8, 28, 7)) | |
table.insert(level, Level(120, 8, 32, 8)) | |
table.insert(level, Level(120, 8, 35, 8)) | |
table.insert(level, Level(120, 8, 36, 8)) | |
table.insert(level, Level(120, 8, 38, 9)) | |
table.insert(level, Level(120, 8, 40, 9)) | |
table.insert(level, Level(120, 8, 42, 9)) | |
--# Board | |
Board = class() | |
offsetX = 50 | |
offsetY = 50 | |
oldCellSize = 0 | |
maxBombs = 3 | |
gameTime = 1000 | |
ballBitmap = {} | |
colors = {color(212, 220, 26, 255),color(230, 17, 17, 255),color(100, 211, 111, 255),color(35, 36, 181, 255),color(226, 113, 9, 255),color(17, 230, 219, 255),color(236, 23, 203, 255),color(49, 120, 21, 255)} | |
effect1=0 | |
cell = {} | |
cellBackup = {} | |
ballsBeingDestroyed = {} | |
boardCell = {} | |
boardCellEffect = {} | |
boardMeshDef = {} | |
messages = {} | |
North = vec2(0, 1) | |
East = vec2(1, 0) | |
South = vec2(0, -1) | |
West = vec2(-1, 0) | |
function Board:init() | |
end | |
function initialise() | |
for x = 1, cols do --initialise multidimensional arrays | |
boardCell[x] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} | |
boardCellEffect[x] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} | |
boardMeshDef[x] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} | |
end | |
spriteMode(CENTER) | |
for i = 1, nbcolors do | |
ballBitmap[i] = raytraceBall(100, colors[i]) | |
end | |
for y = 1, rows do | |
for x = 1, cols do | |
local a = x * 255 / cols | |
local b = 255 - y * 255 / rows | |
boardCell[x][y] = (a+b)/2 | |
boardCellEffect[x][y] = (a+b)/2 | |
end | |
end | |
end | |
function raytraceBall(size, c) | |
local img=image(size,size) | |
x=size/2 | |
y=x | |
setContext(img) | |
background(0, 0, 0, 0) | |
noStroke() | |
despl=1.3 | |
fill(0, 0, 0, 100) | |
ellipse(x+size*.02, y-size*.02, size*.95) | |
fill(c.r,c.g,c.b, 255) | |
ellipse(x,y,size*.95) | |
for i = 1, size/4 do | |
fill(216, 216, 216, i/size*255) | |
ellipse(x-i*despl,y+i*despl,size-i*4) | |
end | |
setContext() | |
return img | |
end | |
function generateBoard() | |
if cellSize ~= oldCellSize then | |
oldCellSize = cellSize | |
boardMesh = mesh() | |
local t = image(1,1) | |
t:set(1,1,255,255,255) | |
boardMesh.texture = t | |
local c = cellSize | |
for y = 1, rows do | |
for x = 1, cols do | |
boardMeshDef[x][y]=boardMesh:addRect(offsetX+(x-1)*c+c/2, offsetY+(y-1)*c+c/2, c-2, c-2) | |
end | |
end | |
end | |
end | |
function Board:draw() | |
cellSize = (WIDTH-offsetX*2)/cols | |
generateBoard() | |
noStroke() | |
background(255, 204, 0) | |
topOfBoard = offsetY+cellSize*rows+16 | |
rightOfTheBoard = offsetX+cellSize*cols | |
--Draw board | |
strokeWidth(1) | |
for y = 1, rows do | |
for x = 1, cols do | |
if boardCellEffect[x][y] < 0 then boardCellEffect[x][y] = 0 end | |
if boardCellEffect[x][y] > 255 then boardCellEffect[x][y] = 255 end | |
--fill(boardCellEffect[x][y]) | |
c = color(boardCellEffect[x][y],boardCellEffect[x][y],boardCellEffect[x][y],255) | |
boardMesh:setRectColor(boardMeshDef[x][y], c) | |
if boardCellEffect[x][y] < boardCell[x][y] then | |
boardCellEffect[x][y] = boardCellEffect[x][y] + 1 | |
end | |
if boardCellEffect[x][y] > boardCell[x][y] then | |
boardCellEffect[x][y] = boardCellEffect[x][y] - 1 | |
end | |
--rect(offsetX + (x-1)*cellSize, offsetY + (y-1)*cellSize, cellSize, cellSize) | |
end | |
end | |
boardMesh:draw() | |
--Draw balls | |
for y = 1, rows do | |
for x = 1, cols do | |
if cell[x][y] ~= 0 then | |
drawBall(x, y, cell[x][y], 10) | |
end | |
end | |
end | |
--Draw disappearing balls | |
for i, ball in ipairs(ballsBeingDestroyed) do | |
drawBall(ball.col, ball.row, ball.type, ball.size) | |
ball.size = ball.size-1 | |
if ball.size < 0 then | |
table.remove(ballsBeingDestroyed, i) | |
end | |
end | |
--Draw messages | |
for i, m in ipairs(messages) do | |
m:draw() | |
if m.life < 0 then | |
table.remove(messages, i) | |
end | |
end | |
--Draw score | |
fill(0) | |
fontSize(16) | |
textAlign(RIGHT) | |
text("SCORE " .. score, 100, topOfBoard) | |
--Draw gameTimer | |
--print(lastTime) | |
if (state=="GAME_SCR") then | |
diff = os.clock()-lastTime | |
if diff>0 then | |
gameTime=gameTime-diff --if diff is <0, the system clock has been reseted | |
end | |
lastTime=os.clock() | |
if gameTime < 0 then | |
composeEndScreen() | |
state = "END_SCR" | |
end | |
if gameTime < timeAlert then | |
timeAlert = timeAlert - .5 | |
sound(SOUND_HIT, 29462) | |
end | |
end | |
--Draw score | |
fill(100) | |
rect (318,topOfBoard-8,204,20) | |
percentgameTime=100*gameTime/gameDuration | |
fill(2.5*(100-percentgameTime),2.5*percentgameTime,0) | |
rect (320,topOfBoard-6,percentgameTime*2,16) | |
--Draw serie | |
fill(0) | |
text("SERIES " .. serie, 250, topOfBoard) | |
--Draw "MENU" button | |
fill(201, 255, 0, 255) | |
stroke(236, 11, 11, 255) | |
strokeWidth(3) | |
rect(rightOfTheBoard-100, topOfBoard-10, 100, 40) | |
fill(0) | |
text("MENU", rightOfTheBoard-50, topOfBoard+9) | |
--Draw bombs | |
fill(140, 140, 140, 255) | |
rect(rightOfTheBoard-400-3, topOfBoard-10-3, 250, 46) | |
if bombs > 0 then | |
if bombArmed then | |
fill(250, 109, 13, 255) | |
rect(rightOfTheBoard-400, topOfBoard-10, 244, 40) | |
fontSize(25) | |
fill(223, 216, 159, 255) | |
text("Bomb armed", rightOfTheBoard-400+125, topOfBoard-10+20) | |
else | |
fill(212, 249, 13, 255) | |
rect(rightOfTheBoard-400, topOfBoard-10, 244/3*bombs, 40) | |
fill(51, 34, 213, 255) | |
fontSize(25) | |
text("Throw a bomb", rightOfTheBoard-400+125, topOfBoard-10+20) | |
end | |
else | |
fill(193, 193, 193, 255) | |
text("Match 3 balls to get a bomb", rightOfTheBoard-400+125, topOfBoard-10+20) | |
end | |
--Effect 1 | |
if effect1>0 then | |
for row=1, rows do | |
boardCellEffect[effect1][row] = boardCell[effect1][row] + 70 | |
--boardCellEffect[effect1][row] = boardCell[effect1][row] + math.random(100)-50 | |
end | |
effect1=effect1+1 | |
if effect1>cols then effect1 = 0 end | |
end | |
end | |
function drawBall(x, y, type, scale) | |
sprite(ballBitmap[type],offsetX+cellSize*(x-.5),offsetY+cellSize*(y-.5),cellSize*scale/11) | |
end | |
function Board:touched(touch) | |
t=topOfBoard --names are too long... | |
r=rightOfTheBoard | |
if touch.x > rightOfTheBoard-100 and touch.y > topOfBoard-10 then | |
state="PAUSE_SCR" | |
elseif touch.x>r-403 and touch.x<r-153 and touch.y>t-13 and bombs > 0 then | |
if bombArmed then | |
bombArmed = false | |
sound(SOUND_RANDOM, 30627) | |
else | |
bombArmed = true | |
sound(SOUND_POWERUP, 36772) | |
end | |
else | |
local x = touch.x - offsetX | |
local y = touch.y - offsetY | |
local col = math.floor(x / cellSize) + 1 | |
local row = math.floor(y / cellSize) + 1 | |
if col < 1 or col > cols or row < 1 or row > rows then return end | |
local hit = false | |
if bombArmed then | |
bombExplodes(col, row) | |
hit = true | |
else | |
if (cell[col][row] == 0) then --if cell is empty, then play | |
boardCellEffect[col][row] = boardCell[col][row] + 50 | |
intersects = {} | |
for c = 1, nbcolors do | |
intersects[c] = {} | |
end | |
testCell(col, row, North) | |
testCell(col, row, East) | |
testCell(col, row, South) | |
testCell(col, row, West) | |
for i, t in ipairs(intersects) do | |
if #t > 1 then --hit | |
hit = true | |
if #t == 3 and bombs < maxBombs then | |
bombs = bombs + 1 | |
sound(SOUND_POWERUP, 47571) | |
table.insert(messages, Message("Bomb aquired")) | |
elseif #t == 4 then | |
crossBombExplodes(col,row) | |
end | |
score = score + #t * #t | |
for c = 1, #t do | |
cell[t[c].col] [t[c].row] = 0 | |
table.insert(ballsBeingDestroyed, t[c]) | |
end | |
end | |
end | |
else | |
table.insert(messages, Message("Don't touch the balls!!!")) --Testing *************** | |
sound(SOUND_RANDOM, 25222) | |
return --do nothing!!! | |
end | |
end | |
if hit then | |
serie = serie + 1 | |
if serie > longestSerie then longestSerie = serie end | |
sound(SOUND_HIT, 33819) | |
else -- missed!! | |
serie = 0 | |
sound(DATA, "ZgFAEgBAQEBAQEBAAAAAAJOJjj6oKQo+fwBAf0BGQEBAQEBA") | |
end | |
if areTherePossibleMoves() == false then | |
if bombs == 0 then --Game Over: No moves, no bombs | |
composeEndScreen() | |
state="END_SCR" | |
else | |
table.insert(messages, Message("Use the bombs")) | |
end | |
end | |
if ballsLeft() == 0 then --Victory | |
composeEndScreen() | |
state="END_SCR" | |
end | |
end | |
end | |
function crossBombExplodes(col,row) | |
sound(SOUND_EXPLODE, 21) | |
for y = 1, rows do | |
for x = 1, cols do | |
boardCellEffect[x][y] = boardCell[x][y] + 80 | |
end | |
end | |
for y = 1, rows do | |
cell[col][y]=0 | |
table.insert(ballsBeingDestroyed, Ball(col,y,1,math.random(20)+10)) | |
end | |
for x = 1, cols do | |
cell[x][row]=0 | |
table.insert(ballsBeingDestroyed, Ball(x,row,1,math.random(20)+10)) | |
end | |
end | |
function composeEndScreen() | |
sound(DATA, "ZgFAOAAvR2QwP1Zu7EPpPdQZeD/ENqi+TgB8ajhAUCp/UQIR") | |
endSCR = Interface() --reset object | |
endSCR:addLabel(3, "Game Over", 50) | |
endSCR:addButton(15, "Restart", "restart") | |
endSCR:addButton(16.5, "New Game", "goToSplashScreen") | |
endSCR:addLabel(5, "Simple Score: " .. score, 30) | |
endSCR:addLabel(6, "Thrown Bombs: " .. thrownBombs .. " x 20 = " .. thrownBombs*20, 30) | |
endSCR:addLabel(7, "Longest Series: " .. longestSerie.." x 4 = "..longestSerie*4, 30) | |
if currentLevel < nbLevels() then | |
endSCR:addButton(18, "Next Level", "nextLevel") | |
else | |
endSCR:addLabel(18, "This was the Last Level") | |
end | |
local bl = ballsLeft() | |
local s = score+thrownBombs*20+longestSerie*4 | |
if bl == 0 then | |
endSCR:addLabel(8, "Time Left: "..math.floor(gameTime).." seconds x 4 = "..math.floor(gameTime)*4, 30) | |
s = s + math.floor(gameTime)*4 | |
end | |
if s > getMaxScore(currentLevel) then setMaxScore(currentLevel, s) end | |
local b = nbcolors*ballsOfEach-bl | |
if b > getMaxBalls(currentLevel) then setMaxBalls(currentLevel, b) end | |
endSCR:addLabel(9, "Big Score: "..s, 40) | |
end | |
function bombExplodes(col, row) | |
bombArmed = false | |
bombs = bombs - 1 | |
thrownBombs = thrownBombs + 1 | |
sound(DATA, "ZgNAEQBAQEBAQEBAAAAAADf+vj4GOAk/aQBAf0BAQEBAQEBA") | |
for y = row - 1, row +1 do | |
for x = col - 1, col + 1 do | |
if x>0 and x<=cols and y>0 and y<=rows then | |
table.insert(ballsBeingDestroyed, Ball(x,y,1,math.random(20)+10)) | |
if cell[x][y] > 0 then score = score + 2 end | |
boardCellEffect[x][y] = boardCell[x][y] + 50 | |
cell[x][y] = 0 | |
end | |
end | |
end | |
end | |
function testCell(x, y, vel) | |
local pos = vec2(x,y) | |
local content = 0 | |
while pos.x > 0 and pos.x < cols + 1 and pos.y > 0 and pos.y < rows + 1 and content == 0 do | |
content = cell[pos.x][pos.y] | |
pos = pos + vel | |
if content > 0 then | |
pos = pos - vel | |
table.insert(intersects[content], Ball(pos.x, pos.y, content)) | |
return | |
end | |
end | |
end | |
function areTherePossibleMoves() | |
for row = 1, rows do | |
for col = 1, cols do | |
if isCasePlayable(col, row) then return true end | |
end | |
end | |
return false | |
end | |
function isCasePlayable(col, row) | |
intersects = {} | |
for c = 1, nbcolors do | |
intersects[c] = {} | |
end | |
if (cell[col][row] == 0) then --if cell is empty, then test | |
testCell(col, row, North) | |
testCell(col, row, East) | |
testCell(col, row, South) | |
testCell(col, row, West) | |
for i, t in ipairs(intersects) do | |
if #t > 1 then | |
return true | |
end | |
end | |
return false | |
end | |
end | |
function ballsLeft() | |
local bl = 0 | |
for row = 1, rows do | |
for col = 1, cols do | |
if cell[col][row] ~= 0 then bl = bl + 1 end | |
end | |
end | |
return bl | |
end | |
function populate() | |
local max = 25000 --"life insurance" | |
for x = 1, cols do --initialise multidimensional arrays | |
cell[x] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} | |
cellBackup[x] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} | |
end | |
for c = 1, nbcolors do | |
for i = 1, ballsOfEach do | |
x = math.random(cols) | |
y = math.random(rows) | |
while (cell[x][y] ~= 0) do --Find an empty cell | |
max = max -1 | |
if max <= 0 then break end --Avoid endless loop | |
x = math.random(cols) | |
y = math.random(rows) | |
end | |
cell[x][y]=c --Put a ball on it | |
end | |
end | |
store() --So you can retry the same game again | |
end | |
function Board:start(lev) | |
currentLevel = lev | |
gameDuration, nbcolors, ballsOfEach, cols, rows = level[lev]:getValues() | |
state="GAME_SCR" | |
gameTime = gameDuration --gameTime limit for a game in seconds | |
lastTime=os.clock() | |
initialise() | |
populate() | |
restartVars() | |
end | |
function Board:restart() | |
state="GAME_SCR" | |
gameTime = gameDuration --gameTime limit for a game in seconds | |
lastTime=os.clock() | |
restore() | |
restartVars() | |
effect1=1 | |
end | |
function Board:resume() | |
state="GAME_SCR" | |
lastTime=os.clock() | |
end | |
function restartVars() | |
score=0 | |
serie = 0 --hits in a row | |
bombs = 0 | |
bombArmed = false | |
thrownBombs = 0 | |
longestSerie = 0 | |
timeAlert = 3 | |
end | |
function store() | |
for y = 1, rows do | |
for x = 1, cols do | |
cellBackup[x][y]=cell[x][y] | |
end | |
end | |
end | |
function restore() | |
for y = 1, rows do | |
for x = 1, cols do | |
cell[x][y]=cellBackup[x][y] | |
end | |
end | |
score=0 | |
end | |
Ball = class() | |
--Constructor | |
function Ball:init(c, r, t, size) | |
self.col=c | |
self.row=r | |
self.type=t | |
self.size=size or 10 --only used in ballsBeingDestroyed | |
end | |
--# Interface | |
Interface = class() | |
local x=WIDTH/2 | |
local w=300 | |
local h=40 | |
function Interface:init() -- Constructor | |
self.buttons = {} | |
self.labels = {} | |
end | |
function Interface:addButton(line, txt, id) | |
table.insert(self.buttons,Button(line, txt, id)) | |
end | |
function Interface:addLabel(line, txt, size) | |
table.insert(self.labels,Label(line, txt, size)) | |
end | |
function Interface:draw() | |
x=WIDTH/2 | |
noStroke() | |
fill(150,150,150,100) | |
rect(0,0,WIDTH,HEIGHT) | |
for i, button in ipairs(self.buttons) do | |
button:draw() | |
end | |
for i, label in ipairs(self.labels) do | |
label:draw() | |
end | |
end | |
function Interface:touched(touch) | |
local xb=touch.x | |
local yb=touch.y | |
ellipse(xb,yb,50,50) | |
for i, button in ipairs(self.buttons) do | |
if xb>x-w/2 and xb<x+w/2 and yb>HEIGHT-button.line*h and yb<HEIGHT-(button.line-1)*h then | |
sound(SOUND_BLIT, 33372) | |
return button.id | |
end | |
end | |
return "background" | |
end | |
---------------- | |
Button = class() | |
function Button:init(line, txt, id) -- Constructor | |
self.line=line | |
self.txt=txt | |
self.id=id | |
end | |
function Button:draw() | |
strokeWidth(2) | |
fill(255,150,150) | |
rect(x-w/2,HEIGHT-self.line*h,w,h) | |
font("Arial-BoldMT") | |
fill(0,0,255) | |
fontSize(35) | |
textAlign(CENTER) | |
text(self.txt, x,HEIGHT-(self.line-.5)*h) | |
end | |
---------------- | |
Label = class() | |
function Label:init(line, txt, size) -- Constructor | |
self.line=line | |
self.txt=txt | |
self.size=size | |
end | |
function Label:draw() | |
fontSize(self.size) | |
textAlign(CENTER) | |
fill(2, 2, 2, 205) | |
text(self.txt, x+2,HEIGHT-(self.line-.5)*h-3) | |
fill(255, 232, 0, 255) | |
text(self.txt, x,HEIGHT-(self.line-.5)*h) | |
end | |
---------------- | |
--# LevelSelect | |
LevelSelect = class() | |
function LevelSelect:init(title, firstLevel, nbLevels) | |
self.title = title | |
self.firstLevel = firstLevel | |
self.nbLevels = nbLevels | |
end | |
function LevelSelect:draw() | |
myWidth = WIDTH * 0.9 | |
myHeight = HEIGHT * 0.8 | |
myLeft = (WIDTH - myWidth)/2 | |
myTop = myHeight + (HEIGHT - myHeight)/2 | |
bw = myWidth/5 * 0.9 --button width | |
bh = myHeight/5 * 0.85 | |
xSpace = (1.2 * myWidth - bw) / 5 -- == myWidth/5 + (myWidth/5-bw)/5 | |
ySpace = myHeight / 5 | |
sd = bw * 0.07 --shadow displacement | |
noStroke() | |
fill(124, 124, 124, 218) | |
rect(0,0,WIDTH,HEIGHT) | |
fill(0, 0, 0, 155) | |
fontSize(45) | |
text(self.title, WIDTH/2+3, HEIGHT*0.95-3) | |
fill(255, 217, 0, 255) | |
text(self.title, WIDTH/2, HEIGHT*0.95) | |
fill(0, 0, 0, 155) | |
fontSize(45) | |
text("Back to Main Menu", WIDTH*2/3+3, HEIGHT*0.05-3) | |
fill(255, 0, 0, 255) | |
text("Back to Main Menu", WIDTH*2/3, HEIGHT*0.05) | |
i=self.firstLevel | |
for y = 0,4 do | |
for x = 0,4 do | |
fill(0, 0, 0, 97) | |
rect(myLeft+x*xSpace+sd, myTop-y*ySpace-bh-sd, bw, bh) | |
fill(223, 183, 137, 255) | |
rect(myLeft+x*xSpace, myTop-y*ySpace-bh, bw, bh) | |
fill(28, 30, 59, 255) | |
fontSize(22) | |
text(i, myLeft+x*xSpace+bw/6, myTop-y*ySpace-bh/5) | |
local s=getMaxScore(i) | |
local b=getMaxBalls(i) | |
local tb=level[i].colors*level[i].ballsOfEach | |
text("Score: "..s, myLeft+x*xSpace+bw/2, myTop-y*ySpace-bh/2) | |
text(b.."/"..tb, myLeft+x*xSpace+bw/2, myTop-y*ySpace-bh/1.3) | |
drawStars(b, tb, myLeft+x*xSpace+bw/2.3, myTop-y*ySpace-bh/5) | |
i = i + 1 | |
if i > self.firstLevel + self.nbLevels - 1 then return end | |
end | |
end | |
end | |
function drawStars(balls, totalBalls, x, y) | |
nbStars = 0 | |
if balls > totalBalls/2 then nbStars = nbStars + 1 end | |
if balls > totalBalls*3/4 then nbStars = nbStars + 1 end | |
if balls == totalBalls then nbStars = nbStars + 1 end | |
for i = 0, nbStars - 1 do | |
sprite("SpaceCute:Star", x+i*25, y, 40) | |
end | |
end | |
function LevelSelect:touched(touch) | |
myWidth = WIDTH * 0.9 | |
myHeight = HEIGHT * 0.8 | |
myLeft = (WIDTH - myWidth)/2 | |
myTop = myHeight + (HEIGHT - myHeight)/2 | |
bw = myWidth/5 * 0.9 --button width | |
bh = myHeight/5 * 0.85 | |
xSpace = (1.2 * myWidth - bw) / 5 -- == myWidth/5 + (myWidth/5-bw)/5 | |
ySpace = myHeight / 5 | |
x=touch.x-myLeft | |
y=myTop-touch.y | |
if x>0 and x<myWidth and y>0 and y<myHeight then | |
col = math.floor(x/xSpace) | |
row = math.floor(y/ySpace) | |
bSelected = row*5+col+1 | |
return bSelected + self.firstLevel - 1 | |
else return 0 | |
end | |
end | |
--# Main | |
-- Main | |
displayMode(FULLSCREEN) | |
mainSCR = Interface() | |
pauseSCR = Interface() | |
board = Board() | |
levelSelSCR = {} | |
levelSelSCR[1]= LevelSelect("World 1: 4 colors", 1, 25) | |
levelSelSCR[2]= LevelSelect("World 2: 5 colors", 26, 25) | |
levelSelSCR[3]= LevelSelect("World 3: 6 colors", 51, 25) | |
levelSelSCR[4]= LevelSelect("World 4: 7 colors", 76, 25) | |
levelSelSCR[5]= LevelSelect("World 5: 8 colors", 101, 25) | |
function nbLevels() | |
local total = 0 | |
for i, l in ipairs(levelSelSCR) do | |
total = total + l.nbLevels | |
end | |
return total | |
end | |
function setup() | |
--clearLocalData() | |
mainSCR:addLabel(3, "Small Balls", 50) | |
mainSCR:addButton(5, "World 1: 4 colors", "start1") | |
mainSCR:addButton(6.2, "World 2: 5 colors", "start2") | |
mainSCR:addButton(7.4, "World 3: 6 colors", "start3") | |
mainSCR:addButton(8.6, "World 4: 7 colors", "start4") | |
mainSCR:addButton(9.8, "World 5: 8 colors", "start5") | |
mainSCR:addLabel(12, "How to play", 50) | |
mainSCR:addLabel(14, "Try to eliminate all the balls", 25) | |
mainSCR:addLabel(15, "by touching empty cases that are connected vertically or horizontally", 20) | |
mainSCR:addLabel(16, "with two or more balls which are the same color.", 20) | |
mainSCR:addLabel(17, "-Matching 3 balls gives you a Bomb", 20) | |
mainSCR:addLabel(18, "-Matching 4 balls explodes a special Cross Bomb", 20) | |
pauseSCR:addLabel(3, "The game is paused", 50) | |
pauseSCR:addButton(5, "Resume", "resume") | |
pauseSCR:addButton(7, "Restart", "restart") | |
pauseSCR:addButton(9, "New game", "goToSplashScreen") | |
pauseSCR:addLabel(12, "How to play", 50) | |
pauseSCR:addLabel(14, "Try to eliminate all the balls", 25) | |
pauseSCR:addLabel(15, "by touching empty cases that are connected vertically or horizontally", 20) | |
pauseSCR:addLabel(16, "with two or more balls which are the same color", 20) | |
pauseSCR:addLabel(17, "-Matching 3 balls gives you a Bomb", 20) | |
pauseSCR:addLabel(18, "-Matching 4 balls explodes a special Cross Bomb", 20) | |
board:start(25) | |
state="MAIN_SCR" | |
end | |
function draw() | |
board:draw() | |
if state=="MAIN_SCR" then | |
mainSCR:draw() | |
elseif state=="PAUSE_SCR" then | |
pauseSCR:draw() | |
elseif state=="END_SCR" then | |
endSCR:draw() | |
elseif state=="LEVEL_SCR" then | |
levelSelSCR[world]:draw() | |
end | |
end | |
function touched(touch) | |
if touch.state == ENDED then | |
if state=="GAME_SCR" then | |
board:touched(touch) | |
return | |
end | |
--Get "answer" from menus | |
answer = "" | |
if state=="MAIN_SCR" then | |
answer = mainSCR:touched(touch) | |
elseif (state=="PAUSE_SCR") then | |
answer = pauseSCR:touched(touch) | |
elseif (state=="END_SCR") then | |
answer = endSCR:touched(touch) | |
elseif state=="LEVEL_SCR" then | |
answer = levelSelSCR[world]:touched(touch) | |
if answer ~= 0 then | |
board:start(answer) | |
effect1=1 | |
table.insert(messages, Message("Level "..currentLevel)) | |
else state="MAIN_SCR" end | |
end | |
--Treat "answer" | |
if answer=="start1" then | |
state="LEVEL_SCR" | |
world = 1 | |
elseif answer=="start2" then | |
state="LEVEL_SCR" | |
world = 2 | |
elseif answer=="start3" then | |
state="LEVEL_SCR" | |
world = 3 | |
elseif answer=="start4" then | |
state="LEVEL_SCR" | |
world = 4 | |
elseif answer=="start5" then | |
state="LEVEL_SCR" | |
world = 5 | |
elseif answer=="restart" then | |
board:restart() | |
elseif answer=="resume" then | |
board:resume() | |
elseif answer=="nextLevel" then | |
board:start(currentLevel + 1) | |
effect1=1 | |
table.insert(messages, Message("Level "..currentLevel)) | |
elseif answer=="goToSplashScreen" then | |
state="MAIN_SCR" | |
end | |
end | |
end | |
--# Message | |
Message = class() | |
maxLife = 60 | |
function Message:init(message,x,y,size,mColor) | |
self.message = message or "abcdefg" | |
self.x = x or WIDTH/2 | |
self.y = y or HEIGHT/2 | |
self.color = mColor or color(255, 231, 0, 255) | |
self.size = size or 50 | |
self.life = maxLife | |
end | |
function Message:draw() | |
self.life = self.life - 1 | |
fontSize(self.size) | |
fill(0,0,0, (self.life)/maxLife*255) | |
text(self.message, self.x+2, self.y-3+maxLife-self.life) | |
fill(self.color.r,self.color.g,self.color.b, (self.life)/maxLife*255+50) | |
text(self.message, self.x, self.y+maxLife-self.life) | |
end | |
--# Notes |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment