how to delay gotoscene - lua

whenever the specific food hits the monkey, the game restarts but I want to delay it for few seconds and show some text before restarting but i cant seem to. It does not delay,
local function monkeyCollision( self, event )
if event.phase == "began" then
if event.target.type == "monkey" and event.other.type == "food" then
print( "chomp!" )
event.other.alpha = 0
event.other:removeSelf()
addToScore(5)
-- get points!
else
print("ow!")
monkey.alpha = 0
monkey:removeSelf()
displayScore = display.newText( "The total score is " .. score , 0, 0, "Helvetica", 30 )
displayScore.x = screenLeft +150
displayScore.y = screenRight-100
displayre = display.newText( " The game is going restart", 0, 0, "Helvetica", 25 )
displayre.x = screenLeft +150
displayre.y = screenRight-200
storyboard.gotoScene("play", "fade", 1000)
end

Why not put it in a timer:
timer.performWithDelay(5000, function() storyboard.gotoScene("play", "fade", 1000); end)
That will delay 5 seconds before calling storybaord.gotoScene()

Add a timer as Rob did like
timer.performWithDelay(5000, function() storyboard.gotoScene("play", "fade", 1000); end)
But you also have a problem now. What if you hit another food after you already hit one? This would make multiple timers go off and probably glitch because it will remove a monkey which was already removed...
local lostGame = false
local function monkeyCollision( self, event )
if event.phase == "began" then
if event.target.type == "monkey" and event.other.type == "food" then
print( "chomp!" )
event.other.alpha = 0
event.other:removeSelf()
addToScore(5)
-- get points!
else
if lostGame == false then
print("ow!")
monkey.alpha = 0
monkey:removeSelf()
displayScore = display.newText( "The total score is " .. score , 0, 0, "Helvetica", 30 )
displayScore.x = screenLeft +150
displayScore.y = screenRight-100
displayre = display.newText( " The game is going restart", 0, 0, "Helvetica", 25 )
displayre.x = screenLeft +150
displayre.y = screenRight-200
timer.performWithDelay(5000, function() storyboard.gotoScene("play", "fade", 1000); end)
lostGame = true
end
end
end
end
By adding a variable to check if you have already lost, you can prevent it from running the code to leave while you are in the delay.

Related

LUA - Unable to make the game restart after the timer finishes

I have to make a small game for my college work and at the end of the game I would like it so if you click the game over button it restarts it, however every time I have tried to do this it hasn't worked with either errors or just the game restarting and the game over image not being removed.
I know that the current code exits the app when the gameover sign is clicked due to the closeDownApp function (this is the code from before I tried to add the ability to restart)
Any help on how to do it will be greatly appreciated
--Define the variables
rotateAmt = 5
rotateMin = -90
rotateMax = 90
cannonRotation = 0
cannonForce = 1200
playerPoints = 0
targetHit = false
timeLeft = 600
--Define the functions
function closeDownApp(event)
os.exit ( )
end
function update( )
--decrease the time counter
timeLeft = timeLeft - 1
scoreDisplay.text = 'Kills: ' .. playerPoints .. ' Time: ' .. timeLeft
--check if the time has run out
if (timeLeft <= 0) then
--display the final score
scoreDisplay.text = 'Your score was ' .. playerPoints
--remove all of the screen objects
display.remove(cannonBarrel)
display.remove(target)
display.remove(upButton)
display.remove(downButton)
display.remove(fireButton)
--display the 'game over' sign
gameOver = display.newImage('gameover.png', 150, 75)
gameOver:addEventListener('tap', closeDownApp)
-- make a group
end
--check if the target has been hit
if (targetHit == true) then
targetHit = false
playerPoints = playerPoints + 1
Hit = display.newImage('Hit.png', target.x, target.y)
--replace the target with the hit picture
transition.dissolve(Hit, target, 1000, 0)
display.remove(bullet)
--put the target back to a random position
target.x = math.random(280, 500 )
target.y = math.random(100, 290 )
end
end
function onCollide(event)
targetHit=true
end
function fire(event)
--only fire at the beginning of a touch event
if (event.phase == 'began') then
media.playSound('bang.wav')
bullet = display.newImage('bullet.png')
--move the image
bullet.x, bullet.y = cannonBarrel:localToContent(70, 0)
bullet.rotation = cannonRotation
--apply physics to the cannonball
physics.addBody( bullet, { density=2.0, friction=0.2, radius=15 } )
--determine the appropriate ratio of horizontal to vertical force
force_x = math.cos(math.rad(cannonRotation)) * cannonForce
force_y = math.sin(math.rad(cannonRotation)) * cannonForce
--fire the cannonball
bullet:applyForce( force_x, force_y, bullet.x, bullet.y )
end
end
function moveDown(event)
--only move the barrel if the touch event started
if (event.phase == 'began') then
cannonRotation = cannonRotation + rotateAmt
if (cannonRotation >= rotateMax) then
cannonRotation = rotateMax
end
cannonBarrel.rotation = cannonRotation
fireButton.rotation = cannonRotation
end
end
function moveUp(event)
--only move the barrel if the touch event started
if (event.phase == 'began') then
cannonRotation = cannonRotation - rotateAmt
if (cannonRotation <= rotateMin) then
cannonRotation = rotateMin
end
cannonBarrel.rotation = cannonRotation
fireButton.rotation = cannonRotation
end
end
function makeTarget( )
target = display.newImage('target.png')
target.x = math.random(280, 450)
target.y = math.random(100, 290)
physics.addBody(target,{density=1.0, friction=0.5, bounce=0.05, radius=15})
target.bodyType = 'static'
target:addEventListener('collision', onCollide)
end
function makeInterface( )
--up button
upButton = display.newImage('up_button.png')
upButton:translate(3, 37)
upButton:addEventListener('touch', moveUp)
--down button
downButton = display.newImage('down_button.png')
downButton:translate(3, 176)
downButton:addEventListener('touch', moveDown)
--fire button
fireButton = display.newImage('fire_button.png')
fireButton:translate(19, 124)
fireButton:addEventListener('touch', fire)
--display cannon parts
cannonBarrel = display.newImage('cannon_barrel.png')
cannonBarrel:translate(73, 109)
--display score
scoreDisplay = display.newText( ('Points: ' .. playerPoints), 70, -18, native.systemFont, 20 )
scoreDisplay:setTextColor( 255,255,255 )
scoreDisplay:translate(display.contentHeight /2, 30)
end
--Define control structure
function init( )
audio.stop (1)
display.setStatusBar(display.HiddenStatusBar)
background = display.newImage('bg.jpg')
physics = require('physics')
physics.setDrawMode('normal')
physics.start( )
makeInterface( )
makeTarget( )
Runtime:addEventListener('enterFrame', update)
local backgroundMusic = audio.loadStream("theme.mp3")
local backgroundMusicChannel = audio.play( backgroundMusic,{channel=2, loops=-1, fadein=10 })
audio.setVolume( 0.5, { channel=backgroundMusicChannel } )
end
function introScreen( )
local backgroundMusic1 = audio.loadStream("intro.mp3")
local backgroundMusicChannel1 = audio.play( backgroundMusic1,{channel=1, loops=1, fadein=10 })
-- Display the background
background = display.newImage ("IntroScreen.png")
-- Display the play button at the top right
playBtn = display.newImage ("playBtn.png", 350, 10)
playBtn:addEventListener('tap', init)
end
--Call the code
introScreen( )
This seems like it was written for Corona SDK. Their forums (https://forums.coronalabs.com/) seem very active.
I'm sure that you'd be able to solve this issue a lot faster by asking for help there.

Attempt to perform arithmetic on field 'y' (a nil value)

I'm new here and I'm struggling with this error in Corona, when game ends (lives=0) and I try to remove the background (that is moving with a function "move"):
"Attempt to perform arithmetic on field 'y' (a nil value)"
in line "background.y = background.y + 4"
Is there anybody who can explain me what is the mistake?
THE CODE:
--add PHYSICS
local physics = require( "physics" )
physics.start()
physics.setGravity( 0, 0 )
local lives = 1
local died = false
--###
--add background
background = display.newImageRect( "background.png", 800, 14000 )
background.x = display.contentCenterX
background.y = 730
background.myName = "background"
--add bottle
bottiglia = display.newImageRect( "bottiglia.png", 41, 104 )
physics.addBody( bottiglia, "dynamic", { radius=45, bounce=0.5 } )
bottiglia.x = display.contentCenterX
bottiglia.y = 10
bottiglia.myName = "bottiglia"
--function move
local function move()
bottiglia.y = bottiglia.y + 4
background.y = background.y + 4
end
Runtime:addEventListener( "enterFrame", move )
--###
--add player
studente = display.newImageRect( "studente.png", 98, 79 )
studente.x = display.contentCenterX
studente.y = display.contentHeight - 100
physics.addBody( studente, { radius=40, isSensor=true } )
studente.myName = "studente"
--###
--function collision
local function onCollision( event )
if ( event.phase == "began" ) then
local obj1 = event.object1
local obj2 = event.object2
if ( ( obj1.myName == "studente" and obj2.myName == "bottiglia" ) or
( obj1.myName == "bottiglia" and obj2.myName == "studente" ) )
then
if ( died == false ) then
died = true
-- lives update
lives = lives - 1
livesText.text = "Lives: " .. lives
if ( lives == 0 ) then
display.remove( studente )
display.remove( background)
timer.performWithDelay( 100, endGame )
end
else
studente.alpha = 0
timer.performWithDelay( 500, restoreStudente )
end
end
end
end
Runtime:addEventListener( "collision", onCollision )
livesText = display.newText( "Lives: " .. lives, 200, 80, native.systemFont, 36 )
--thank you all
The Runtime listener (move function) is working all the time. It changes position of bottiglia and background objects but since background does not exist any more you get an error.
A simple solution is to remove the global listener using Runtime:removeEventListener() before you remove the background object.
Use Runtime:removeEventListener("enterFrame", move)
If you don't want remove listener, you can add checks for nil:
--function move
local function move()
if (bottiglia ~= nil and bottiglia.y ~= nil) then
bottiglia.y = bottiglia.y + 4
end
if (background~= nil and background.y ~= nil) then
background.y = background.y + 4
end
end
This is also pretty risky to use such global variables: bottiglia and background.
You can make it little safer if make them as (or something like that):
myGlobalsVars = { }
myGlobalsVars.myGlobalsVars = display.newGroup()
myGlobalsVars.background = display.newGroup()

How do i add a button to back to Main Menu (another .lua file)?

This game is something like killing mosquito. This is the level 1 file. When player tap the bee, game over will be displayed. When time's up, game over will be displayed. Total mosquitoes killed will be displayed at the end. I'm very very new to corona and to game development.
My question is:
Where to put in function to go back to main menu via "touch"? What is the code for it?
i'm using composer. So i tried composer.gotoScene("menu") but that doesn't seems to work. Error.
Thanks in advance for any help given. Here is part of the code:
local composer = require( "composer" )
local scene = composer.newScene()
local physics = require("physics")
local widget = require "widget"
physics.start()
rand = math.random( 20 )
local slap_sound = audio.loadSound("Sound/slap2.mp3")
local ow = audio.loadSound("Sound/ow.mp3")
local buttonSound = audio.loadSound("Sound/sound2.mp3")
local back
--local mossie_sound = audio.loadSound("Sound/mossie.mp3")
local count={total1=0,total=0,touch=0,life=3}
local background = display.newImageRect( "Images/bg.jpg", display.contentWidth, display.contentHeight )
background.anchorX = 0
background.anchorY = 0
background.x, background.y = 0, 0
local total=display.newText("Score : 0",display.contentWidth * 0.5, 20, "Arial", 26)
total:setTextColor(000000)
local time_remain = 30
local mossie
local bee
local shade
local gameOverScreen
local winScreen
local gameIsActive = false
local countdown=display.newText(time_remain ,display.contentWidth * 0.9, 20, "Arial", 26)
countdown:setTextColor(000000)
local life = display.newText("Life : 3 " ,display.contentWidth * 0.5, 50, "Arial", 26)
life:setTextColor(000000)
local pauseBtn = display.newImage("Images/pause.png")
pauseBtn.x = display.contentWidth * 0.1
pauseBtn.y = display.contentHeight - 450
local resumeBtn = display.newImage("Images/playb.png")
resumeBtn.x = display.contentWidth * 0.1
resumeBtn.y = display.contentHeight - 450
local gameOver = function()
composer.removeScene("level1") //scene cannot be removed???
gameIsActive = false
physics.pause()
gameOverScreen = display.newImage("Images/gameover.png",400,300)
gameOverScreen.x = 160
gameOverScreen.y = 240
gameOverScreen.alpha = 0
transition.to(gameOverScreen,{time=500,alpha=1})
total.isVisible = true
total.text="Score : "..count.touch
total.x = 160
total.y = 400
botwall.isVisible = false
mossie.isVisible = false
bee.isVisible = false
life.isVisible = false
countdown.isVisible = false
pauseBtn.isVisible = false
resumeBtn.isVisible = false
end
local collisionListener=function(self,event)
if(event.phase=="began")then
if(event.other.type=="mossie")then
audio.play(ow)
count.life=count.life-1
if(count.life==0) then
gameOver()
end
event.other:removeSelf()
event.other=nil
else
event.other:removeSelf()
event.other=nil
end
end
end
local function countDown(e)
time_remain = time_remain-1
countdown.text = time_remain
end
local checkTimer = function()
if(time_remain == 0) then
gameOver()
end
end
function killIt(e)
if(e.phase == "ended") then
gameOver()
end
end
--spawn Bee
local function newBee(event)
bee = display.newImage("Images/lebah.png")
bee.x = 60 + math.random( 160 )
bee.y = -100
bee.type="other"
physics.addBody( bee, { density=1.4, friction=0.3, bounce=0.2} )
checkTimer()
bee:addEventListener("touch",killIt)
end
---whenMossieIsTouched
function onTouch(mossie)
audio.play(slap_sound)
count.touch=count.touch+1
total.text="Score : "..count.touch
mossie.target:removeSelf()
--print("total"..mossietouchcount)
end
---spawn Mossie
local function newMossie(event)
--audio.play(mossie_sound)
total.text="Score : "..count.touch
life.text="Life : "..count.life
mossie = display.newImage("Images/biasa.png")
mossie.x = 60 + math.random( 160 )
mossie.y = -100
mossie.type="mossie"
mossie:setFillColor(255,0,0)
physics.addBody( mossie, { density=0.3, friction=0.2, bounce=0.5} )
mossie.name = "mossie"
--checkTimer()
mossie:addEventListener("touch",onTouch)
end
local bottomWall = function()
--botwall=display.newRect(0,display.contentHeight,display.contentWidth*2,10)
botwall=display.newImage("Images/tangan.png")
botwall.x = 160
botwall.y = 500
botwall:setFillColor(22,125,185,255)
botwall.type="botwall"
botwall.collision=collisionListener
physics.addBody(botwall,"static",{ density=100.0, friction=0.0, bounce=0.0} )
botwall:addEventListener("collision",botwall)
end
local gameActivate = function()
gameIsActive = true
end
local gameStart = function()
local gametmr = timer.performWithDelay(1000, countDown, 0)
local dropMossie = timer.performWithDelay( 1000 , newMossie, -1 )
local dropBee = timer.performWithDelay( 1800 , newBee, -1)
local pauseGame = function(e)
if(e.phase=="ended") then
audio.play(buttonSound)
physics.pause()
timer.pause(gametmr)
pauseBtn.isVisible = false
resumeBtn.isVisible = true
return true
end
end
local resumeGame = function(e)
if(e.phase=="ended") then
audio.play(buttonSound)
physics.start()
timer.resume(gametmr)
pauseBtn.isVisible = true
resumeBtn.isVisible = false
return true
end
end
pauseBtn:addEventListener("touch", pauseGame)
resumeBtn:addEventListener("touch", resumeGame)
resumeBtn.isVisible = false
bottomWall()
gameActivate()
end
gameStart()
return scene
Make sure the scene is called "menu.lua" when you try to use the composer.gotoScene("menu")
First make sure you require the libraries at the top
local composer = require( "composer" )
local widget = require( "widget" )
Then add a listener that will handle the button events
local function handleButtonEvent( event )
if ( "ended" == event.phase ) then
composer.gotoScene ("menu")
end
end
And then create the button
local myButton = widget.newButton
{
left = 100,
top = 200,
id = "myButton",
label = "Default",
onEvent = handleButtonEvent
}
EDIT:
Looking at your code I can see you aren't actually using composer. Sure you might be including the libraries but you aren't setting up any of the functions required for it to work.
I suggest you read this article: Introducing the Composer API. This will guide you through the use of composer.
At the very least you should have the following functions for composer to work.
scene:create()
scene:show()
scene:hide()
scene:delete()
And within those utilize the the scene's view using local sceneGroup = self.view. Once objects been inserted into this properly you can have “manage” your scene and the display objects within.

how to make a button pressed only once in corona sdk and not repeatedly?

im making a questions app that when you pick the correct answer button a +1 is added to the score and -1 when selecting wrong answer,
How can I make buttons able to be pressed once, but then not pressable again after that? since score keeps adding if you keep pressing on the button!
this is button1:
local widget = require( "widget" )
local function handleButtonEvent( event )
if ( "ended" == event.phase ) then
minusScore()
print( "Button was pressed and released" )
end
end
local button1 = widget.newButton
{
width = 350,
height = 360,
left= 30,
top= 220,
defaultFile = "speakers.png",
overFile = "wrong.png",
--label = "button",
onEvent = handleButtonEvent
}
this is the score function..maybe theres a way that the score adds 1 then stops:
-------------------score------------------------
local score = 0
local scoreTxt = display.newText( "0", 0, 0, "Helvetica", 40 )
scoreTxt:setReferencePoint(display.TopLeftReferencePoint)
scoreTxt.x = display.screenOriginX + 700
scoreTxt.y = display.screenOriginY + 37
scoreTxt:setTextColor(2,2,2)
---------------------score added 10-----------------------------
function updateScore()
score = score + 1
_G.score = score
scoreTxt.text = string.format(" %d", score)
end
local scoretimer = timer.performWithDelay(1, updateScore,1)
---------------------score minus 1-----------------------------
function minusScore()
score = score - 1
_G.score = score
scoreTxt.text = string.format(" %d", score)
end
local scoretimer = timer.performWithDelay(1, minusScore,1)
You could do something like this:
local minusButtonPressed = false
local function handleButtonEvent( event )
if ( ( "ended" == event.phase ) and (minusButtonPressed == false) ) then
minusScore()
print( "Button was pressed and released" )
--disable the button
minusButtonPressed = true
end
end

"state" table that saves the score not working properly

I'm writing the code that would save the scores to a "state" table and it would continuously accumulate until it reaches the result page. I use the table because it says table is better than using 'globals'. I'm having problems with the accumulation as the scoreText resets to 0 when jumping to the next scene.
main.lua
display.setStatusBar( display.HiddenStatusBar )
local storyboard = require "storyboard"
storyboard.state = {}
storyboard.state.score = 0
storyboard.gotoScene( "scene_splash" )
Question1.lua
local scoreText
function scene:enterScene(event)
...
scoreText = display.newText( "0", 0, 0, native.systemFont, 32 )
scoreText:setFillColor( 0,0, 0 )
scoreText.x = 87
scoreText.y = 28
group:insert( scoreText )
if (event.other == balloons[1]) then
scene.updateScore()
print('Ball is colliding')
balloon1.isVisible = false
balloonText1.isVisible = false
audio.play(pop)
storyboard.gotoScene("correctAnswer1", "fade", 1000)
end
end
function scene.updateScore()
storyboard.state.score = storyboard.state.score + 50
scoreText.text = storyboard.state.score
end
Question2.lua
local scoreText
function scene:enterScene(event)
...
if (event.other == balloons[3]) then
scene.updateScore()
print('Ball is colliding')
balloon3.isVisible = false
balloonText3.isVisible = false
audio.play(pop)
storyboard.gotoScene("correctAnswer2", "fade", 1000)
end
end
function scene.updateScore()
storyboard.state.score = storyboard.state.score + 50
scoreText.text = storyboard.state.score
end
...
I made a minor mistake in a line and i changed it to:
scoreText = display.newText( storyboard.state.score, 0, 0, native.systemFont, 32 )
The problem is that the enterScene event does not have an other field so event.other is nil so the block of code where you call score.update does not get executed in either of the question scenes. You can check this by putting some print statements in update. The condition should be something else.

Resources