Why is event.target set to nil?

local widget = require("widget") local spawnedObjects = {} local function myTouchListener( event ) if(event.phase == "began") then -- if (event.target ~= nil) then if (target ~= nil) then timer.performWithDelay(1, function() event.target:removeSelf() end) timer.performWithDelay(1, function() event.target = nil end) end end return true -- returning true "prevents touch propagation to underlying objects" end local function spawnBubble(bubbleSize) local bubble = display.newCircle(0, 0, bubbleSize) bubble:setFillColor(.5, .5, .5) bubble.radius = bubbleSize bubble.x = 400 bubble.y = 600 spawnedObjects[#spawnedObjects+1] = bubble spawnedObjects[#spawnedObjects]:addEventListener( "touch", myTouchListener ) end local function circleGrow() for i = 1,#spawnedObjects do if (spawnedObjects[i] ~= nil) then local storedRadius = spawnedObjects[i].radius local storedX = spawnedObjects[i].x local storedY = spawnedObjects[i].y storedRadius = storedRadius + 1 print(spawnedObjects[i].radius) spawnedObjects[i]:removeSelf() -- spawnedObjects[i] = nil spawnedObjects[i] = display.newCircle(storedX, storedY, storedRadius) spawnedObjects[i].radius = storedRadius spawnedObjects[i]:setFillColor(.5, .5, .5) spawnedObjects[i]:addEventListener( "touch", myTouchListener ) end end end spawnBubble(100) timer.performWithDelay( 100, circleGrow, 0)  

My problem is a simple-ish one, but I cannot seem to figure out to solution. I have the above code, and I am trying to make a sample game, where you have many growing circles, or bubbles, and they disappear on touch. However, something is not working. it keeps reporting that target == nil. (line 10). I do not know why this is, but if anyone could help me I would be very grateful. I can make the circles, and have them increase their radii by 1 ten times every second, but I cannot make them do anything on touch. I used to have it so that there was no if statement surrounding lines 11-12, but then there would be an error. I have also tried another if statement (seen but commented out on line 9). This would check if event.target==nil, which I think should work. So, why does it think that target==nil? Why does it not execute the lines of code in the if statement? it seems to me that the conditional is true, that the target is not a nil value.

You declare target, but you don’t assign anything to it, therefore it is nil.

It looks like you want to use event.target.  If you are getting an error using event.target, what is it?  If I had to guess, it is because you are using two performWithDelays on an item you are trying to remove.

See if this removes your error… replace line 11 and 12 with this.

timer.performWithDelay(1, function() event.target:removeSelf() event.target = nil end)

Unfortunately, that did not work. I am getting a different error message.

“main.lua:50: attempt to call method ‘removeSelf’ (a nil value)”

line 50 is:

spawnedObjects[i]:removeSelf()

Thank you for replying, but this does not solve my error. I do not seem to recall where I declared target, either…

Any help is much appreciated!

Well that error indicates that spawnedObjects[i] is no longer a display object.  It’s been overwritten with something else or is nil itself.  Perhaps “i” isn’t what you think it is.

The problem with target not being defined is here.  I’m not going to use code formatting so I can highlight the area:

local function myTouchListener( event )

    if(event.phase == “began”) then

        – if (event.target ~= nil) then

        if ( target ~= nil ) then   – should be event.target not just “target”

            timer.performWithDelay(1, function() event.target:removeSelf() end)

            timer.performWithDelay(1, function() event.target = nil end)

                          – consider replacing the two lines above, with just one:

            timer.performWithDelay(1, function() event.target:removeSelf(); event.target = nil; end)

        end

    end

    return true

    – returning true “prevents touch propagation to underlying objects”

end

Rob

Hmm. Thank you for your input. I fixed my problem by accident, but I don’t understand why my code is working now. I changed the conditionals in the if statements on line 39 to “if (spawnedObjects[i].removeSelf ~= nil) then”. However, I do not quite understand why this works. Is removeSelf an attribute? I thought that it was simply a function. Once again, any help is appreciated.

:removeSelf() is a function that’s part of a display object.  It will only be on things created by display.newImage(), display.newImageRect(),  display.newCircle() etc. 

If this line of code:

if (spawnedObjects[i].removeSelf ~= nil)

is in your myTouchListener, there is no guarantee that “i” will be the value you expect it to be when the touch handler fires.   This is why you should event.target since it’s the object that was touched.

Rob

I appreciate your reply, and I do not mean to be offensive in any way, but the line of code which I previously mentioned is not in myTouchListener. As I mentioned, it is on line 39, and you can scroll up to see my code. It is in the function circleGrow, which makes each circle increase their radius by 1 pixel every 10 milliseconds. I understand how the function “object:removeSelf()” works, but why it is treated as an attribute instead of a function?

You declare target, but you don’t assign anything to it, therefore it is nil.

It looks like you want to use event.target.  If you are getting an error using event.target, what is it?  If I had to guess, it is because you are using two performWithDelays on an item you are trying to remove.

See if this removes your error… replace line 11 and 12 with this.

timer.performWithDelay(1, function() event.target:removeSelf() event.target = nil end)

Unfortunately, that did not work. I am getting a different error message.

“main.lua:50: attempt to call method ‘removeSelf’ (a nil value)”

line 50 is:

spawnedObjects[i]:removeSelf()

Thank you for replying, but this does not solve my error. I do not seem to recall where I declared target, either…

Any help is much appreciated!

Well that error indicates that spawnedObjects[i] is no longer a display object.  It’s been overwritten with something else or is nil itself.  Perhaps “i” isn’t what you think it is.

The problem with target not being defined is here.  I’m not going to use code formatting so I can highlight the area:

local function myTouchListener( event )

    if(event.phase == “began”) then

        – if (event.target ~= nil) then

        if ( target ~= nil ) then   – should be event.target not just “target”

            timer.performWithDelay(1, function() event.target:removeSelf() end)

            timer.performWithDelay(1, function() event.target = nil end)

                          – consider replacing the two lines above, with just one:

            timer.performWithDelay(1, function() event.target:removeSelf(); event.target = nil; end)

        end

    end

    return true

    – returning true “prevents touch propagation to underlying objects”

end

Rob

Hmm. Thank you for your input. I fixed my problem by accident, but I don’t understand why my code is working now. I changed the conditionals in the if statements on line 39 to “if (spawnedObjects[i].removeSelf ~= nil) then”. However, I do not quite understand why this works. Is removeSelf an attribute? I thought that it was simply a function. Once again, any help is appreciated.

:removeSelf() is a function that’s part of a display object.  It will only be on things created by display.newImage(), display.newImageRect(),  display.newCircle() etc. 

If this line of code:

if (spawnedObjects[i].removeSelf ~= nil)

is in your myTouchListener, there is no guarantee that “i” will be the value you expect it to be when the touch handler fires.   This is why you should event.target since it’s the object that was touched.

Rob

I appreciate your reply, and I do not mean to be offensive in any way, but the line of code which I previously mentioned is not in myTouchListener. As I mentioned, it is on line 39, and you can scroll up to see my code. It is in the function circleGrow, which makes each circle increase their radius by 1 pixel every 10 milliseconds. I understand how the function “object:removeSelf()” works, but why it is treated as an attribute instead of a function?