Delete a self object of a function [corona sdk] - lua

I have a little problem and I'm searching for an easy solution,
in my game, if a bullet touches a specific ennemy, this target should be deleted and respawn otherwhere,
I'm using the self-collision event to make the instructions single to each ennemy,
the problem is that self-collision function only works if he recognise the target, but as I delete it the first time in my collision function, that ennemy doesn't exist anymore for my function. It works only the first time.
I hope that my problem is understandable,
here is an example of the code:
local ennemy
ennemy = display.newRect(0,0, 20, 50)
transition.to( ennemy, {time = 2000, x = 240, y = 160} )
local function onCollision(self,event)
display.remove( bullet )
display.remove( ennemy )
ennemy = display.newRect(0,0, 20, 50)
transition.to( ennemy, {time = 2000, x = 240, y = 160} )
end
ennemy.collision = onCollision
ennemy:addEventListener( "collision", ennemy )

You only do addEventListener() for the first enemy object, after a collision you have a brand new enemy object which also needs to have it's collision listener setup.
local onCollision -- forward declare onCollision() so we can use it from addEnemy()
local enemy
local function addEnemy()
enemy = display.newRect(0,0, 20, 50)
-- new object so need to assign collision listener again
enemy.collision = onCollision
enemy:addEventListener( "collision", enemy )
transition.to( enemy, {time = 2000, x = 240, y = 160} )
end
local function onCollision(self,event)
display.remove( bullet )
display.remove( enemy )
addEnemy()
end
-- Add first enemy…
addEnemy()

Related

Corona SDK. Lua. display.newText() - my updated score text is overlapping old one without erasing

I'm developing clone version of Nintendo Tetris game using Corona SDK. There are two text objects on the top of my screen: one represents current level, another one represents current score. Every time I fill in line with blocks my program erases this line and add some scores and +1 level. The problem is that once I update my score and level variables and use myText.text to refresh my texts it doesn't erase old text and creates the new text that overlapping the old one.
My code is following:
1) I declare two local variables at the begging of my scene
local scoreText
local levelText
2) I have function that erases the line and updates texts
function eraseLines()
-- some code that erases lines
scores = scores + 10
scoreText.text = "Score:"..scores
level = level + 1
levelText.text = "Level:"..level
end
3) In scene:show(event) I create our texts
function scene:show( event )
-- some code
scoreText = display.newText("Score:"..scores, halfW*0.5, 20 )
levelText = display.newText("Level:".. level, halfW*1.5, 20 )
sceneGroup:insert( scoreText )
sceneGroup:insert( levelText )
scoreText:setFillColor( 0, 0, 0 )
levelText:setFillColor( 0, 0, 0 )
end
Please help me to find out why overlapping happens
At the moment you are adding twice score/level labels, 'cause the show event is called two times (phases) will and did. Add display objects when you are creating the scene.
-- create()
function scene:create( event )
local sceneGroup = self.view
-- Code here runs when the scene is first created but has not yet appeared on screen
scoreText = display.newText( "Score: 0", halfW * 0.5, 20 )
levelText = display.newText( "Level: 0", halfW * 1.5, 20 )
sceneGroup:insert( scoreText )
sceneGroup:insert( levelText )
scoreText:setFillColor( 0, 0, 0 )
levelText:setFillColor( 0, 0, 0 )
end
-- show()
function scene:show( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
-- Code here runs when the scene is still off screen (but is about to come on screen)
scoreText.text = "Score: " .. score
levelText.text = "Level: " .. level
elseif ( phase == "did" ) then
-- Code here runs when the scene is entirely on screen
end
end
Here's a poorly constructed single script for displaying score
local scoreCounter = {}
local frameTime = 0
scoreCount = 0
finalScore = nil
local tempText = nil
local function update( event )
frameTime = frameTime + 1
--after every 7 frames score will increase
if(frameTime % 7 == 0) then
scoreCount = scoreCount + 1
tempText.text = scoreCount
frameTime = 0
end
end
-- here is a memory leak I guess
function scoreCounter.displayScore(xCoordinate, yCoordinate)
tempText = display.newText(scoreCount, xCoordinate, yCoordinate)
end
Runtime:addEventListener("enterFrame", update)
return scoreCounter
Usage:
local scoreCounter = require("pathtoluafile")
scoreCounter.displayScore(xCoordinate, yCoordinate)

Corona : ScoreText writing new score over the old one

My code writes the score ( final score) over the old one ( without deleting it) So when it's counting again we can actually see the old score ( the last one that the player had) written on the back of the counter. ( and when it shows the new highscore, we can also see the old one on the back )
local physics = require "physics"
physics.start()
--physics.setContinuous( false )
local storyboard = require "storyboard"
local scene = storyboard.newScene()
display.setDefault( "anchorX", 0 )
display.setDefault( "anchorY", 0 )
--local mydata = require( "mydata" )
--mydata.score = 0
score = 0
function scene:createScene(event)
local screenGroup = self.view
sky = display.newImage("bg.jpg")
sky.x = 820; sky.y = 0. sky.rotation = 90
screenGroup:insert(sky)
mountain1 = display.newImage("montagne2.png")
mountain1.x = -200; mountain1.y = 600
mountain1.speed = 0.5
screenGroup:insert(mountain1)
end
local scoreNumber = display.newText(score, 400, 0, nil, 50)
scoreNumber.xScale = 1.2
scoreNumber.yScale = 1.2
if scoreNumber then
scoreNumber:removeSelf()
end
local function updateScore()
score = score + 1
scoreNumber.text = score
--mydata.score = mydata.score + 1
end
scoreTimer = timer.performWithDelay(100, updateScore, -1)
local scoreText = display.newText("score:", 0, 0, nil, 50)
scoreText.xScale = 1.2
scoreText.yScale = 1.2
screenGroup:insert( scoreNumber)
end
function scene:exitScene(event)
Runtime:removeEventListener("touch", touchScreen)
Runtime:removeEventListener("enterFrame", mountain1)
Runtime:removeEventListener("enterFrame", mountain2)
Runtime:removeEventListener("enterFrame", mountain3)
Runtime:removeEventListener("enterFrame", mountain4)
Runtime:removeEventListener("enterFrame", missile1)
Runtime:removeEventListener("enterFrame", obst1)
Runtime:removeEventListener("enterFrame", obst2)
Runtime:removeEventListener("enterFrame", obst3)
Runtime:removeEventListener("enterFrame", obst4)
Runtime:removeEventListener("enterFrame", obst5)
Runtime:removeEventListener("enterFrame", obst6)
Runtime:removeEventListener("collision", onCollision)
timer.cancel(scoreTimer)
timer.cancel(memTimer)
end
function scene:destroyScene(event)
end
scene:addEventListener("createScene", scene)
scene:addEventListener("enterScene", scene)
scene:addEventListener("exitScene", scene)
scene:addEventListener("destroyScene", scene)
return scene
I'm not 100% sure we are seeing enough code or more importantly the right code, but there are a couple of things going on.
local scoreNumber = display.newText(score, 400, 0, nil, 50)
scoreNumber.xScale = 1.2
scoreNumber.yScale = 1.2
if scoreNumber then
scoreNumber:removeSelf()
end
In this block of code, you create scoreNumber and immediately remove it. You also never add it to the scene's view group: screenGroup:insert( scoreNumber)
local function updateScore()
score = score + 1
scoreNumber.text = score
--mydata.score = mydata.score + 1
end
scoreTimer = timer.performWithDelay(100, updateScore, -1)
This will likely crash your app since every 100 milliseconds (1/10th of a second) you call updateScore, which tries to reference scoreNumber which you removed right above it.
local scoreText = display.newText("score:", 0, 0, nil, 50)
scoreText.xScale = 1.2
scoreText.yScale = 1.2
Now you've created scoreText, but I never see you insert it into the screenGroup, nor do I see you ever update it's value.
You have a lot of other things going on. I don't see where you're setting the default anchor points (if you even are) and if you're not, display objects are centered on their X and Y values. So scoreNumber, for the brief time it draws will be centered 400px from the left and 0px from the top. This puts at least the top half of the text off screen. Then you scale it up for some reason. Why not just use a larger font? 50 * 1.2 = 60. Then scoreText is drawn at 0, 0 which not only puts the top half off screen, it puts the left half off screen.
Remember if you want Storyboard to manage your display objects, they must be inserted in to the screenGroup for you and you should not have to remove them yourself.

Attempt to Index GlobalCredits 'event' (a nil value)

I have just started to learn LUA in school, but i cannot find many helpful tutorials o the internet to aid in my learning. I have made a simple game (which doesn't work yet, i realize that) and a main menu. However, when i try to start the app, it gives me this error:
/Users/jordanmcbride/Desktop/Lua Projects/Tapinator/main.lua:47: attempt to index global 'showCredits' (a nil value)
stack traceback:
/Users/jordanmcbride/Desktop/Lua Projects/Tapinator/main.lua:47: in main chunk
[Finished in 9.4s]
I have looked the error, and I cannot seem to understand how to fix it. The other questions have said something about returning the function returning a nil value, and that I should add a return statement to the end, but that doesn't work either.
Here is the code # line 47.
function showCredits.touch(e)
playButton.isVisible = false
creditsButton.isVisible = false
creditsView = display.newImage('credits.png', 0, display.contentHeight)
lastY = name.y
transition.to(name, {time = 300, y = display.contentHeight * 0.5 - title.height - 25})
transition.to(creditsView, {time = 300, y = display.contentHeight * 0.5 + creditsView.height, onComplete = function() creditsView:addEventListener('tap', hideCredits) end})
end
Here is my full code, in case the problem lies elsewhere:
display.setStatusBar(display.HiddenStatusBar)
radius = 40
smallTime = 200
bigTime = 800
score = 0
scoreInc = 2000
--HomePage
local name
local playButton
local creditsButton
local homePage
--Credits
local creditsPage
--Sounds
local circleSpawn = audio.loadSound( "circle_spawn.wav" )
local circleTap = audio.loadSound( "circle_tap.wav" )
function Main()
name = display.newImage('title.png', display.contentWidth / 2, 53)
name:scale( .5, .5 )
playButton = display.newImage('playButton.png', display.contentWidth / 2, 245)
playButton:scale( .5, .5 )
creditsButton = display.newImage('creditsButton.png', display.contentWidth / 2, 305)
creditsButton:scale( .5, .5 )
homePage = display.newGroup(name, playButton, creditsButton)
startButtonListeners('add')
end
function showCredits.touch(e)
playButton.isVisible = false
creditsButton.isVisible = false
creditsView = display.newImage('credits.png', 0, display.contentHeight)
lastY = name.y
transition.to(name, {time = 300, y = display.contentHeight * 0.5 - title.height - 25})
transition.to(creditsView, {time = 300, y = display.contentHeight * 0.5 + creditsView.height, onComplete = function() creditsView:addEventListener('tap', hideCredits) end})
end
function hideCredits.touch(e)
transition.to(creditsView, {time = 300, y = display.contentHeight, onComplete = function() creditsButton.isVisible = true playButton.isVisible = true creditsView:removeEventListener('tap', hideCredits) display.remove(creditsView) creditsView = nil end})
transition.to(name, {time = 300, y = lastY});
end
function startButtonListeners(action)
if(action == 'add') then
playButton:addEventListener('touch', playGame)
creditsButton:addEventListener('touch', showCredits)
else
playButton:removeEventListener('touch', playGame)
creditsButton:removeEventListener('touch', showCredits)
end
end
Main()
printScore = display.newText("Score: " .. tostring(score), display.contentWidth-80, 40, native.systemFontBold, 20)
-- A function that creates random circles
function generateCircle ()
-- Creates a new circle between 0 (the left most bounds) and the width of the display (being the content width), and also
-- 0 (the upper most bounds) and the height of the display (being the content height). The radius of the circle is 'radius'
x = math.random(radius, display.contentWidth-radius)
y = math.random(80, display.contentHeight)
score = score + scoreInc
myCircle = display.newCircle( x, y, radius )
myCircle:setFillColor( math.random(), math.random(), math.random() )
delayTime = math.random(smallTime, bigTime)
score = score + scoreInc
printScore.text = "Score:"..tostring(scores)
local spawnChannel = audio.play( circleSpawn )
timer.performWithDelay( delayTime, generateCircle )
end
generateCircle()
function myCircle:touch( event )
local tapChannel = audio.play( circleTap )
myCircle:removeSelf()
end
myCircle:addEventListener( "touch", myCircle )
The answer by greatwolf will work. But just a tip from my experience. One way I like to create functions is to try to define the name of the function first near the top of the lua file. Then I will define the function later on in the file. Something like this:
--function preallocation
local onPlayTap
local onSoundOnTap
local onSoundOffTap
local onCreditsTap
local onHelpTap
---------------------------------------------------------------------------------
-- Custom Function Definitions
---------------------------------------------------------------------------------
--Called when Sound On Button is tapped, turn off sound
onSoundOnTap = function(event)
end
--Called when Sound Off Button is tapped, turn on sound
onSoundOffTap = function(event)
end
--Called when Credits button is tapped, shows credits
onCreditsTap = function(event)
end
--Called when Help button is tapped, shows help
onHelpTap = function(event)
end
--Callback to Play button. Moves scene to Level Picker Scene
onPlayTap = function(event)
end
What this does is allow each function to be called by any other function in the file. If you do it the way you are doing it by adding the function name before the function like so:
local showCredits = {}
function showCredits.touch(e)
end
local hideCredits = {}
function hideCredits.touch(e)
end
your showCredit function will not be able to call the hideCredits function below it because the hideCredits variable has not been defined yet when the showCredit function was defined. Although this may not effect your current game, in future apps or games, you may need to call functions inside of other functions. To make this work properly, predefine all your function variables first, then define all your function afterwards. Hope this helps.

physics doesn't work in lua

This code creates a cannon and 3 balloons, the cannon should shoot out a bullet that'll destroy balloons, along with the words. DUring the process the cannon should rotate and when i release my finger from the screen it shoots. For some reason it doesn't respond, cannon not rotating nor any bullet is shot.
local score = 0
local scoreText
local scoreForLevelComplete
local background
local infoBar
local restartBtn
local cannon
local levelNum
local cannonCharge = {}
local shot = {}
local cannonBall
local impulse = 0
local balloons = {}
local cannonCharge = {}
local shot = {}
function scene:createScene(event)
local group = self.view
background = display.newImage( "bkg_clouds.png")
group:insert(background)
background.x = 230
background.y = 195
scoreText = display.newText( "0", 0, 0, native.systemFont, 32 )
scoreText:setFillColor( 0,0, 0 )
scoreText.x = 87
scoreText.y = 28
group:insert( scoreText )
questionText = display.newText('a', display.contentCenterX, display.contentWidth/4, native.systemFont, 40)
group:insert(questionText)
infoBar = display.newImage ("infoBar.png")
group:insert(infoBar)
infoBar.x = 10
infoBar.y = 25
restartBtn = display.newImage ("restartBtn.png")
group:insert(restartBtn)
restartBtn.x = 470
restartBtn.y = 300
cannon = display.newImage ("cannon.png")
group:insert(cannon)
cannon.x = 10
cannon.y = 270
cannon.anchorX = 0.5
cannon.anchorY = 0.5
restartBtn.isVisible = true
local balloon = display.newImage ('balloon_fat_red.png', 495, 125)
group:insert(balloon)
balloon = display.newImage ('balloon_fat_red.png', 495, 175)
group:insert(balloon)
balloon = display.newImage ('balloon_fat_red.png', 495, 225)
group:insert(balloon)
local balloonText1 = display.newText('\227\129\130', 495, 125)
balloonText1:setFillColor( 1,1, 0 )
local balloonText2 = display.newText('\227\129\132', 495, 170)
balloonText2:setFillColor( 1,1, 0 )
local balloonText3 = display.newText('\227\129\134', 495, 225)
balloonText3:setFillColor( 1,1, 0 )
balloon.name = 'balloon'
physics.addBody(balloon)
balloon.bodyType = 'static'
table.insert(balloons, balloon)
group:insert(balloonText1)
group:insert(balloonText2)
group:insert(balloonText3)
function ballCollision(e)
if (e.other.name == 'balloon') then
scene.updateScore()
e.target:removeSelf()
print ('remove balloon text')
e.other:removeSelf()
audio.play(pop)
end
end
function cannonCharge:touch(e)
if(e.phase == 'began') then
impulse = 0
cannon.isVisible = true
Runtime:addEventListener('enterFrame', charge)
end
end
function charge()
local degreesPerFrame = 0.5
cannon.rotation = cannon.rotation - degreesPerFrame
impulse=impulse-0.2
if(cannon.rotation < -46) then
cannon.rotation = -46
impulse = -3.2
end
end
function shot:touch(e)
if(e.phase == 'ended') then
Runtime:removeEventListener('enterFrame', charge)
cannon.isVisible = true
cannon.rotation = 0
cannonBall = display.newImage('cannon ball.png', 84, 220)
physics.addBody(cannonBall, {density = 1, friction = 0, bounce = 0})
group:insert(cannonBall)
-- Shoot cannon ball
cannonBall:applyLinearImpulse(3, impulse, cannonBall.x, cannonBall.y )
--Collision listener
cannonBall:addEventListener ('collision', ballCollision)
end
end
end
This is my enterscene function
function scene:enterScene( event )
local group = self.view
background:addEventListener('touch', cannonCharge)
background:addEventListener('touch', shot)
end
I know the Corona docs say that listener can be a table object when call addEventListener('event', listener) but I have never seen or used that. There is no advantage in posted code to have functions defined inside the createScene since they are global and you already have a bunch or module-local variables. Try pulling the listeners out and making them regular functions:
local canon
...
local cannonCharge = function(event)
if event.phase == 'began' then
impulse = 0
cannon.isVisible = true
Runtime:addEventListener('enterFrame', charge)
end
end
local shot = function(event)
...
end
local function charge()
...
end
... other local functions ...
function scene:createScene(event)
...
end
Also, confirm that your touch listeners are being called by printing something inside each one.
Finally, and most importantly, you only added the last balloon to the physics so the bullet can only collide with that one balloon. The same way that you had to add group:insert(balloon) after each balloon created, you should have physics.addBody(balloon, ...) after each group insert. So do this:
local balloon1 = display.newImage ('balloon_fat_red.png', 495, 125)
local balloon2 = display.newImage ('balloon_fat_red.png', 495, 175)
local balloon3 = display.newImage ('balloon_fat_red.png', 495, 225)
group:insert(balloon1)
group:insert(balloon2)
group:insert(balloon3)
physics.addBody(balloon1)
physics.addBody(balloon2)
physics.addBody(balloon3)
balloon1.bodyType = 'static'
balloon2.bodyType = 'static'
balloon3.bodyType = 'static'
table.insert(balloons, balloon1)
table.insert(balloons, balloon2)
table.insert(balloons, balloon3)
There is a lot of code duplication there, and adding more balloons requires many lines to change, so you might as well factor out the duplicate code into a function:
local function createBalloon(x, y)
local balloon = display.newImage ('balloon_fat_red.png', x, y)
group:insert(balloon)
physics.addBody(balloon)
balloon.bodyType = 'static'
table.insert(balloons, balloon)
end
createBalloon(495, 125)
createBalloon(495, 175)
createBalloon(495, 225)
which has the advantage that if you need more balloon you won't forget any settings, and any new settings put in createBallon so all balloons have same config (except for function parameters like x,y etc).
Update: Determine which balloon in collision handler
Depends why you need to know which of the balloons. For example if it's because balloon 1 gives 10 pts while 3 gives 30, then there are better ways: you can add your fields to objects, like you could have balloon1.points = 10, balloon2.points = 30 etc (you would make that a function argument of createBalloon) and in collision handler just use score = score + e.other.points. You should only need to use Local Collision Handling because only need to know when the cannon ball collides with balloons. To figure out if e.other is a balloon, easiest is to add a property when you create balloon:
local function createBalloon(x, y, balloonText)
local balloon = ...
...
balloon.isBalloon = true -- only balloon objects will have this
balloon.label = balloonText
end
Couple notes on the above: another custom property is label since you want to remove the balloon text in the collision handler, easiest is to have a property for it. But do not remove objects involved in collision in the collision handler, as explained in that document, use delayed removal. So your handler becomes
function ballCollision(e)
if e.other.isBalloon then
scene.updateScore(e.other.points)
timer.performWithDelay(1, e.target.removeSelf, e.target)
timer.performWithDelay(1, e.other.removeSelf, e.target)
e.other.label:removeSelf() -- this is ok: not involved in collision
audio.play(pop)
end
end
You have declared balloons as a array and using the balloon
as a variable while assigning images to them. So you need to declare 3 separate balloon object like balloon text or if you are using array then you need to declare like this.
for i=1,3 do
balloon[i] = display.newImage ('balloon_fat_red.png', 495, 225)
group:insert(balloon[i])
end
So it will identify which balloon you want to shoot.

Lua/Corona sdk error

I'm having this issue, and I can't find a solution:
"level1.lua:161 attempt to index global 'crate' (a nil value)"
It happens when it should change the crate position on line 161, but "centerX + (centerX * event.xGravity" does not return nil, cause the "textMessage" show the correct value.
Code below
-----------------------------------------------------------------------------------------
--
-- level1.lua
--
-----------------------------------------------------------------------------------------
local storyboard = require( "storyboard" )
local scene = storyboard.newScene()
-- include Corona's "physics" library
local physics = require "physics"
physics.start(); physics.pause()
--------------------------------------------
-- Sounds
local shakeSound = audio.loadSound ("shake.mp3")
-- Display, metrics stuff
local centerX = display.contentWidth / 2
local centerY = display.contentHeight / 2
-- forward declarations and other locals
local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth*0.5
-----------------------------------------------------------------------------------------
-- BEGINNING OF YOUR IMPLEMENTATION
--
-- NOTE: Code outside of listener functions (below) will only be executed once,
-- unless storyboard.removeScene() is called.
--
-----------------------------------------------------------------------------------------
-- Text parameters
local labelx = 50
local x = 220
local y = 95
local fontSize = 24
local frameUpdate = false -- used to update our Text Color (once per frame)
local xglabel = display.newText( "gravity x = ", labelx, y, native.systemFont, fontSize )
xglabel:setTextColor(255,255,255)
local textMessage = function( str, location, scrTime, size, color, font )
local x, t
size = tonumber(size) or 24
color = color or {255, 255, 255}
font = font or "Helvetica"
-- Determine where to position the text on the screen
if "string" == type(location) then
if "Top" == location then
x = display.contentHeight/4
elseif "Bottom" == location then
x = (display.contentHeight/4)*3
else
-- Assume middle location
x = display.contentHeight/2
end
else
-- Assume it's a number -- default to Middle if not
x = tonumber(location) or display.contentHeight/2
end
scrTime = (tonumber(scrTime) or 3) * 1000 -- default to 3 seconds (3000) if no time given
t = display.newText(str, 0, 0, font, size )
t.x = display.contentWidth/2
t.y = x
t:setTextColor( color[1], color[2], color[3] )
-- Time of 0 = keeps on screen forever (unless removed by calling routine)
--
if scrTime ~= 0 then
-- Function called after screen delay to fade out and remove text message object
local textMsgTimerEnd = function()
transition.to( t, {time = 500, alpha = 0},
function() t.removeSelf() end )
end
-- Keep the message on the screen for the specified time delay
timer.performWithDelay( scrTime, textMsgTimerEnd )
end
return t -- return our text object in case it's needed
end -- textMessage()
-- Called when the scene's view does not exist:
function scene:createScene( event )
local group = self.view
-- create a grey rectangle as the backdrop
local background = display.newRect( 0, 0, screenW, screenH )
background:setFillColor( 128 )
-- make a crate (off-screen), position it, and rotate slightly
local crate = display.newImage('crate.png') --display.newImageRect( "crate.png", 90, 90 )
crate.x = centerX
crate.y = centerY
crate.rotation = 15
-- add physics to the crate
physics.addBody( crate, { density=1.0, friction=0.3, bounce=0.3 } )
-- create a grass object and add physics (with custom shape)
local grass = display.newImageRect( "grass.png", screenW, 82 )
grass:setReferencePoint( display.BottomLeftReferencePoint )
grass.x, grass.y = 0, display.contentHeight
-- define a shape that's slightly shorter than image bounds (set draw mode to "hybrid" or "debug" to see)
local grassShape = { -halfW,-34, halfW,-34, halfW,34, -halfW,34 }
physics.addBody( grass, "static", { friction=0.3, shape=grassShape } )
-- all display objects must be inserted into group
group:insert( background )
group:insert( grass)
group:insert( crate )
end
-- Called immediately after scene has moved onscreen:
function scene:enterScene( event )
local group = self.view
physics.start()
end
-- Called when scene is about to move offscreen:
function scene:exitScene( event )
local group = self.view
physics.stop()
end
-- If scene's view is removed, scene:destroyScene() will be called just prior to:
function scene:destroyScene( event )
local group = self.view
package.loaded[physics] = nil
physics = nil
end
-- Accelerometer
local function onAccelerate( event )
-- Move our object based on the accelerator values --
textMessage( tostring(centerX + (centerX * event.xGravity)), "naosei", 0.5, 12, {255, 255, 0} )
crate.x = centerX + (centerX * event.xGravity)
crate.y = centerY + (centerY * event.yGravity * -1)
-- sound beep if Shake'n
if event.isShake == true then
textMessage( "Shake!", "Top", 3, 52, {255, 255, 0} )
audio.play( shakeSound )
end
end
-----------------------------------------------------------------------------------------
-- END OF YOUR IMPLEMENTATION
-----------------------------------------------------------------------------------------
-- Add runtime listeners
Runtime:addEventListener ("accelerometer", onAccelerate);
-- Add scene listeners
-- "createScene" event is dispatched if scene's view does not exist
scene:addEventListener( "createScene", scene )
-- "enterScene" event is dispatched whenever scene transition has finished
scene:addEventListener( "enterScene", scene )
-- "exitScene" event is dispatched whenever before next scene's transition begins
scene:addEventListener( "exitScene", scene )
-- "destroyScene" event is dispatched before view is unloaded, which can be
-- automatically unloaded in low memory situations, or explicitly via a call to
-- storyboard.purgeScene() or storyboard.removeScene().
scene:addEventListener( "destroyScene", scene )
-----------------------------------------------------------------------------------------
return scene
"level1.lua:161 attempt to index global 'crate' (a nil value)"
Because there is no crate variable in scope on line 161.
You do have a variable named crate inside of createScene but it's local, so it's only visible within that function. Line 161 is a different function (onAccelerate), there is no local crate variable in scope there, so Lua looks for a global (_G['crate']), gets back nil, and you try to index that. Hence the error.
Easiest fix: remove the keyword local from the crate on line 108, so you create a global. It's not pretty, but it should work.
I would avoid using global variables because of memory leak issues.
What I do is define the display object names in the root scope and then set them from within the createScene function. I think this helps lua to do garbage collection.
local background, crate
function scene:createScene( event )
local group = self.view
local background = display.newRect( 0, 0, screenW, screenH )
local crate = display.newImage('crate.png')
group:insert( background )
group:insert( crate )
end

Resources