Created
December 12, 2012 22:06
-
-
Save AntonioCiolino/4272076 to your computer and use it in GitHub Desktop.
TicTacToe - simple TicTacToe game
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
TicTacToe for Codea |
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
-- | |
-- Explode.lua | |
-- | |
-- subset of the old school explode code form forums | |
NUMSTARS = 50 | |
COLOURS = { | |
color(255, 0, 0, 125), | |
color(255, 227, 0, 125), | |
color(99, 255, 0, 125), | |
color(0, 140, 255, 125), | |
color(238, 0, 255, 125), | |
color(255, 156, 0, 125), | |
color(0, 255, 189, 125), | |
color(255, 0, 146, 125) | |
} | |
-- iparameter("Stars",0,1,1) | |
-- number of particles of each firework | |
iparameter("Firework_Parts",0,500,100) | |
iparameter("Life",0,100,30) | |
iparameter("Life_Variation",0,100,100) | |
parameter("Air_Resistance",0,1,0.1) | |
iparameter("PartSize",0,100,35) | |
iparameter("PartSize_Variation",0,100,50) | |
parameter("Velocity",0,50,50) | |
iparameter("Velocity_Variation",0,100,100) | |
iparameter("Color_Variation",0,100,50) | |
--watch("DeltaTime") | |
Explode = class() | |
function Explode:init() | |
self.fireworks={} | |
end | |
function Explode:draw() | |
-- draw fireworks | |
for k,fw in pairs(self.fireworks) do | |
if fw:isDead() then | |
self.fireworks[k] = nil | |
else | |
pushStyle() | |
fw:draw() | |
popStyle() | |
end | |
end | |
end | |
function Explode:createFirework(x,y,color) | |
--local pos = self:freePos(self.fireworks) | |
self.fireworks[#self.fireworks+1] = Firework(x,y,color) | |
end | |
function Explode:freePos(list) | |
return self:freePosRecursive(list,1) | |
end | |
function Explode:freePosRecursive(list,n) | |
if list[n] == nil then | |
return n | |
else | |
return self:freePosRecursive(list,n+1) | |
end | |
end |
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
-- | |
-- Firework.lua | |
-- | |
Firework = class() | |
function Firework:init(x,y,colour) | |
-- you can accept and set parameters here | |
self.p = {} | |
self.numParticles = Firework_Parts | |
for i=1,self.numParticles do | |
local psize = genNumber(PartSize,PartSize_Variation) | |
local v = vec2(math.random(-100,100),math.random(-100,100)) | |
v = v:normalize() | |
v = v * genNumber(Velocity,Velocity_Variation) | |
local c = color(genNumber(colour.r,Color_Variation), | |
genNumber(colour.g,Color_Variation), | |
genNumber(colour.b,Color_Variation), | |
colour.a | |
) | |
self.p[i] = Particle(x, | |
y, | |
psize, | |
genNumber(Life,Life_Variation), | |
c, | |
v) | |
--self.p[i].sprite = Sprite:GetImage() | |
end | |
end | |
function Firework:draw() | |
local resistance = 1/(Air_Resistance + 1) | |
local g = vec2(Gravity.x,Gravity.y) | |
for i=1,self.numParticles do | |
local p = self.p[i] | |
p.x = p.x + p.v.x | |
p.y = p.y + p.v.y | |
p.v = p.v + g | |
p.v = p.v * resistance | |
local size = math.random(PartSize) * (p.lifeLeft/p.life) | |
p.width = size | |
p.height = size | |
p:draw() | |
end | |
end | |
function Firework:isDead() | |
for i=1,self.numParticles do | |
p = self.p[i] | |
if p.lifeLeft ~= 0 and | |
(p.x>0 and p.x<WIDTH and p.y>0 and p.y<HEIGHT)then | |
return false | |
end | |
end | |
return true | |
end |
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
-- | |
-- FlashText.lua | |
-- | |
FlashText = class() | |
-- used to display a score on the screen. builds ina delay for x secs. | |
function FlashText:init(params) | |
-- you can accept and set parameters here | |
self.time = params.time or 5 --seconds | |
self.text = params.text or "..." -- display text | |
self.pos = params.pos -- where in the world to show it. | |
self.fontsize = params.fontsize or 48 | |
self.startTime = nil | |
self:start() -- auto start | |
end | |
function FlashText:start() | |
self.startTime = ElapsedTime | |
end | |
-- false means its done and should be purged. | |
function FlashText:active() | |
if self.startTime == nil then return false end | |
return ElapsedTime - self.startTime < self.time | |
end | |
function FlashText:draw() | |
if self.startTime == nil then return end | |
if ElapsedTime - self.startTime < self.time then | |
pushStyle() | |
font("MyriadPro-Bold") | |
fontSize(self.fontsize) | |
r=math.random(255) | |
g=math.random(255) | |
b=math.random(255) | |
fill(r,g,b,255) | |
text(self.text, self.pos.x, self.pos.y) | |
popStyle() | |
end | |
end | |
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
-- | |
-- GameFunctions.lua | |
-- | |
--this file contains all of the needed functions to drive the game | |
function SetDisplayMode() | |
debug = true --can be used to do logging, etc. set to false to supress msgs | |
production = false --for the "real deal" | |
-- release as this - don't do in Codea or else you can't get back to code! | |
if production == true then | |
displayMode(FULLSCREEN_NO_BUTTONS) | |
else | |
displayMode(STANDARD) | |
displayMode(FULLSCREEN) | |
end | |
end | |
function GameSetup() | |
--Helper- used to archive code - we need to improve saveCode. | |
if (archive==true) then | |
displayMode(STANDARD) | |
if saveCode ~= nil then | |
saveCode("TicTacToe") | |
end | |
end | |
--highscores = {} --pull these from a param or a network service | |
LoadAssets() --if there are assets to load, do it here. | |
explode = Explode() --set up for fireworks | |
message = FlashText({time=0, text="",pos = vec2(0,0)}) --if we have text to render/flash | |
end | |
--The game has started - gameplay begins. | |
function StartNewGame() | |
--any vars that require initialization ot start a new game (hearbeat) | |
--scores per player - HACK! | |
playerX = 0 | |
playerO = 0 | |
blank_board = { | |
{"","",""}, | |
{"","",""}, | |
{"","",""} } | |
offset = WIDTH - HEIGHT | |
end | |
--The game has ended - gameplay ends | |
function GameEnded() | |
--anything we need to do to clean up an existing game | |
end | |
--Load any assets needed. Currently, simple img loading, but this can be used to load | |
--audio files or 3D objects. | |
function LoadAssets() | |
--imgCircle = readImage("Documents:ExampleCircle") | |
--imgCross = readImage() | |
end | |
--if we decide to do http loading, we'll need a callback function... | |
--function LoadAssetCallback() | |
--end | |
--logs a message from the developer. | |
function log(msg) | |
if debug == false then | |
return | |
else | |
--handle yor messages appropirately. | |
--print(msg) | |
end | |
end | |
--this is in my generic utils library, added here so that this code can operate standalone | |
function clamp(x, min, max) | |
return math.max(min, math.min(max, x)) | |
end |
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.lua | |
-- | |
-- 0_GameTemplate | |
function setup() | |
archive = true --false --we want to archive the code on each run - backup often! | |
SetDisplayMode() | |
--GAME STATE DRIVER -- CAN ABSTRACT IN THE FUTURE | |
-- define consts - these drive the game state | |
--Note that I could have abstracted these into the GameFunctions file, but I want | |
--to "see" the states. | |
GAMESTATE_TITLE = 1 | |
GAMESTATE_PLAYING = 2 | |
-- put any screen states you want in here. | |
GAMESTATE_SCREEN1 = 3 | |
GAMESTATE_SCREEN2 = 4 | |
GAMESTATE_ENDED = 5 | |
--these are the screens (classes) that are called when the game performs it's heartbeat | |
--there should be one of these for each of the items above. | |
GAMESTATES = { ScreenTitle, ScreenGame, nil, nil, ScreenEnd } | |
--start at the default Title / Menu screen | |
--note that this will occur fast, so if you are defer loading, you'll have to | |
--be aware that all assets might not be loaded before the Title screen renders. | |
GAMESTATE = GAMESTATE_TITLE | |
--END OF GAMESTATE DRIVER | |
GameSetup() --sets up game parameters. Not the same as the game state driver. | |
ScreenTitle:init() | |
end | |
-- This function gets called once every frame | |
--this is the game's heartbeat. | |
function draw() | |
background(0, 0, 0, 255) | |
--state machine | |
GAMESTATES[GAMESTATE]:draw() | |
end | |
--any touches we get, forward on to the screen / class that needs them. | |
--note that this assumes that the default touch() is working, in the case of the | |
--Controllers library, touch() gets overridden and this becomes unused. | |
function touched(touch) | |
--state machine | |
GAMESTATES[GAMESTATE]:touched(touch) | |
end |
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
-- | |
-- Particle.lua | |
-- | |
Particle = class() | |
Particle.DEFAULT_OPACITY = 125 | |
Particle.DEFAULT_ANGLE = 0 | |
Particle.DEFAULT_MASS = 1 | |
function Particle:init(posx,posy,size,life,colour, | |
velocity,mass,angle,sprite) | |
-- position | |
self.x = posx | |
self.y = posy | |
self.ox = -5 | |
self.oy = 0 | |
-- size | |
self.width = size | |
self.height = size | |
-- color | |
if colour == nil then | |
self.color = color(255, 255, 255, 255) | |
else | |
self.color = colour | |
end | |
-- velocity | |
self.v = velocity | |
-- life | |
self.life = life | |
self.lifeLeft= life | |
-- sprite | |
self.sprite = sprite | |
-- mass | |
if mass == nil then | |
self.mass = DEFAULT_MASS | |
else | |
self.mass = mass | |
end | |
-- angle | |
if angle == nil then | |
self.angle = self.DEFAULT_ANGLE | |
else | |
self.angle = angle | |
end | |
end | |
function Particle:draw() | |
if self.lifeLeft > 0 then | |
self.lifeLeft = self.lifeLeft - 1 | |
end | |
if self.lifeLeft ~= 0 then | |
if self.sprite == nil then | |
fill(self.color) | |
ellipse(self.x,self.y,self.width,self.height) | |
else | |
pushMatrix() | |
translate(self.x,self.y) | |
rotate(self.angle) | |
tint(self.color) | |
sprite(self.sprite,0,0,self.width,self.height) | |
popMatrix() | |
end | |
end | |
end | |
function genNumber(number,variation) | |
ret = variation*0.01*number | |
ret = number + math.random(-ret,ret) | |
return ret | |
end |
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
-- | |
-- ScreenEnd.lua | |
-- | |
ScreenEnd = class() | |
--Call init() to set up ScreenEnd parameters. This is effectively a static class | |
function ScreenEnd:init() | |
end | |
function ScreenEnd:draw() | |
text("unused. remove?", WIDTH/2, HEIGHT/2) | |
end | |
function ScreenEnd:touched(touch) | |
if touch.state == ENDED then | |
GAMESTATE = GAMESTATE_TITLE | |
end | |
end |
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
-- | |
-- ScreenGame.lua | |
-- | |
ScreenGame = class() | |
--Call init() to set up ScreenGame parameters. This is effectively a static class | |
function ScreenGame:init(params) | |
-- you can accept and set parameters here | |
self.x = params.x or 1 | |
self.y = params.y or 1 | |
self.drawSpeed = params.drawSpeed or 2 --secs | |
self.drawing = true --drawing the board. | |
self.player = "X" | |
self.board = params.board -- | |
ScreenGame:SetupNewBoard() | |
end | |
function ScreenGame:draw() | |
self:DrawInitialBoard() | |
explode:draw() | |
message:draw() | |
if (message:active() == false and self.winner ~= nil) then | |
ScreenGame:SetupNewBoard() | |
end | |
textMode(CORNER) | |
text("Player: " .. self.player, 20, HEIGHT - 100) | |
text ("X: " .. playerX, 20, HEIGHT - 200) | |
text ("O: " .. playerO, 20, HEIGHT - 250) | |
--draw marks | |
for k,v in pairs(self.board) do | |
for key, item in pairs(v) do | |
text(item , 75+ key*225, 800-(k*225)) | |
end | |
end | |
--AC: HACK!!! Check for end of moves in the game | |
for k,v in pairs(self.board) do | |
for key, item in pairs(v) do | |
if item == "" then return end | |
end | |
end | |
if self.winner == nil then | |
message = FlashText({ time = 2, text = "Cat's Game, no winner!", | |
pos = vec2(WIDTH/2-140, HEIGHT/2)} ) | |
sound(DATA, "ZgFAGwBDVRljX0pZpyABv1aNGz+iVWM/QABPXz5NfT5AZSxr") | |
ScreenGame:SetupNewBoard() | |
end | |
end | |
function ScreenGame:touched(touch) | |
if self.winner ~= nil then return end --allow code to do stuff w/o touch interfering | |
if touch.state == ENDED then | |
local x = touch.x - offset | |
x = math.floor(x/225)+1 | |
local y = touch.y | |
y = 3-math.floor(y/225) | |
x=clamp(x,1,3) | |
y=clamp(y,1,3) | |
--now we have a bucket | |
if self.board[y][x] ~= "" then | |
--illegal touch | |
sound(SOUND_EXPLODE, 967) | |
else | |
self.board[y][x] = self.player | |
sound(SOUND_PICKUP, 6768) | |
if self.player == "X" then self.player = "O" else self.player = "X" end | |
end | |
self.winner = Analyze(self.board) | |
end | |
end | |
--fun way of drawing the background initially | |
function ScreenGame:DrawInitialBoard() | |
local linesize = 30 --line size | |
local padding = 50 --edge padding | |
pushStyle() | |
--AC we're drawing only 4 lines - make this easy! | |
strokeWidth(linesize) | |
stroke(186, 142, 142, 255) | |
line(400,padding, 400, HEIGHT-padding) | |
line(700,padding, 700, HEIGHT-padding) | |
--note that HEIGHT is correct for the WIDTH param, we are maknig a square | |
line(padding+ offset/2, 250, HEIGHT+ offset/2, 250) | |
line(padding+ offset/2, 550, HEIGHT+ offset/2, 550) | |
popStyle() | |
end | |
function Analyze(board) | |
local winner = nil | |
--check all horizontals | |
for x=1,3 do | |
if board[1][x] ~= "" then | |
if board[1][x] == board[2][x] and board[2][x] == board[3][x] then | |
--winner! draw line? | |
--text("WINNER "..board[1][x], 100,100) | |
winner = board[1][x] | |
end | |
end | |
end | |
--check second horizontal | |
for y=1,3 do | |
if board[y][1] ~= "" then | |
if board[y][1] == board[y][2] and board[y][2] == board[y][3] then | |
--winner! draw line? | |
--text("WINNER " .. board[y][1], 100,100) | |
winner = board[y][1] | |
end | |
end | |
end | |
--check diagonals | |
if board[1][1] ~= "" then | |
if board[1][1] == board[2][2] and board[2][2] == board[3][3] then | |
--winner! draw line? | |
--text("WINNER "..board[1][1], 100,100) | |
winner = board[1][1] | |
end | |
end | |
if board[1][3] ~= "" then | |
if board[1][3] == board[2][2] and board[2][2] == board[3][1] then | |
--winner! draw line? | |
--text("WINNER "..board[1][3], 100,100) | |
winner = board[1][3] | |
end | |
end | |
if (winner ~= nil ) then | |
--draw pretty explosions | |
explode:createFirework(100,500,color(255,255,255,255)) | |
sound(SOUND_EXPLODE, 968) | |
explode:createFirework(300,200,color(255,255,255,255)) | |
sound(SOUND_EXPLODE, 966) | |
explode:createFirework(500,400,color(255,255,255,255)) | |
sound(SOUND_EXPLODE, 967) | |
--increment player's win count | |
if winner == "X" then | |
playerX = playerX + 1 | |
else | |
playerO = playerO + 1 | |
end | |
message = FlashText({ time = 2, text = "Player " .. winner .. " wins!", | |
pos = vec2(WIDTH/2-80, HEIGHT/2)} ) | |
end | |
return winner --value or nil | |
end | |
function ScreenGame:SetupNewBoard() | |
self.board = { | |
{"","",""}, | |
{"","",""}, | |
{"","",""} } | |
-- self.player = "X" --we should enforce X alwys first, but let's not... | |
self.winner= nil --this will allow tuch() to operate - this is the gatekeeper :) | |
end | |
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
-- | |
-- ScreenTitle.lua | |
-- | |
ScreenTitle = class() | |
function ScreenTitle:init() | |
--cascade items down the screen | |
self.letter = "X" | |
items = {} | |
for x=1,25 do | |
i = vec3(math.random(WIDTH), math.random(HEIGHT)+HEIGHT, | |
math.random(3)) --20==item width , z= item falling speed | |
table.insert(items, i) | |
end | |
tmr = Timer(5) | |
tmr:start() | |
end | |
function ScreenTitle:draw() | |
fontSize(36) | |
font("Baskerville-SemiBold") | |
fill(114, 88, 88, 255) | |
if tmr:check() == true then | |
sound(DATA, "ZgNACwBAeQwzIHxmAAAAAA0PxD6kYgc+WQBbeXNiXDgKBghw") | |
if self.letter == "X" then self.letter = "O" else self.letter = "X" end | |
tmr = Timer(5) | |
tmr:start() | |
end | |
for k,v in pairs(items) do | |
text(self.letter, v.x, v.y) | |
v.y = v.y - v.z | |
if v.y < 0 then v.y = math.random(HEIGHT)+HEIGHT end | |
end | |
local w,h = textSize("TicTacToe") | |
fill(200, 188, 135, 255) | |
stroke(174, 174, 174, 255) | |
rectMode(CORNER) | |
local pad = 5 | |
rect(WIDTH/2-w/2-pad, HEIGHT/2-h/2-pad, w+pad*2,h+pad*2) | |
fill(255, 255, 255, 255) | |
text("TicTacToe", WIDTH/2, HEIGHT/2) | |
text("Touch to play", WIDTH/2, 100) | |
if (message:active() == false) then | |
message = FlashText({time=2, text="Play TicTacToe!", | |
pos=vec2(math.random(200)+ 400, math.random(200)+400), | |
fontsize = 36 }) | |
else | |
message:draw() | |
end | |
end | |
function ScreenTitle:touched(touch) | |
if touch.state == ENDED then | |
StartNewGame() | |
ScreenGame:init({x=WIDTH/2, y=HEIGHT/2, board=blank_board}) | |
GAMESTATE = GAMESTATE_PLAYING | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment