Corona SDK (LUA) Spawning objects and timer issues - timer

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

Related

Corona SDK timer countUp speeds up when button is touch?

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.

Corona SDK, Timer pause and resume does not work?

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.

CoronaSDK - Remove timer from scene on click

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

"Throw" concept in Corona SDK

Alright, I am creating an app where I have already created the touch and drag effect. I don't know how to code the part where the user lets go of the object and it goes flying, hence the "throw."
local body = event.target
local phase = event.phase
local stage = display.getCurrentStage()
---
if event.phase == "began" then
--begin focus
display.getCurrentStage():setFocus( self, event.id)
self.isFocus = true
self.markX = self.x -- store x location of object
self.markY = self.y -- store y location of object
physics.addBody(happy)
elseif self.isFocus then
if event.phase == "moved" then
physics.addBody(happy)
-- drag touch object
local x = (event.x - event.xStart) + self.markX
local y = (event.y - event.yStart) + self.markY
self.x, self.y = x, y -- move object based on calculations above
elseif event.phase == "ended" then
-- end focus
display.getCurrentStage():setFocus( self, nil)
self.isFocus = false
end
end
return true
Once again, I am trying to get the user to be able to throw the object instead of just dragging it. Also, if anyone can help with the touch and hold timer that would make the object go away and respawn then it would be much appreciated.
You would probably compute the velocity at release: compute the touch position (x1,y1) at touch begin phase and the touch position (x2, y2) at touch end phase, and the time between the two: you then set your object's linear velocity to this (it is a 2D vector) via object.setLinearVelocity(). If the body is non-static, this will set it in motion. The motion will depend on whether it is dynamic or kinematic. If dynamic, the velocity will be set then it will change depending on external forces applied to the object (like gravity). Example:
local startTouchMove = 0
....
local function touchListener(event)
if event.phase == "began" then
...
self.markX = event.x -- store x location of object
self.markY = event.y -- store y location of object
startTouchMove = system.timer()
...
elseif self.isFocus then
if event.phase == "moved" then
...
elseif event.phase == "ended" then
-- set the instantaneous velocity based on touch motion
local dt = system.timer() - startTouchMove
if dt ~= 0 then
local velX = ( event.x - self.markX ) / dt
local velY = ( event.y - self.markY ) / dt
yourObject:setLinearVelocity(velX, velY)
end
end
end
end

Corona SDK array index is beyond array bounds, advice needed

I will try to as concise as possible with my issue.
Firstly, files are:
block.lua
base.lua
main.lua
In block.lua I create a block, add collision detection and a cleanup code.
In base.lua I create a base made up of 4 columns and 10 rows. 40 blocks in total.
In main.lua I create 4 bases made from the base.class.
All is working fine once the game begins.
I remove the bases and call them again on level 2.
They create themselves ok BUT
when the enemy is destroyed once again, and the bases are to be rebuilt, I get an:
array index 1 is beyond array bounds:1..1
-- all the way up to--
array index 800 is beyond array bounds:1..159
it will then create the bases and continue until the enemys are destroyed and do the same again starting at :
array index 800 is beyond array bounds:1..159
-- all the way up to--
array index 4000 is beyond array bounds:1..159
The terminal points me at block.lua line 23
blockGroup:insert(blockNum,self.block)
Now I cant see anything wrong in the class, I have looked and googled for hours but all to no avail.
I would really appreciate a helping hand to guide me here please.
I have tried rewriting the "cleanup" etc but no joy.
I left a few commented out bits in there and removed some of the irrelevant stuff.
I post below the relevant code:
--MAIN.LUA--
function gameOver()
Runtime:removeEventListener("enterFrame", onEnterFrame)
Runtime:removeEventListener("enterFrame", movePlayer)
layers:removeSelf()
layers = nil
enemyCount = 0
for i = 1,#allEnemys do
timer.cancel(allEnemys[i].clock)
Runtime:removeEventListener( "enterFrame", allEnemys[i] )
display.remove(allEnemys[i].image)
allEnemys[i].image=nil
end
allEnemys=nil
cleanupBlocks()
end
----------------------------------------------------------------------
-- LEVEL UP --
----------------------------------------------------------------------
function levelUp(level)
enemyCount = 0
local enemys = require("modules.enemy")
if allEnemys ~= nil then
for i = 1,#allEnemys do
timer.cancel(allEnemys[i].clock)
Runtime:removeEventListener( "enterFrame", allEnemys[i] )
display.remove(allEnemys[i].image)
allEnemys[i].image=nil
end
end
allEnemys=nil
cleanupBlocks()
levels()
end
----------------------------------------------------------------------
-- LEVELS --
----------------------------------------------------------------------
function levels(level)
function createInvader(x, y, row)
for j = 1, 2 do
for i = 1, 2 do
if allEnemys == nil then
allEnemys = {}
else
enemysCount=#allEnemys
end
allEnemys[#allEnemys + 1] = enemys:new()
allEnemys[#allEnemys ]:init(i * 60, j * 70 + 70,j)
allEnemys[#allEnemys ]:start()
end
end
end
createInvader()
--[[function createBases1()
local base = require("modules.base")
for i = 1, 4 do
base:new()
base:init(i * 180 - 130, 850)
end
end ]]--
createBases()
end
--BLOCK.LUA--
local block = {}
local block_mt = { __index = block}
local scene = scene
local blockGroup = display.newGroup()
local blockNum = 0
function block:new() -- constructor
local group = {}
return setmetatable( group, block_mt )
end
function block:init(xloc,yloc) --initializer
-- Create attributes
self.block = display.newRect( xloc,yloc,10,10)
self.block:setFillColor ( 2, 255, 14 )
blockNum = blockNum + 1
blockGroup:insert(blockNum,self.block)
local blockCollisionFilter = { categoryBits = 128, maskBits = 387}
physics.addBody( self.block, "static", {filter = blockCollisionFilter})
self.count = 1
end
function cleanupBlocks()
--[[ print(blockNum, blockGroup.numChildren)
for i=1,blockGroup.numChildren do
blockGroup[1]:removeSelf()
blockGroup[1] = nil
end ]]--
print(blockNum, blockGroup.numChildren)
while blockGroup.numChildren>0 do
display.remove(blockGroup[1])
blockGroup[1]=nil
end
end
function block:start()
--- Create Listeneres
self.block:addEventListener( "collision", self )
scene:addEventListener('base_block_event', self)
end
return block
--BASE.LUA--
local base = {}
local base_mt = { __index = base}
local scene = scene
local block = require("modules.block")
function base:new() -- constructor
local group = {}
return setmetatable( group, base_mt )
end
function base:init(xloc, yloc) --initializer
-- Create attributes
local base
for j = 1, 4 do
for i = 1, 10 do
base = block:new()
base:init(xloc+i * 10,yloc+j * 10)
base:start()
end
end
end
return base
I see you use
blockNum = blockNum + 1
blockGroup:insert(blockNum,self.block)
Try to use
blockGroup:insert(self.block)
just to see if you still get that error.

Resources