collision function not running - lua

I created 3 balloons(only need 3) and each of them contains a specific word and one of the words is the right answer. I shoot a ball from the cannon and hit the balloons. Assume the balloon 3 holds the balloonText3 which is the right answer, if i hit it the ball and the text disappears. For some reason, the ballCollision(event) doesn't run, i used print statement to confirm it. Whats wrong here?
local cannonBalls = display.newGroup()
...
local shot = function(event)
if(event.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})
cannonBalls:insert(cannonBall)
print ('shot')
-- Shoot cannon ball
cannonBall:applyLinearImpulse(3, impulse, cannonBall.x, cannonBall.y )
--Collision listener
print('event listener')
cannonBall:addEventListener ('collision', ballCollision)
end
end
function ballCollision(event)
if (event.other.name =='balloon3') then
scene.updateScore()
print('Ball is colliding')
timer.performWithDelay(1, e.target.removeSelf, e.target)
timer.performWithDelay(1, e.other.removeSelf, e.target)
balloonText3.isVisible = false
audio.play(pop)
end
end
function scene:createScene(event)
local group = self.view
...
local balloon1 = display.newImage ('balloon_fat_red.png', 495, 60)
local balloon2 = display.newImage ('balloon_fat_red.png', 495, 115)
local balloon3 = display.newImage ('balloon_fat_red.png', 495, 160)
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)
local balloonText1 = display.newText('\227\129\130', 495, 60)
balloonText1:setFillColor( 1,1, 0 )
local balloonText2 = display.newText('\227\129\132', 495, 115)
balloonText2:setFillColor( 1,1, 0 )
local balloonText3 = display.newText('\227\129\134', 495, 160)
balloonText3:setFillColor( 1,1, 0 )
group:insert(balloonText1)
group:insert(balloonText2)
group:insert(balloonText3)
end

I'm going to assume that you put the print statement in the if block of ballCollision, because I can't see anything else wrong with the listener registration. Also, I don't see anywhere in the code where you set the name attribute of the balloon object. So either
add balloon3.name = "balloon3" (and similarly for 1 and 2) after setting bodyType,
or (probably simpler)
use if event.other == balloons[3] then ... in the collision handler. You don't need parentheses around the condition in Lua.

Related

How do I make an object change direction on tap?

I'm very new to Lua. This is what I tried:
local function tapListener( event )
-- Code executed when the button is tapped
if crate.gravityScale == 1 then crate.gravityScale=-1
if crate.gravityScale == -1 then crate.gravityScale=1
-- "event.target" is the tapped object
return true
end
local myButton = display.newRect( 540, 960, 1080, 1920 )
myButton:setFillColor( 0, 0.01 )
myButton:addEventListener( "tap", tapListener )
-- Add a "tap" listener to the object
What is the correct way to do this? I can't really understand how to do it with just API reference.
.......
Edit 8/19/17:
I didn't like how it moved with gravity so I changed it to setLinearVelocity but now it won't change direction on tap. Here's what I tried:
speed = 400
-- make a crate (off-screen), position it, and rotate slightly
local crate = display.newImageRect( "crate.png", 90, 90 )
crate.x, crate.y = 540, 1750
crate.rotation = 0
physics.addBody( crate, "dyanamic" )
crate:setLinearVelocity(speed, 0)
local function tapListener( event )
speed = speed == 400 and -400 or 400
return true
end
local myButton = display.newRect( 540, 960, 1080, 1920 )
myButton:setFillColor( 0, 0.01 )
myButton:addEventListener( "tap", tapListener )
What did I do wrong?

Making specific text disappearing after it is hit

The code below removes a balloon when a bullet hits it. I'm stuck on how to make the specific balloonTexts disappear when they are hit by the bullet. For example, I wanted to make the balloon that has 'balloonText2' disappear when the bullet hits it. How do I detect its the second balloon i hit?
function createBalloons(a, b)
for i = 1, a do
for j = 1, b do
local balloon = display.newImage ('balloon_fat_red.png', 465+ (i * 30), 80 + (j * 50))
balloonText1 = display.newText(hiragana_array[x+1], 495, 125)
balloonText2 = display.newText(hiragana_array[x+2], 495, 175)
balloonText3 = display.newText(hiragana_array[x+3], 495, 225)
balloonText1:setFillColor( 1,1, 0 )
balloonText2:setFillColor( 1,1, 0 )
balloonText3:setFillColor( 1,1, 0 )
balloon.name = 'balloon'
physics.addBody(balloon)
balloon.bodyType = 'static'
table.insert(balloons, balloon)
end
end
target.text = #balloons
end
--ball collides with balloon
function ballCollision(e)
if (e.other.name == 'balloon') then
e.target:removeSelf()
e.other:removeSelf()
audio.play(pop)
score.text = score.text + 50
score.anchorX = 0
score.anchorY = 0
score.x = 200
score.y = 50
target.text = target.text - 1
end
You need to keep track of the balloonText's. What I would consider doing is adding the display objects for the text the balloon object:
local balloon = display.newImage ('balloon_fat_red.png', 465+ (i * 30), 80 + (j * 50))
balloon.balloonText1 = display.newText(hiragana_array[x+1], 495, 125)
balloon.balloonText2 = display.newText(hiragana_array[x+2], 495, 175)
balloon.balloonText3 = display.newText(hiragana_array[x+3], 495, 225)
Then in your collision handler:
e.target:removeSelf()
e.other.balloonText1:removeSelf()
e.other.balloonText2:removeSelf()
e.other.balloonText3:removeSelf()
e.other:removeSelf()
or something like that.
Can you assign name property of the text object. Then print e.other.name in collision function and see what's the output. I think e.other is getting nil, that's why it's not removing from the display group.

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.

What is wrong with the restart game function in corona

The restart game function doesn't seem to work and I don't know why. The balloons, scores resets but the game doesn't resets, i can't shoot the balloons again. (plus the askUser, yesBtn and noBtn doesn't go invisible either)
function createBalloons(a, b)
for i = 1, a do
for j = 1, b do
local balloon = display.newImage ('balloon_fat_red.png', 270+ (i * 30), 80 + (j * 50))
balloonText = display.newText(hiragana_array[x+1], 300, 125)
balloonTextt = display.newText(hiragana_array[x+2], 300, 175)
balloonTexttt = display.newText(hiragana_array[x+3], 300, 225)
balloonText:setFillColor( 1,1, 0 )
balloonTextt:setFillColor( 1,1, 0 )
balloonTexttt:setFillColor( 1,1, 0 )
balloon.name = 'balloon'
physics.addBody(balloon)
balloon.bodyType = 'static'
table.insert(balloons, balloon)
end
end
target.text = #balloons
end
function restartLvl()
for i = 1, #balloons do
display.remove(balloons[i])
print ("restart level")
end
score.text = '0'
ballRemain.text = '3'
balloons = {}
createBalloons(1, 3)
askUser.isVisible = false
yesBtn.isVisible = false
noBtn.isVisible = false
print("time from start: ", (system.getTimer()-gameTime))
print('send mail')
sendMail()
end
This is what it shows in the simulator.
I'm not seeing any problem with that code, my guess is the problem is elsewhere. You're going to have to dig a little more, maybe put some more print statements. For example maybe isVisible is being reset to true by another function, after the restartLvl, like in an enterFrame handler.

Attempt to index global "self"(a nil value)

I ran this code and it gave me an error attempt to index global 'self' (a nil value), in this scene i'm creating the Question1 of the game, inside which includes creating cannon, balloons and other game elements. I checked but i'm not sure whats wrong here.
function scene.createScene()
local group = self.view ---line 27 where i got the error
scoreText = display.newText( "0", 0, 0, globals.font.bold, 32 )
scoreText.x = display.contentCenterX
scoreText.y = 32
group:insert( scoreText )
background = display.newImage( "bkg_clouds.png")
group:insert(background)
background.x = 240
background.y = 195
questionText = display.newText('a', display.contentCenterX, display.contentWidth/4, native.systemFont, 40)
group:insert(questionText)
infoBar = display.newImage ("infoBar.png")
group:insert(infoBar)
background.x = 200
background.y = 100
restartBtn = display.newImage ("restartBtn.png")
group:insert(restartBtn)
background.x = 470
background.y = 300
cannon = display.newImage ("cannon.png")
group:insert(cannon)
background.x = 10
background.y = 270
cannon.anchorX = 0.5
cannon.anchorY = 0.5
restartBtn.isVisible = true
function createBalloons(a, b)
for i = 1, a do
for j = 1, b do
local balloon = display.newImage ('balloon_fat_red.png', 465+ (i * 30), 80 + (j * 50))
balloon.balloonText1 = display.newText(hiragana_array[x+1], 495, 125)
balloon.balloonText2 = display.newText(hiragana_array[x+2], 495, 175)
balloon.balloonText3 = display.newText(hiragana_array[x+3], 495, 225)
balloon.balloonText1:setFillColor( 1,1, 0 )
balloon.balloonText2:setFillColor( 1,1, 0 )
balloon.balloonText3:setFillColor( 1,1, 0 )
balloon.name = 'balloon'
physics.addBody(balloon)
balloon.bodyType = 'static'
table.insert(balloons, balloon)
end
end
target.text = #balloons
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 = 1
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 = false
cannon.rotation = 0
local 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(dir, impulse, cannonBall.x, cannonBall.y )
--Collision listener
cannonBall:addEventListener ('collision', ballCollision)
end
end
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
cannonBall:applyLinearImpulse(dir, impulse, cannonBall.x, cannonBall.y )
--Collision listener
cannonBall:addEventListener ('collision', ballCollision)
scene.view:insert( ballCollision )
end
You probably need function scene:createScene(). Note the colon instead of the dot in your original code.
Your function should be like this.
function scene:createScene( event )
local group = self.view
-----------------------------------------------------------------------------
-- CREATE display objects and add them to 'group' here.
-- Example use-case: Restore 'group' from previously saved state.
-----------------------------------------------------------------------------
end
Here is the reference:
http://docs.coronalabs.com/api/library/storyboard/

Resources