Corona not recognizing obj ~= nil

I am trying to create a space shooter game but I am having trouble with obj ~= nill. Can anyone please help this newbie?

here is my code:

local function wave1(  )

        local sceneGroup = scene.view

            local function e1(  )

                    --create enemy1

            local enemy = display.newImageRect(“images/enemy.png”,50,25)

            enemy.x=-(screenW+enemy.contentWidth)

            enemy.y=0

            enemy.name=“enemy”

            physics.addBody(enemy)

            sceneGroup:insert(enemy)

            enemy:addEventListener(‘collision’, collisionHandler)

                    local function removeEnemy( self, event )

                        if (enemy ~=nil) then

                            if (enemy.x > screenW ) then

                                Runtime:removeEventListener( “enterFrame”, self )

                                enemy:removeSelf()

                                enemy=nil

                            end

                        end

                    end

                    if (enemy ~= nil) then

                    enemy.enterFrame = removeEnemy

                    Runtime:addEventListener( “enterFrame”, enemy )

                    end

            local function fire()

                local function shoot()

                    local blaster = display.newImageRect( “images/ammoE.png”, 20, 20 )

                        blaster.x = enemy.x

                        blaster.y = enemy.y+5

                        transition.to( blaster, { time=1000, y=(blaster.y+screenH),} )

                        sceneGroup:insert(blaster)

                        --remove fire start

                        local function removeBullet( self, event )

                            if (blaster.y > 200) or (isGameOver==true)then

                                Runtime:removeEventListener( “enterFrame”, self )

                                display.remove( self )

                            end

                        end

                        blaster.enterFrame = removeBullet

                        Runtime:addEventListener( “enterFrame”, blaster )–remove fire end

                end

                timer.performWithDelay(50,shoot,3)

            end

            if (enemy ~=nil)then

                timer.performWithDelay(3000,fire,1)

            end

            transition.to( enemy, { time=4500, x=display.contentWidth+enemy.contentWidth,y=100} )–control enemy speed

   

     

    end

    timer.performWithDelay(300,e1,6)

    end

    function collisionHandler(e)

        if(e.other.name == ‘bullet’ and e.target.name == ‘enemy’) then

            – audio.play(explo)

            display.remove(e.other)

            display.remove(e.target)

            e.target=nil

        end

    end

I’m sorry if its kinda messy…

function collisionHandler works but it gives function removeEnemy an error even though removeEnemy should only work if enemy is not nil.

I somehow found a solution to removeEnemy… I simply changed enemy:removeSelf() to display.remove(enemy) and it works fine now. The only problem now is this part of the code:

 if (enemy ~=nil)then timer.performWithDelay(3000,fire,1) end

timer.performWithDelay(3000,fire,1) still triggers even though enemy is removed from the screen. Is there something wrong with the way I removed the object?

@kurokawashinji47:

Welcome to the forums! I see that on your second post you figured out how to format code in your posts. That’s great - the more concise and well-formatted your questions, the better responses you’ll get. :slight_smile:

To reply your first post, and to confirm that you’re on the right track: display.remove(object) performs the same operation as object:removeSelf(), but it does the work of checking to make sure the object exists first. In my opinion it’s a much better way to go, as using removeSelf can lead to Runtime errors if you accidentally call it against an object that’s already been removed.

In response to your second post: removing display objects from the stage does not automatically convert that object’s variable to nil. All Corona display objects are stored in Lua tables, and while removing the display object will clear out the object’s table, it will not nil it. That’s up to you to handle, should you choose to do so. Opinions can vary on whether it’s necessary to do so - I personally find it’s something most developers can skip, unless you have a particular need to optimize your memory usage: even a thousand empty tables won’t slow down most Corona apps.

Now, since we know that removing an object will not explicitly nil out its associated table, how do we check to see if the display object still exists? One way that I’ve used in the past is to check to see if the object is nil, but also if its removeSelf property is nil. When you call display.remove on an object (or removeSelf, for that matter), the table is cleared out, so checking for any common display object property will clue you in as to whether the object still exists. You could even use x or y, but I like removeSelf, because it’s a fairly unique property that in most cases will only belong to Corona display objects.

Here’s how you could modify your current code to check if an object is nil as well as if it still has a removeSelf property:

if enemy and enemy.removeSelf then timer.performWithDelay(3000, fire, 1) end

Or, if you _really_ wanted to go the extra mile to ensure you won’t get a Runtime error if enemy is not nil, but is not a table:

if type(enemy) == 'table' and enemy.removeSelf then timer.performWithDelay(3000, fire, 1) end

Hope this helps, and again - welcome to the forums!

@schroederapps

First of all, thank you for your reply and thank you for the warm welcome.

I tried both of your codes but it does not seem to work. The enemy still fires even though it’s supposed to be dead.

The line

timer.performWithDelay(3000, fire, 1)

is the one that triggers the enemy fire. It should not trigger if enemy is dead (or in this case if enemy is nil). I have tried modifying it into

enemyFire=timer.performWithDelay(3000, fire, 1)

and changing my code for collisionHandler into

function collisionHandler(e) if(e.other.name == 'bullet' and e.target.name == 'enemy') then timer.cancel(enemyFire) display.remove(e.other) display.remove(e.target) e.target=nil print(e.target) end end

but it still won’t work. Is there any other way to disable it?

@kurokawashinji47

There are a number of ways you can go about accomplishing this, but here’s what I’d recommend. Add this line of code to the top of your fire function:

if enemy == nil or enemy.removeSelf == nil then return true end

This basically checks to see if the enemy display object still exists, and if it does not, it halts that fire function before it can begin. This means it is safe to call that fire function regardless of whether or not the enemy object still exists - the function checks and stops itself by returning true if the enemy has been destroyed.

Hope this helps!

@schroederapps

Thank you very for taking the time to answer my questions. You have been a great help. 

Here is my implementation.  Create a global function…

function isDisplayObject(obj) if obj ~= nil then if type( obj.removeSelf ) == "function" then return true else return false end else return false end end

then when you want to use it do something like this (it makes your code nice and readable)…

if isDisplayObject(myObject) then --do something with myObject end

I somehow found a solution to removeEnemy… I simply changed enemy:removeSelf() to display.remove(enemy) and it works fine now. The only problem now is this part of the code:

 if (enemy ~=nil)then timer.performWithDelay(3000,fire,1) end

timer.performWithDelay(3000,fire,1) still triggers even though enemy is removed from the screen. Is there something wrong with the way I removed the object?

@kurokawashinji47:

Welcome to the forums! I see that on your second post you figured out how to format code in your posts. That’s great - the more concise and well-formatted your questions, the better responses you’ll get. :slight_smile:

To reply your first post, and to confirm that you’re on the right track: display.remove(object) performs the same operation as object:removeSelf(), but it does the work of checking to make sure the object exists first. In my opinion it’s a much better way to go, as using removeSelf can lead to Runtime errors if you accidentally call it against an object that’s already been removed.

In response to your second post: removing display objects from the stage does not automatically convert that object’s variable to nil. All Corona display objects are stored in Lua tables, and while removing the display object will clear out the object’s table, it will not nil it. That’s up to you to handle, should you choose to do so. Opinions can vary on whether it’s necessary to do so - I personally find it’s something most developers can skip, unless you have a particular need to optimize your memory usage: even a thousand empty tables won’t slow down most Corona apps.

Now, since we know that removing an object will not explicitly nil out its associated table, how do we check to see if the display object still exists? One way that I’ve used in the past is to check to see if the object is nil, but also if its removeSelf property is nil. When you call display.remove on an object (or removeSelf, for that matter), the table is cleared out, so checking for any common display object property will clue you in as to whether the object still exists. You could even use x or y, but I like removeSelf, because it’s a fairly unique property that in most cases will only belong to Corona display objects.

Here’s how you could modify your current code to check if an object is nil as well as if it still has a removeSelf property:

if enemy and enemy.removeSelf then timer.performWithDelay(3000, fire, 1) end

Or, if you _really_ wanted to go the extra mile to ensure you won’t get a Runtime error if enemy is not nil, but is not a table:

if type(enemy) == 'table' and enemy.removeSelf then timer.performWithDelay(3000, fire, 1) end

Hope this helps, and again - welcome to the forums!

@schroederapps

First of all, thank you for your reply and thank you for the warm welcome.

I tried both of your codes but it does not seem to work. The enemy still fires even though it’s supposed to be dead.

The line

timer.performWithDelay(3000, fire, 1)

is the one that triggers the enemy fire. It should not trigger if enemy is dead (or in this case if enemy is nil). I have tried modifying it into

enemyFire=timer.performWithDelay(3000, fire, 1)

and changing my code for collisionHandler into

function collisionHandler(e) if(e.other.name == 'bullet' and e.target.name == 'enemy') then timer.cancel(enemyFire) display.remove(e.other) display.remove(e.target) e.target=nil print(e.target) end end

but it still won’t work. Is there any other way to disable it?

@kurokawashinji47

There are a number of ways you can go about accomplishing this, but here’s what I’d recommend. Add this line of code to the top of your fire function:

if enemy == nil or enemy.removeSelf == nil then return true end

This basically checks to see if the enemy display object still exists, and if it does not, it halts that fire function before it can begin. This means it is safe to call that fire function regardless of whether or not the enemy object still exists - the function checks and stops itself by returning true if the enemy has been destroyed.

Hope this helps!

@schroederapps

Thank you very for taking the time to answer my questions. You have been a great help. 

Here is my implementation.  Create a global function…

function isDisplayObject(obj) if obj ~= nil then if type( obj.removeSelf ) == "function" then return true else return false end else return false end end

then when you want to use it do something like this (it makes your code nice and readable)…

if isDisplayObject(myObject) then --do something with myObject end