Add event listener problems

This may be a basic question but I am having trouble getting my bird object to move even though I have applied the correct (I think) code.

In line 35 I added the event listener as you can see. And in line 78 I created the function it references to. Am Im obviously doing something wrong so can you guys please help me out? Maybe it has something to do with the scene?

[lua]local storyboard = require( “storyboard” )
local scene = storyboard.newScene()

– include Corona’s “physics” library
local physics = require “physics”
physics.start(); physics.pause()


– forward declarations and other locals
local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth*0.5


– Called when the scene’s view does not exist:
function scene:createScene( event )
local group = self.view

– create the level background
local background = display.newImageRect( “Stage1BG.jpg”, display.contentWidth, display.contentHeight )
background:setReferencePoint( display.TopLeftReferencePoint )
background.x, background.y = 0, 0

– make the object, position it
local bird = display.newImage( “Bird2Side.png” )
bird.x = display.contentWidth/65 + 30
bird.y = display.contentHeight/2

– add physics to the bird
physics.addBody( bird, “dynamic”, { density=3.0, friction=0.3, bounce=0.2, radius=35 } )

–add an event listener to the bird
bird:addEventListener( “touch”, moveBird )

local startingBranch = display.newImage( “StartingBranch.png” )
startingBranch.x = display.contentWidth/65
startingBranch.y = display.contentHeight - 40
–add starting Branch as a physics body
physics.addBody(startingBranch, “static”, { friction=0.5 } )

local endingBranch = display.newImage(“EndingBranch.png”)
endingBranch.x = display.contentWidth
endingBranch.y = display.contentHeight - 40
–add ending Branch as a physics body
physics.addBody(endingBranch, “static”, { friction=0.5 })

local block1 = display.newImage(“WoodBlock1.png”)
block1.x = display.contentWidth/4
block1.y = display.contentHeight - 40
–add block 1 as physics body
physics.addBody( block1, “static”, { density=2.0, friction=0.3, bounce = 0.4 } )

local block2 = display.newImage(“WoodBlock2.png”)
block2.x = display.contentWidth/2
block2.y = display.contentHeight - 40
–add block 2 as physics body
physics.addBody( block2, “static”, { density = 1, friction = 2, bounce = 0.4, })

local block3 = display.newImage(“WoodBlock3.png”)
block3.x = display.contentWidth/1.33
block3.y = display.contentHeight - 40
–add block 3 as physics body
physics.addBody( block3, “static”, { density=2.0, friction=0.3, bounce = 0.4 } )

– all display objects must be inserted into group
group:insert( background )
group:insert( bird )
group:insert( block1 )
group:insert( block2 )
group:insert( block3 )
group:insert( startingBranch )
group:insert( endingBranch )
end

function scene:moveBird( event )
bird:applyLinearImpulse( 0 , -0.5, bird.x, bird.y)
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


– END OF YOUR IMPLEMENTATION

– “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[/lua] [import]uid: 162953 topic_id: 29298 reply_id: 329298[/import]

Try moving your moveBird function above your createScene function. Right now, because your createScene function comes first and the moveBird function comes after, the reference moveBird in line 35 is nil at that time (i.e., it doesn’t refer to anything yet at that time).

Let me know if this helps.

  • Andrew [import]uid: 109711 topic_id: 29298 reply_id: 117819[/import]

I changed the position as you suggested and it doesn’t work. However changing the name from “scene:moveBird” to just “moveBird” allowed the level to load, but the object still didn’t move when I clicked on it. [import]uid: 162953 topic_id: 29298 reply_id: 117824[/import]

I neglected to mention a third thing: the moveBird function makes reference to the bird variable, but since that variable is local to createBird, the moveBird function won’t have access to it. You can fix that by forward declaring the bird variable above either function, i.e., put the statement [lua]local bird[/lua] toward the top of your code, and then in createBird, just say [lua]bird = display.newImage( “Bird2Side.png” )[/lua] instead of [lua]local bird = display.newImage( “Bird2Side.png” )[/lua].

  • Andrew [import]uid: 109711 topic_id: 29298 reply_id: 117844[/import]

You’ve gotten some good advice, but you have two “scope” issues with the original code and a function implementation problem.

Lets look at the scope issues.

First, as previous people have stated, you need to move the function above the createScene() call. Since you try and reference moveBird() in createScene, Corona SDK needs to know about it first. Moving it above createScene() solves that.

The 2nd scope problem is the definition of “bird” itself. It is declared “local” to createScene, so that variable only exists inside of createScene. The easy fix is to add: “local bird” at the top of the module, perhaps around line 11 or 12 and then remove the word “local” from where you are creating “bird” inside of createScene().

Now for the function problems.

In Lua there are two different ways to setup event listeners (well 3, but we don’t need to go there). One where you pass the object itself in as the “self” parameter and one where it’s just a function call. Personally I find the latter easier and since event.target has my object in it, I don’t really need to access the “self” parameter.

By defining the function as scene:moveBird(event), there is an implicit first parameter, “self” that is passed. But to properly set this event listener up, you have to do this:

bird.touch = scene:moveBird  
bird:addEventListener("touch", bird)  

Notice that I passed my object to addEventListener, not the function.

I find that unnecessary in most cases, so what you need to do, IMHO is this:

  1. Rewrite the function:
local function moveBird(event)  
 ...  
end  

Then set up the handler:

bird:addEventListener("touch", moveBird)  

Like you are currently doing it. So drop the scene: from the function definition and you should be good to go.
[import]uid: 19626 topic_id: 29298 reply_id: 117877[/import]

thanks for the detailed reply! Putting the function above the create:scene function made sense. I also read through what you had to say and learned a few things. However its still not working! arghhh

here is how I have my code (I have just taken a snippet which involves the important parts) and I followed your instructions to the letter.

[lua]local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth*0.5
local bird = display.newImage( “Bird2Side.png” )


– BEGINNING OF YOUR IMPLEMENTATION

– NOTE: Code outside of listener functions (below) will only be executed once,
– unless storyboard.removeScene() is called.


local function moveBird(event)
bird:applyLinearImpulse( 0 , -1, bird.x, bird.y)
end
– Called when the scene’s view does not exist:
function scene:createScene( event )
local group = self.view

– create the level background
local background = display.newImageRect( “Stage1BG.jpg”, display.contentWidth, display.contentHeight )
background:setReferencePoint( display.TopLeftReferencePoint )
background.x, background.y = 0, 0

– make a bird (off-screen), position it, and rotate slightly
–bird = display.newImage( “Bird2Side.png” )
bird.x = display.contentWidth/65 + 30
bird.y = display.contentHeight/2

– add physics to the bird
physics.addBody( bird, “dynamic”, { density=3.0, friction=0.3, bounce=0.2, radius=35 } )

–add an event listener to the bird
bird:addEventListener( “touch”, moveBird )[/lua]
I have also tried putting the

[lua]bird:addEventListener( “touch”, moveBird )[/lua]

under the function and still nothing happens :frowning: [import]uid: 162953 topic_id: 29298 reply_id: 117942[/import]

Couple of minor nits to start with.

bird = display.newImage( “Bird2Side.png” )

should probably be in the createScene function, you just need to do:

local bird

at the top.

Next is your event handler. You look like everything is setup correctly, but if you end up creating multiple birds you need a way to reference which bird to move. I would re-write moveBird like this:

local function moveBird(event)  
 local target = event.target -- this is the bird that was touched  
 target:applyLinearImpulse( 0 , -1, target.x, target.y)  
end  

but wait… There is more…

The “touch” event will call your function multiple times: when you first touch the object, if you move your finger while touching it and when you lift your finger. These are called phases and have specific names: “began”, “ended”, “moved”. There are a couple of other rare ones, but these are the three you are interested in.

If you are building a button or want to simulate a tap, you really are only concerned with the “ended” phase as that most mimics how computer mouse clicks work. They tend to record the “click” as when the mouse button is released, not pressed.

If you want to drag something, you’re going to pay attention to all three. So lets re-write this properly having the app respond to apply your impulse on first tap (in case they hold their finger down too long…, waiting on “ended” may make more sense.

local function moveBird(event)  
 if event.phase == "began" then  
 local target = event.target -- this is the bird that was touched  
 target:applyLinearImpulse( 0 , -1, target.x, target.y)  
 end  
 return true  
end  

The last line, “return true” is very important. This tells Corona that your object handled that touch event and to not send it on to other objects behind it.

Now to address why it’s not working. I don’t know. The code looks like it should work.

Did you start physics with a physics.start()?

The bird’s density is 3.0… 3 times heavier than water. That means it weighs a lot. Heavy things are hard to move and you are only applying 1 meter/second/second force. Gravity is 9.8 mss. It’s possible that the impulse isn’t enough to really move the bird.

So how can we tell if the moveBird function is getting called?

Well that’s where out very good friend, the “print” statement comes in handy. It will dump text to the console so that you can see what is going on in your code. There are a few debugging/editors out there like Corona Complete and CIDER that will let you watch variables and set break points, but that may be over kill when you just want to know if your function is firing.

Let’s rewrite the function once again:

local function moveBird(event)  
 print("moveBird", event.phase, event.target.x, event.target.y)  
 if event.phase == "began" then  
 local target = event.target -- this is the bird that was touched  
 target:applyLinearImpulse( 0 , -1, target.x, target.y)  
 end  
 return true  
end  

If the function is getting called you should see something like:

moveBird: began 104 108  
moveBird: ended 104 108  

in your console. You will get one line when you first touch the object and another when you un-touch it. If you see these, your function is working and its likely your physics settings interfering with movement. If you don’t get these, then we need to look deeper into your code.

[import]uid: 19626 topic_id: 29298 reply_id: 117947[/import]

wow thanks so much for the detailed response! This solved all my problems and I tweaked the density and lo and behold it was WAY to high. So now I can make some good progress with this game! Once again thanks for the replies and I’m sure ill be in contact haha [import]uid: 162953 topic_id: 29298 reply_id: 117956[/import]