I have some issues in my game related to timers, and at this point I have doubts if I use them right way.
Game is snake-like
Actually I’m testing two players mode
One power up can be spawned at once
Each player can take one power up at once
Power up has 3 different spawn time delay
Timers have handles initialized at the beginning
You can pause game
Here is the simplified code of aformentioned functions. Left only essential parts (code is long) so you CAN’T run it. I hope is readable tho
local composer = require( "composer" )
local scene = composer.newScene()
local gameLoopTimer -- Timer for game loop
local powerUpEffectTimer -- Timer for power up effect
local powerUpClockTimer -- Timer for power up gui clock
local powerUpSpawnTimer -- Timer for power up spawn delay
local gameMode = composer.getVariable( "mode" ) -- 1 - single player; 2 - multiplayer
local gameState
local snakeGodMode = {false, false} -- Modifier if player has GOD MODE [1] - player 1 [2] - player 2
local powerUps = true -- Gamerule if power ups are allowed
local p1isPower = false -- Player 1 has powerup flag
local p2isPower = false -- Player 2 has powerup flag
local powerUpExist = false
local powerUpTable = {} -- Table for spawned power ups
local powerUpTypes
local powerUpTimes = {5000,10000,15000}
if gameMode == 1 then
powerUpTypes = {"speedUp", "slowDown", "godMode", "revUp", "randUp"}
elseif gameMode == 2 then
powerUpTypes = {"speedUp", "slowDown", "godMode", "revUp", "speedUpB", "slowDownB", "revUpB", "randUp"}
end
local function pauseTimers()
if snakeMoveTimer ~= nil then timer.pause( snakeMoveTimer ) end
if gameLoopTimer ~= nil then timer.pause( gameLoopTimer ) end
if powerUpEffectTimer ~= nil then timer.pause( powerUpEffectTimer ) end
if powerUpClockTimer ~= nil then timer.pause( powerUpClockTimer ) end
if powerUpSpawnTimer ~= nil then timer.pause( powerUpSpawnTimer ) end
if gameMode == 2 then
if snakeMoveTimer2 ~= nil then timer.pause( snakeMoveTimer2 ) end
if respawnTimer ~= nil then timer.pause( respawnTimer ) end
end
end
local function resumeTimers()
if snakeMoveTimer ~= nil then timer.resume( snakeMoveTimer ) end
if gameLoopTimer ~= nil then timer.resume( gameLoopTimer ) end
if powerUpEffectTimer ~= nil then timer.resume( powerUpEffectTimer ) end
if powerUpClockTimer ~= nil then timer.resume( powerUpClockTimer ) end
if powerUpSpawnTimer ~= nil then timer.resume( powerUpSpawnTimer ) end
if gameMode == 2 then
if snakeMoveTimer2 ~= nil then timer.resume( snakeMoveTimer2 ) end
if respawnTimer ~= nil then timer.resume( respawnTimer ) end
end
end
-- Creates new pickup item after previous one is collected
local function pickupSpawn (itemType)
if itemType == "power" then
timer.cancel(powerUpSpawnTimer)
powerUpSpawnTimer = nil
local powerVar = math.random( #powerUpTypes )
local thisPowerUp = display.etc.
thisPowerUp.myName = powerUpTypes[powerVar]
thisPowerUp:setSequence( powerUpTypes[powerVar] )
thisPowerUp:play()
powerUpTable[#powerUpTable + 1] = thisPowerUp
end
end
-- Drawing Ui with powerup icon and clock
local function powerUpActivate(player, powerType)
local pIconX, pIconY, pTimerX, pTimerY
local pTime = 10
if player == snakeHead then
pIconX, pIconY, pTimerX, pTimerY = blah, blah, blah, blah
p1isPower = true
elseif player == snakeHead2 then
pIconX, pIconY, pTimerX, pTimerY = blah, blah, blah, blah
p2isPower = true
end
local pUpIcon = display.etc.
local timerClock = display.etc.
local countDown = function (event)
pTime = pTime - 1
timerClock.text = pTime
if event.count == 10 then
display.remove(pUpIcon)
display.remove(timerClock)
if player == snakeHead then
p1isPower = false
elseif player == snakeHead2 then
p2isPower = false
end
end
end
powerUpClockTimer = timer.performWithDelay( 1000, countDown, 10 )
end
-- God Mode effect power up
local function makeGodMode(player, long, target)
local pNum
if player == snakeHead then
pNum = 1
elseif player == snakeHead2 then
pNum = 2
end
snakeGodMode[pNum] = true
powerUpActivate(player, "godMode")
local closure = function()
snakeGodMode[pNum] = false
timer.cancel(powerUpEffectTimer)
powerUpEffectTimer = nil
end
powerUpEffectTimer = timer.performWithDelay( long, closure )
end
-- Power up collecting check
local function powerCheck (headObject)
for i = #powerUpTable, 1, -1 do
local thisPower = powerUpTable[i]
if (headObject.x == thisPower.x) and (headObject.y == thisPower.y) then
if thisPower.myName == "godMode" then
makeGodMode(headObject, 10000)
end
powerUpExist = false
display.remove(thisPower)
thisPower = nil
end
end
end
local function gameLoop()
if powerUps == true and powerUpExist == false then
local d = math.random(#powerUpTimes)
local dd = powerUpTimes[d]
powerUpExist = true
local closure = function() return pickupSpawn("power") end
powerUpSpawnTimer = timer.performWithDelay( dd, closure)
end
if gameMode == 1 then
if powerUps == true then
if p1isPower == false then
powerCheck(snakeHead)
end
end
elseif gameMode == 2 then
if powerUps == true then
if p1isPower == false then
powerCheck(snakeHead)
elseif p2isPower == false then
powerCheck(snakeHead2)
end
end
end
end
local function resumeGame(button)
gameState = "active"
if button == "resume" then
resumeTimers()
transition.resumeAll()
--timer.resumeAll()
elseif button == "exit" then
endGame()
end
end
local function pauseGame()
-- Pausing game
gameState = "paused"
pauseTimers()
transition.pauseAll()
end
function scene:show( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
elseif ( phase == "did" ) then
intro.create(stageNo)
timer.performWithDelay( 2600, function()
gameLoopTimer = timer.performWithDelay( 10, gameLoop, 0 );
snakeMoveTimer = timer.performWithDelay( 300, moveLoop, 0);
if gameMode == 2 then snakeMoveTimer2 = timer.performWithDelay( 300, moveLoop2, 0 ) end;
gameState = "active";
end )
end
end
function scene:hide( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
if snakeMoveTimer ~= nil then timer.cancel( snakeMoveTimer ) end
if gameLoopTimer ~= nil then timer.cancel( gameLoopTimer ) end
if powerUpEffectTimer ~= nil then timer.cancel( powerUpEffectTimer ) end
if powerUpClockTimer ~= nil then timer.cancel( powerUpClockTimer ) end
if powerUpSpawnTimer ~= nil then timer.cancel( powerUpSpawnTimer ) end
if gameMode == 2 then
if snakeMoveTimer2 ~= nil then timer.cancel( snakeMoveTimer2 ) end
if respawnTimer ~= nil then timer.cancel( respawnTimer ) end
end
elseif ( phase == "did" ) then
transition.pauseAll()
transition.cancelAll()
composer.removeScene( "game" )
end
end
-
After few iterations of spawning and collecting power up, when I pause/resume game I got warnings due to “expired timers”. Even I delete them when they are expired.
(Yes, these warnings are about one of these timers 'cause I hadn’t any warnings before implementing these) -
Also sometimes I have problem with “powerUpSpawnTimer” that even though it gets a “dd” number to spawn (for debug I’ve put there print right before fire of timer) but nothing happened. To be precise, it spawns few time, I collect power ups, and then stops spawning. (no warnings in console)
-
Another thing is when one player has powerup (god mode in this case) and another power up is spawned and player 2 takes it. The powerUpEffectTimer, and other power up related timers are doubled. What should I do to make them “dynamic” and not coliding with each other?
I thought about creating local handles of powerUpEffectTimer etc. and adding them to table with timers, and then removing proper one with loop after finish.
Speaking of pausing and resuming it should work to if in pauseTimers() and resumeTimers() I could add loops.
- Moreover double of powerUpEffectTimer is when player is respawned, you got god mode too but it has separate function due to placing in code. But still use same handle for timer like makeGodMode()
And I’m not sure if I should use iterations in powerUpSpawnTimer or in any of them. Because this one is never start two at the same time but powerUpEffectTimer does so what with it?