I have a newCircle that when clicked changes the color of the circle and starts a timer it it. i want to be able to click the circle again and change it back to black and completely remove the timer from the scene.
delta = 0
local function tapListener( event )
if (delta == 0) then
c1:setFillColor(1,1,0)
local timeLimit = 20
timeLeft = display.newText(timeLimit, c1.x, c1.y, native.systemFontBold, 14)
timeLeft:setTextColor(255,0,0)
local function timerDown()
timeLimit = timeLimit-1
timeLeft.text = timeLimit
if(timeLimit==0)then
print("Time Out") -- or do your code for time out
end
end
aTimer = timer.performWithDelay(1000,timerDown,timeLimit)
delta = delta + 1
else
c1:setFillColor(0,0,0)
delta = delta - 1
end
answer:
else
c1:setFillColor(0,0,0)
timer.cancel( aTimer )
timeLeft.alpha = 0
delta = delta - 1
end
the timer.cancal( aTimer ) stops the timer and the timeLeft.aplha = 0 hides the text that is displaying the timer
Related
Corona SDK timer countUp speeds up when button is touch? I do have 15 question in my game and everytime the answer is being touch the timer countUp speeds up everytime it goes to the another question..
Here is my button touch event
buttonTouched = function(event)
local t = event.target
local id = t.id
if event.phase == "began" and touchEnabled == true then
display.getCurrentStage():setFocus( t )
t.isFocus = true
if id == "answer" then
t.alpha = 0.6
else
t.xScale = 0.9
t.yScale = 0.9
end
elseif t.isFocus then
if event.phase == "ended" then
display.getCurrentStage():setFocus( nil )
t.isFocus = false
if id == "answer" then
t.alpha = 1
else
t.xScale = 1
t.yScale = 1
end
-- Check that touch finished in the button.
local b = t.contentBounds
if event.x >= b.xMin and event.x <= b.xMax and event.y >= b.yMin and event.y <= b.yMax then
utils.playSound("select")
if id == "answer" then
if timer_trans ~= nil then
transition.cancel(timer_trans)
timer_trans = nil
end
if result_trans ~= nil then
transition.cancel(result_trans)
result_trans = nil
end
if label_result ~= nil then
display.remove(label_result)
label_result = nil
end
-- Show some text that we can transition
label_result = display.newText({parent=uiGroup, text="", font=easyFont, fontSize=75})
label_result.anchorX = 0
label_result.x = label_question.x - 540
label_result.y = label_question.y + 400
if t.index == questions[onQuestion].answer then
label_result.text = "Correct!"
label_result:setFillColor(0,0.6,0)
utils.playSound("score")
updateScore(1)
else
label_result.text = "Incorrect..."
label_result:setFillColor(0.8,0,0)
utils.playSound("incorrect")
end
result_trans = transition.to(label_result, {time=1600, alpha=0.1, y=label_result.y-18,tag="transTag", onComplete=function()
display.remove(label_result)
label_result = nil
end})
-- Now create the next quesiton
createQuestion()
end
end
end
end
return true
end
function startTimer()
clockTimer = timer.performWithDelay(1000,doCountUp,gameTime)
end
function doCountUp()
currentTime = countUpText.text
currentTime = currentTime +1
countUpText.text = currentTime
if(currentTime == 0) then
countUpText.text = currentTime
startTimer()
end
end
The timer is "speeding up" because instead of resetting the current timer you are creating a new timer when you click the question.
You call startTimer() every time you create a new question
(assuming you set countUpText.text = "-1" in createQuestion(). Every time you touch the answer you create another timer to update the countUpText.text. You have multiple timers updating the text because you don't delete the previously created timers you are just creating new ones.
The easiest way to fix this is to cancel the timer and start a new one if a timer has been created:
local clockTimer
function startTimer()
if (clockTimer ~= nil) then
timer.cancel(clockTimer)
clockTimer = nil
end
clockTimer = timer.performWithDelay(1000,doCountUp,gameTime)
end
So update your startTimer() function to the above and then add local clockTimer to the top of your Lua file.
My timer pause and resume does not work? it has a logical error which said WARNING:timer.resume(timerID)ignored b/c was not paused. Any idea? Should i add add or remove listener to remove to stop the transition of the timer?
local timerEnabled = true -- Stops or allows our countdown timer
local touchEnabled = false
local delay_timer
local timer_trans -- transition of my timerbar
local timer_rect --display object
local timer_bar -- display object
function pauseGame( )
if (timerEnabled==false) then
timer.pause(timer_bar)
answer_rect:removeEventListener( "touch", buttonTouched )
elseif (timerEnabled==true) then
timer.resume(timer_bar)
answer_rect:addEventListener( "touch", buttonTouched )
end
end
local pauseButtonPress = function( event )
pauseGame()
end
timer_rect = display.newRect(uiGroup, _W*0.5, question_rect.y+question_rect.height, _W, 50 )
timer_rect.anchorY = 0
timer_rect:setFillColor(0,0.3,0.7)
if timerEnabled == true then
timer_bar = display.newRect(uiGroup, 0, timer_rect.y+timer_rect.height-20, _W, 35)
timer_bar.anchorX = 0
timer_bar:setFillColor(0.8,1,1)
end
pauseButton= widget.newButton{
defaultFile = "images1/Buttons/Pause.png",
overFile= "images1/Buttons/Resume.png",
onRelease = pauseButtonPress,
}
pauseButton.x = 100
pauseButton.y = 90
pauseButton.xScale = .6
pauseButton.yScale = .6
timer.pause() and timer.resume() should receive a timerID as param, not the object.
Example
local function listener( event )
print( "listener called" )
end
timer1 = timer.performWithDelay( 2000, listener ) -- wait 2 seconds
-- sometime later...
local result = timer.pause( timer1 )
print( "Time remaining is " .. result )
More information about timer.pause() and timer.resume() you may find in documentation.
so while building a mobile game with Corona SDK i am encountering some problems now and then. One of them I didn't seem to solve :
When spawning display objects in a loop, there seems to randomly appear a positional difference between two of the objects in a row.
At first, I thought this was due to large chunks of code that were executed between the actual spawning and the start of the transition, but then I managed to reproduce the same problem in few lines :
local rectangleLoopTimer;
local counter = 0;
local rectangleArray = {}
local function rectangleLoop()
counter = counter + 1
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
table.insert(rectangleArray, thisRectangle)
transition.to(
thisRectangle,
{
time = 5000,
x = thisRectangle.x + 1080,
onComplete = function()
display.remove(thisRectangle)
table.remove(rectangleArray, counter)
end
}
)
end
rectangleLoopTimer = timer.performWithDelay(985, rectangleLoop, 0)
If one executes this, then one sees what I mean, so what do you think why this happens? I appreciate every answer!
Greetings, Nils
EDIT:
This also produces the same problem :
local rectangleLoopTimer;
local counter = 0
local rectangleArray = {}
local thisRectangle
local function rectangleLoop()
counter = counter + 1
thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle.lastTime = 0
thisRectangle.rate = 216
table.insert(rectangleArray, thisRectangle)
thisRectangle.lastTime = system.getTimer()
thisRectangle.enterFrame = function(self, event)
local curTime = system.getTimer()
local dt = curTime - self.lastTime
self.lastTime = curTime
local dx = self.rate * dt / 1000
self.x = self.x + dx
end
Runtime:addEventListener("enterFrame", thisRectangle)
end
rectangleLoopTimer = timer.performWithDelay(1000, rectangleLoop, 0)
RE-EDIT:
This code also produces the same problem, albeit using framerate independent animation. The issue is getting emphasized when increasing the speed of the loop as in the code below :
local loopSpeed = 306
local loopTimerSpeed = 1000
local gapTable = {}
local gapLoopTimer
local frameTime
local gap
--enterFrame for time only
local function frameTime(event)
frameTime = system.getTimer()
end
--enterFrame
local function enterFrame(self, event)
local deltaTime = frameTime - self.time
print(deltaTime/1000)
self.time = frameTime
local speed = self.rate * deltaTime / 1000
self:translate(speed, 0)
end
--loop speed function
local function setLoopSpeed(factor)
loopSpeed = loopSpeed * factor
loopTimerSpeed = loopTimerSpeed / factor
end
--set the loop speed
setLoopSpeed(3)
--loop to create gaps
local function createGap()
gap = display.newRect(1, 1, 308, 442)
gap.time = system.getTimer()
gap.anchorX = 1
gap.anchorY = 0
--animation
gap.rate = loopSpeed
gap.enterFrame = enterFrame
Runtime:addEventListener("enterFrame", gap)
--fill table for cleaning up
table.insert(gapTable, gap)
--cleaning up
for i = #gapTable, 1, -1 do
local thisGap = gapTable[i]
if thisGap.x > display.contentWidth + 500 then
display.remove(thisGap)
table.remove(gapTable, i)
Runtime:removeEventListener("enterFrame", thisGap)
end
thisGap = nil
end
end
Runtime:addEventListener("enterFrame", frameTime)
gapLoopTimer = timer.performWithDelay(
loopTimerSpeed,
createGap,
0
)
This is a very common problem with transitions, and [to me] a bug in Corona SDK.
The important thing to note is how transitions work.
Transitions are nothing else than a table with references to objects and information about what should be done to them each frame.
Each frame such object is retrieved and current time is used to calculate the difference that should be applies to the values of the object, as specified in the transition itself.
This basically means that if you ask Corona to move an object from x = 0 to x = 100 in time = 100. Each frame, Corona will take that information, take current time, and will calculate the x value of your object.
The issue here is, that the current time taken, is current time at a time of calculation, and not time of the frame. It means, that if you have a lot of transitions, it could be quite a few milliseconds between first and last of the transitions within one frame. This will result in different positions within same frame.
If Corona would take frame time [so time at the beginning of the frame] it would use the same value to calculate everything, and no matter how many objects you would be transitioning from A to B, all of them would appear in the same place in all of the frames.
The easiest way to fix this, would be to handle transitions manually in enterFrame or use a library which does it for you, for example: AKTween.
Hope this helps.
EDIT:
Based on your additional code and comments, I think this should work as you wanted. Please forgive me the code quality, I wrote it from memory and didn't test it in Corona.
local rectangleLoopTimer;
local allRectangles = display.newGroup()
local lastTime = system.getTimer()
local function enterFrame()
local curTime = system.getTimer()
local dt = curTime - lastTime
lastTime = curTime
for i = allRectangles.numChildren, 1 do
local rect = allRectangles[i]
local dx = rect.rate * dt / 1000
rect.x = rect.x + dx
end
end
Runtime:addEventListener("enterFrame", enterFrame)
local function createRectangle()
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle.lastTime = 0
thisRectangle.rate = 216
allRectangles:insert(thisRectangle)
end
timer.performWithDelay(1000, createRectangle, 0)
EDIT AFTER RE-EDIT of the post:
You have time set in enterFrame listener, but you don't actually know when it's going to be called. I would not count on the order of functions called during enterFrame stage.
If you don't need futher reference to rects use code below
local rand = math.random
local function rectangleLoop()
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle:setFillColor(rand(), rand(), rand())
transition.to(thisRectangle, {time=5000,x=thisRectangle.x + 1080, onComplete=display.remove})
end
rectangleLoopTimer = timer.performWithDelay(985, rectangleLoop, 0)
Do you need use table to store rects?
So while building a mobile game with Corona SDK I have recently been facing a problem, that I couldn't solve, which are positional differences when spawning display objects in a loop. I got some help and found out this must have something to do with framerate independent animation. But now im facing this :
Albeit I'm using framerate independent animation here, this also produces the same problem. This gets emphasized by increasing the speed of the loop, as in the code below. What are your thoughts on this?
local loopSpeed = 306
local loopTimerSpeed = 1000
local gapTable = {}
local gapLoopTimer
local frameTime
local gap
--enterFrame for time only
local function frameTime(event)
frameTime = system.getTimer()
end
--enterFrame
local function enterFrame(self, event)
local deltaTime = frameTime - self.time
print(deltaTime/1000)
self.time = frameTime
local speed = self.rate * deltaTime / 1000
self:translate(speed, 0)
end
--loop speed function
local function setLoopSpeed(factor)
loopSpeed = loopSpeed * factor
loopTimerSpeed = loopTimerSpeed / factor
end
--set the loop speed
setLoopSpeed(3)
--loop to create gaps
local function createGap()
gap = display.newRect(1, 1, 308, 442)
gap.time = system.getTimer()
gap.anchorX = 1
gap.anchorY = 0
--animation
gap.rate = loopSpeed
gap.enterFrame = enterFrame
Runtime:addEventListener("enterFrame", gap)
--fill table for cleaning up
table.insert(gapTable, gap)
--cleaning up
for i = #gapTable, 1, -1 do
local thisGap = gapTable[i]
if thisGap.x > display.contentWidth + 500 then
display.remove(thisGap)
table.remove(gapTable, i)
Runtime:removeEventListener("enterFrame", thisGap)
end
thisGap = nil
end
end
Runtime:addEventListener("enterFrame", frameTime)
gapLoopTimer = timer.performWithDelay(
loopTimerSpeed,
createGap,
0
)
If you can set up size of gap between rects try use code below
local gapTable = {}
local gapWidth = 50
local runtime = 0
local speed = 20
local gap
local function getDeltaTime()
local temp = system.getTimer() -- Get current game time in ms
local dt = (temp-runtime) / (1000/display.fps) -- 60 fps or 30 fps as base
runtime = temp -- Store game time
return dt
end
local function enterFrame()
local dt = getDeltaTime()
for i=1, #gapTable do
gapTable[i]:translate(speed * dt, 0)
end
end
local function createGap()
local startX = 0
if #gapTable > 0 then
startX = gapTable[#gapTable].x - gapWidth - gapTable[#gapTable].width
end
gap = display.newRect(startX, 1, 308, 442)
gap.anchorX, gap.anchorY = 1, 0
table.insert(gapTable, gap)
--cleaning up
for i=#gapTable, 1, -1 do
if gapTable[i].x > display.contentWidth + 500 then
local rect = table.remove(gapTable, i)
if rect ~= nil then
display.remove(rect)
rect = nil
end
end
end
end
timer.performWithDelay(100, createGap, 0)
Runtime:addEventListener("enterFrame", enterFrame)
Hope this helps:)
I'm trying to spawn objects above screen height to fall down.
The code I've written so far works, but when i lets the scene run out, go back and start the level again the scene have 2 issues:
1. The spawn function "spawnObjects" seems to fire twice every 0.5 sec but only sometimes, but always at the second run. More than often console looks it's firing 3 (liike they're stacking)
2. At the second run the function that should run when timer goes to 0 or less isn't.
This is my code, it might be chunky and have values and what not in odd places. This is because I've been struggling with the timers and now this(still kinda timers) for some days now and I've tried so many different things. Hope anybody can see what I'm doing wrong, if you have a better solution for a countDown timer and/or way of spawning the objects then I'll try wwhatever.
local composer = require( "composer" )
local scene = composer.newScene()
local myData = require( "myData" )
local physics = require("physics")
physics.setDrawMode( "hybrid" )
-- forward references
local w = display.actualContentWidth
local h = display.actualContentHeight
local dropCount = 0
local spawnShit = 0
local spawnTime = 17
local countdownTimer
local score = 0
local countNumber = 10
local countDownNumber = 10
local scoreT = display.newText( {text="Score: "..score, font=system.nativeSystemFont, fontSize=14,} )
scoreT.x = w * 0.5
scoreT.y = h * 0.1
local countDownText = display.newText( {text="", font=system.nativeSystemFont, fontSize=14} )
countDownText.x = w * 0.5
countDownText.y = h * 0.2
local drop01 = display.newImage("drop01.png")
drop01.x = -100
local drop02 = display.newImage("drop02.png")
drop02.x = -100
local drop03 = display.newImage("drop03.png")
drop03.x = -100
local drop04 = display.newImage("drop04.png")
drop04.x = -100
local timerSpawn
-- Display objects
local background = display.newImage( "bluebg.png" )
background.x = w*0.5
background.y = h*0.5
background.width = w
background.height = h
local bckBtn = display.newText({text="<--BACK", font=system.nativeSystemFont, fontSize=14})
bckBtn.x = 50
bckBtn.y = 20
local egon = display.newImage( "Egon.png" )
egon.x = w*0.5
egon.y = h*0.85
egon.width = 100
egon.height = 97
--functions
function goBack (event)
if "began" == event.phase then
elseif event.phase == "ended" then
composer.gotoScene("select", "fade", 500)
end
return true
end
function moveEgon (event)
egon.x = event.x
end
------------------------------------------------vvv---------------------------------------------------
------------------------------------------------vvv---------------------------------------------------
------------------------------------------------vvv---------------------------------------------------
function spawnObjects (event)
dropCount = math.random(1,4)
if stopTimer == 1 then
timer.cancel(timerSpawn)
timerSpawn = nil
spawnShit = nil
end
if spawnShit == 1 then
print( 'spawnShit' )
if dropCount == 1 then
-- Drop01 function and settings
drop01 = display.newImage( "drop01.png" )
drop01.x = math.random(10, 470)
drop01.y = 40
drop01.width = 50
drop01.height = 50
drop01.myName = "01"
physics.addBody( drop01, "dynamic", {density=0.1, friction=0.1, bounce=0.8 } )
elseif dropCount == 2 then
--Do shit for drop02
drop02 = display.newImage( "drop02.png" )
drop02.x = math.random(10, 470)
drop02.y = 40
drop02.width = 50
drop02.height = 50
drop02.myName = "02"
physics.addBody( drop02, "dynamic", {density=0.1, friction=0.1, bounce=0.8 } )
elseif dropCount == 3 then
drop03 = display.newImage( "drop03.png" )
drop03.x = math.random(10, 470)
drop03.y = 40
drop03.width = 50
drop03.height = 50
drop03.myName = "03"
physics.addBody( drop03, "dynamic", {density=0.9, friction=0.1, bounce=0.8 } )
elseif dropCount == 4 then
drop04 = display.newImage( "drop04.png" )
drop04.x = math.random(10, 470)
drop04.y = 40
drop04.width = 50
drop04.height = 50
drop04.myName = "04"
physics.addBody( drop04, "dynamic", {density=0.9, friction=0.1, bounce=0.8 } )
end
end
return true
end
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
function onCollision (event)
if "began" == event.phase then
--v--do shit when touching surface
if event.other.myName == "01" then
-- Do shit for drop01 --
-- Change score, powersups etc
event.other:removeSelf( )
end
if event.other.myName == "02" then
-- Do shit for drop02 --
-- Change score, powersups etc
event.other:removeSelf( )
end
if event.other.myName == "03" then
-- Do shit for drop03 --
-- Change score, powersups etc
event.other:removeSelf( )
end
if event.other.myName == "04" then
-- Do shit for drop04 --
-- Change score, powersups etc
event.other:removeSelf( )
end
elseif "ended" == event.phase then
-- Do shit when leaving surfaces
end
return true
end
------------------------------------------------vvv---------------------------------------------------
------------------------------------------------vvv---------------------------------------------------
------------------------------------------------vvv---------------------------------------------------
function showCountDown (event)
-- Condition to show and hide countdown
if countDownNumber <= 0 then
timer.cancel(event.source)
countDownTimer = nil
spawnShit = 0
print( 'NO MORE SPAAAAAAAAAAAAAAAWWNS' )
else
countDownNumber = countDownNumber -1
countDownText.text = countDownNumber
spawnShit = 1
end
return true
end
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
--function scene:create( event )
function scene:create( event )
local sceneGroup = self.view
-- Initialize the scene here.
-- Example: add display objects to "sceneGroup", add touch listeners, etc
--Listeners
background:addEventListener( "touch", moveEgon )
bckBtn:addEventListener( "touch", goBack )
egon:addEventListener( "collision", onCollision )
--SceneGroup insert
sceneGroup:insert( background )
sceneGroup:insert(egon)
sceneGroup:insert(bckBtn)
sceneGroup:insert(drop01)
sceneGroup:insert(drop02)
sceneGroup:insert(drop03)
sceneGroup:insert(drop04)
sceneGroup:insert(scoreT)
sceneGroup:insert(countDownText)
end
-- "scene:show()"
function scene:show( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
-- Called when the scene is still off screen (but is about to come on screen).
elseif ( phase == "did" ) then
-- Called when the scene is now on screen.
-- Insert code here to make the scene come alive.
-- Example: start timers, begin animation, play audio, etc.
physics.start( )
timercount = 10
-- ADD physic bodies ----
physics.addBody( egon, "static", {density=0.1, friction=0.1, bounce=0.8 } )
countDownNumber = 10
countdownTimer = timer.performWithDelay( 1000, showCountDown, countNumber )
----------- Timers ------------
timerSpawn = timer.performWithDelay(500, spawnObjects, 0 )
end
end
-- "scene:hide()"
function scene:hide( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
-- Called when the scene is on screen (but is about to go off screen).
-- Insert code here to "pause" the scene.
-- Example: stop timers, stop animation, stop audio,
--timer.pause( timerSpawn )
physics.stop()
spawnShit = 0
timerSpawn = nil
countdownTimer = nil
physics.removeBody( egon )
elseif ( phase == "did" ) then
-- Called immediately after scene goes off screen.
end
end
-- "scene:destroy()"
function scene:destroy( event )
local sceneGroup = self.view
-- Called prior to the removal of scene's view ("sceneGroup").
-- Insert code here to clean up the scene.
-- Example: remove display objects, save state, etc.
bckBtn:removeEventListener("touch", goBack )
egon:removeEventListener("touch", moveEgon )
end
-- -------------------------------------------------------------------------------
-- Listener setup
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )
-- -------------------------------------------------------------------------------
return scene
When your scene:show(), you execute
timerSpawn = timer.performWithDelay(500, spawnObjects, 0 )
which will cause spawObjects to be called every 0.5 seconds indefinitely (ie until application exits, or timer is cancelled or paused). This is ok except that when you come back to that scene, that line gets executed again, which will cause a new timer to be created, and timeSpawn now references the new timer. So now you'll have two timers firing at every 0.5 seconds approx. When you leave scene and come back again, you will have 3, etc. The fact that timerSpawn gets set to reference a new timer does not stop the old timer. You probably should pause timerSpawn when the scene gets hidden; then in the show(), you should only create the timer if it doesn't already exist:
function scene:show( event )
....
----------- Timers ------------
countDownNumber = 10
if countdownTimer == nil then
countdownTimer = timer.performWithDelay( 1000, showCountDown, countNumber )
else
timer.resume(countownTimer)
end
if timerSpawn == nil then
timerSpawn = timer.performWithDelay(500, spawnObjects, 0 )
else
timer.resume(timerSpawn)
end
end
function scene:hide( event )
...
if ( phase == "will" ) then
timer.pause( timerSpawn )
timer.pause( countdownTimer )
-- NO:
-- timerSpawn = nil
-- countdownTimer = nil
...
end
end