Error when printing with crate IDs

Right now, I am trying to make this function work: 

function crateLost() if (crate.x \< 0 or crate.x \> display.actualContentWidth + 75) then --line 137 crate.label = label crate.finalize = finalize crate:addEventListener( "finalize" ) print("Crate number "..crate.id.. "was lost") crate = nil end end

But the printing does not work, it just gives me an error the says:  Attempt to index upvalue ‘crate’ (a nil value), and it points to line 137, which is labeled in the code.

I don’t know why this is happening. this is the code that creates my crates:

for i = 1, 5 do &nbsp;&nbsp;&nbsp;&nbsp;for j = 1, 5 do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;crates[count] = display.newImage( "crate.png", 300 + (i\*90), -5000 - (j\*120) ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;physics.addBody(crates[count], {density = 0.1, friction = 1, bounce = 0}) &nbsp;&nbsp;&nbsp;&nbsp; count = count+1 &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end

And this is the code that creates labels for those crates:

function createLabels() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for a = 1, #crates do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crate = crates[a] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crate.id = a &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --print(crate.id) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- https://docs.coronalabs.com/api/library/display/newText.html#syntax-legacy &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label = display.newText( crate.parent, a, 0, 0 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label.crate = crate &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label.enterFrame = enterFrame &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Runtime:addEventListener( "enterFrame", label ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- to help you remove the label later when removing the crate &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crate.label = label &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crate.finalize = finalize &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crate:addEventListener( "finalize" ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end end

This is happening because I niled out the crate, but it only prints that one crate was lost and does this forever. It repeats it forever because it is on an enterFrame event listener. ( Runtime:addEventListener(“enterFrame”) )  I understand why this happens, but I don’t know how to fix it.

As you say, you are making the ‘crate’ variable nil, so when you try to use it next time (30 or 60 times a second) it will be nil and can’t be used.

A piece of advice: You don’t appear to be setting the ‘crate’ variable as local anywhere and that makes me think you are defining it in one of your functions and expecting it to just be there whenever you want it. That is not going to be reliable…

You have a ‘crates’ table, so anything you do with a crate should reference that table.

Question: In your code, are the 3 sections of code you’ve posted in the same order as the post above? If so, you have some thinking to do about how the code is ordered.

To get you started, I think modifying this line:

if (crate.x \< 0 or crate.x \> display.actualContentWidth + 75) then

To this will help:

if (crate and (crate.x \< 0 or crate.x \> display.actualContentWidth + 75)) then

But it appears that while you are trying to remove a label when a crate is removed, you are not removing the enterFrame listener for it, which means it will continue to be called even though the crate is not there any more.

Thank you for the advice, I do have crate defined as a local at the top of my file. I will give this a try.

Also, adding the finalize eventListener just removes the label eventListener.

I tried this but it still only prints the name of one crate and repeats that forever. Also, I noticed something, the crate that repeats forever is the last crate I placed in the game with the two arrays:

 for i = 1, 6 do for j = 1, 6 do crates[count] = display.newImage( "crate.png", 300 + (i\*90), -5000 - (j\*120) ) physics.addBody(crates[count], {density = 0.1, friction = 1, bounce = 0}) count = count+1 end end

For this one: the 36th crate is the one that prints out forever. If it were i = 1, 3 do and j = 1, 4 do, the 12th crate would be printed forever, so how can I fix this?

I’m sure there are many ways to spawn objects into a table, but this is the scheme I use and it’s fairly easy to follow.

I spawn all similar objects into the same table so when I want to reload or respawn the screen I can clear the display objects from memory with display.remove and nil the table holding the objects easily.

The label is added to the indexed crates table and I only use 1 Runtime listener and iterate through the crates table in it to keep the labels on their parent objects as they bounce around, it also removes any crates that go off the screen

I always spawn objects with an ID of some sort so I can reference them later or remove them, whatever, it comes in handy especially if a touch listener is added. I stop the last crate on the floor and print out its ID.

I don’t mean to confuse you, but here is my version of what I think you are trying to accomplish.

This code can be run, but I use graphics 1.0 so you may have to change the colors.  It’s setup for 320x480 portrait view also, but you can change the x,y values to work in landscape.

[lua]

local physics = require(“physics”)
local CratesGroup = display.newGroup()
local crates = {}
local count = 0

local Base

local j
local i

physics.start()

local function removeCrate(event)
    local k
    for k = #crates, 1, -1 do
        
        crates[k].label.x = crates[k].x
        crates[k].label.y = crates[k].y
        
        if #crates == 1 then
            print(“Only 1 crate left!!!”)
            print(“crates[k].ID == “…crates[k].ID…””)
            crates[k]:setLinearVelocity (0, 0)

           physics.removeBody( crates[k] )

           Runtime:removeEventListener( “enterFrame”, removeCrate )

           return
        end
        
        if (crates[k].x < -40 or crates[k].x > display.actualContentWidth + 75) then
            print(“crates[”…k…"].ID is OFF Screen!")
            
            display.remove(crates[k])
             display.remove(crates[k].label)
             table.remove(crates, k)
             --table.remove(crates, k)
            --remove the crate here I guess or do what you want
            
        end
    end
    
end

local function createCrate(i,j)
    print(“count == “…count…””)
    print(“createCrate/ i == “…i…” j == “…j…””)
    
   – crates[count] = display.newImage( “crate.png”, 300 + (i*90), -5000 - (j*120) )
    crates[count] = display.newCircle((i*60) - 30, (j*45), 20 )
    physics.addBody(crates[count], {density = 0.01, friction = .1, bounce = 1})
    
    crates[count].ID = count --give it an ID so you can reference it later so you can identify it if needed
    CratesGroup:insert(crates[count])
    --crates[count]:setStrokeColor(255, 127, 36 )
    crates[count]:setFillColor(255, 255,255)
    
    --add label
    local _label = “”…count…""
    crates[count].label = display.newText( _label, crates[count].x, crates[count].y, native.systemFont, 12 )
    CratesGroup:insert(crates[count].label)
    crates[count].label:setFillColor(0, 0,0)
end

local function spawnCrates()
    
    for i = 1, 5 do
    for j = 1, 5 do
        count = count + 1
        createCrate(i,j)
    end
    end
    
    --add the Runtime listener once as it iterates over all the crates
    Runtime:addEventListener( “enterFrame”, removeCrate )
    
    Base = display.newRect(0, 460, 320, 15 )
   – physics.addBody(Base, {density = 0.01, friction = 1, bounce = 0})
    physics.addBody(Base, “static”)
end

spawnCrates()
 

[/lua]

hope this helps,

Nail

This code is almost perfect, there is just one problem, sometimes the crate it says was removed is not correct, take a look at this screen shot.

When you look, it says crates number 14 and 19 are off the screen, but they are still there.

In the second image, crate number 9 is printed three times in the console.

I think it may actually be working.

the line:  

[lua]

print(“crates[”…k…"].ID is OFF Screen!")

[/lua]

prints the index value [k] not the ID

since the the crates are removed from the crates table when off screen, the index values collapse like this I believe.

when crates[2] is removed, crates[3] now takes the crates[2] place in the table, all the indexes collapse to fill the hole when we removed crates[2].

side note:

This is why I attached the ID to each indexed crate when spawned so the ID or original index value remains the same while the  crates index value itself will change.  This allows me to reference the crate from a touch listener or a some other function later if I need to access/locate it with with a loop like this.  Btw, there are many ways to utilize the an objects ID, it’s a handy value of any table spawned object IMO.

let’s add up the value of all the crates left on the screen and call it a score, let’s say the ID is the crates “value” since it’s an Int and we can do math on it easily.

[lua]

local score = 0

for i = 1, #crates do

    score = score + crates[i].ID

end

print(“score == “…score…””)

[/lua]

-------------------------- end side note

Anyways, add this print statement  and watch the crates ID print when it is removed, which is it’s visible label .

[lua]

  1.             print(“crates[”…k…"].ID is OFF Screen!")
  2.             print(“Removed / crates[”…k…"].ID == “…crates[k].ID…”")
  3. [/lua]

the bigger lesson here is the scheme to spawn similar objects into a table and include everything associated with the object, labels, titles, values ,whatever when you spawn the parent item itself.

Now this object spawning can be done in a separate module or in the lua file you are working with, I  prefer to keep the spawn code in the file or screen I’m working on since I often have a complex touch listener attached to the objects.  It may add some memory usage to my app, but I think it’s probably minimal.  I am constantly changing / editing between modules as it is and I find it quicker to keep the object spawning in the same lua file.

Hope this helps,

Nail

Thanks, but now I am working with spawning the crates and when I run my code and spawn a crate, the crate is separated from its label, as in the label is no longer attached. I know why this is happening and it is because of the removeCrate function, but how can I get around this without losing any functionality?

local function removeCrate(event) local k for k = #crates, 1, -1 do crates[k].label.x = crates[k].x crates[k].label.y = crates[k].y crates[k].label.rotation = crates[k].rotation if #crates == 1 then print("Only 1 crate left!!!") print("crates[k].ID == "..crates[k].ID.."") crates[k]:setLinearVelocity (0, 0) physics.removeBody( crates[k] ) Runtime:removeEventListener( "enterFrame", removeCrate ) return end if (crates[k].x \< -40 or crates[k].x \> display.actualContentWidth + 75) then print("crate "..crates[k].ID.." is OFF Screen!") display.remove(crates[k]) display.remove(crates[k].label) table.remove(crates, k) --table.remove(crates, k) --remove the crate here I guess or do what you want end end end local function createCrate(i,j) --print("count == "..count.."") --print("createCrate/ i == "..i.." j == "..j.."") crates[count] = display.newImage( "crate.png", 100 + (i\*90), -1000 - (j\*120) ) physics.addBody(crates[count], {density = 0.5, friction = .1}) crates[count].ID = count --give it an ID so you can reference it later so you can identify it if needed CratesGroup:insert(crates[count]) --crates[count]:setStrokeColor(255, 127, 36 ) crates[count]:setFillColor(255, 255,255) --add label local \_label = ""..count.."" crates[count].label = display.newText( \_label, crates[count].x, crates[count].y, native.systemFont, 30 ) CratesGroup:insert(crates[count].label) crates[count].label:setFillColor(255,255,255) end local function spawnUserCrates(x, y) spawnCount = spawnCount + 1 crates[spawnCount] = display.newImage( "crate.png", x, y ) physics.addBody(crates[spawnCount], {density = 0.5, friction = .1}) crates[spawnCount].ID = spawnCount + count --give it an ID so you can reference it later so you can identify it if needed CratesGroup:insert(crates[spawnCount]) --crates[count]:setStrokeColor(255, 127, 36 ) crates[spawnCount]:setFillColor(255, 255,255) --add label local \_label = ""..spawnCount + count.."" crates[spawnCount].label = display.newText( \_label, crates[spawnCount].x, crates[spawnCount].y, native.systemFont, 30 ) CratesGroup:insert(crates[spawnCount].label) crates[spawnCount].label:setFillColor(255,255,255) end local function spawnCrates() for i = 1, 5 do for j = 1, 5 do count = count + 1 createCrate(i,j) end end --add the Runtime listener once as it iterates over all the crates Runtime:addEventListener( "enterFrame", removeCrate ) end spawnCrates() function textListener( event ) if ( event.phase == "began" ) then -- User begins editing "defaultField" elseif ( event.phase == "editing" ) then txt = event.text if(string.len(txt)\>3)then txt=string.sub(txt, 1, 3) event.text=txt end elseif ( event.phase == "ended" or event.phase == "submitted" ) then local paramsX = tonumber(txt) spawnUserCrates(paramsX, -200) end end

hmmm…

where did the variable spawnCount come from?  What determines the spawnCount?

You can’t just start adding indexed crates to the crates table if the index already exits.

spawnCount must add the next indexed crate to the crates table.

spawnCount = #crates + 1

use the existing count variable to add the proper label.

count = count + 1

Nail

Ok, but when I place # crates + 1 it says 51, instead of 26. I know it is an easy fix, but I want to know why. I would also like to fix this the other way instead of simply subtracting 25 and “sweeping the problem under the carpet”. Would you happen to know why this is happening?

It’s no problem, I was able to figure out everything. As for the label issue, I had realized the label was set to #crates + 1 + count, making it 51.

EDIT: New problem, I changed my code and now if one crate is already gone and the [layer spawns a new one, the crate falls down blank, and then gives this error message:

ERROR: Runtime error level1.lua:73: attempt to index field '?' (a nil value) stack traceback: level1.lua:73: in function '?' ?: in function \<?:172\> local function removeCrate(event) local k for k = #crates, 1, -1 do crates[k].label.x = crates[k].x --Line 73 (ERROR LINE) crates[k].label.y = crates[k].y crates[k].label.rotation = crates[k].rotation if #crates == 1 then print("Only 1 crate left!!!") print("crates[k].ID == "..crates[k].ID.."") crates[k]:setLinearVelocity (0, 0) physics.removeBody( crates[k] ) Runtime:removeEventListener( "enterFrame", removeCrate ) return end if (crates[k].x \< -40 or crates[k].x \> display.actualContentWidth + 75) then print("crate "..crates[k].ID.." is OFF Screen!") display.remove(crates[k]) display.remove(crates[k].label) table.remove(crates, k) --remove the crate here I guess or do what you want end end end local function createCrate(i,j) --print("count == "..count.."") --print("createCrate/ i == "..i.." j == "..j.."") crates[count] = display.newImage( "crate.png", 100 + (i\*90), -1000 - (j\*120) ) physics.addBody(crates[count], {density = 0.5, friction = .1}) crates[count].ID = count --give it an ID so you can reference it later so you can identify it if needed CratesGroup:insert(crates[count]) --crates[count]:setStrokeColor(255, 127, 36 ) crates[count]:setFillColor(255, 255,255) --add label local \_label = ""..count.."" crates[count].label = display.newText( \_label, crates[count].x, crates[count].y, native.systemFont, 30 ) CratesGroup:insert(crates[count].label) crates[count].label:setFillColor(255,255,255) end local function spawnUserCrates(x, y) count = count + 1 crates[count] = display.newImage( "crate.png", x, y ) physics.addBody(crates[count], {density = 0.5, friction = .1}) crates[count].ID = count --give it an ID so you can reference it later so you can identify it if needed CratesGroup:insert(crates[count]) --crates[count]:setStrokeColor(255, 127, 36 ) crates[count]:setFillColor(255, 255,255) --add label local \_label = ""..count.."" crates[count].label = display.newText( \_label, crates[count].x, crates[count].y, native.systemFont, 30 ) CratesGroup:insert(crates[count].label) crates[count].label:setFillColor(255,255,255) end

Nope, you didn’t follow my previous post.

Nail wrote:

spawnCount is the next indexed crate in the crates table.

spawnCount = #crates + 1

use the existing count variable to add the proper label  / added here: and ID to the crate[spawnCount]

count = count + 1


This is a good project, you should learn a lot about tables and indexing, removing table elements and referencing table elements.

I think you should keep the spawnCount variable in your function.

spawnCount = #crates + 1

The spawnCount is the NEXT index in the crates table

The count variable represents the number of crates you’ve created so far in the current game, which is also the label of the crate and the crates unique ID.

I think this is what needs to happen, didn’t test it.

[lua]

local function spawnUserCrates(x, y)
local spawnCount = #crates + 1  – this is the  next table index for the crate you are spawning

count = count + 1  – this is the total number of crates you’ve spawned + the 1 crate you are spawning, it is also the ID

        crates[spawnCount] = display.newImage( “crate.png”, x, y )
        physics.addBody(crates[spawnCount], {density = 0.5, friction = .1})

        crates[spawnCount].ID = count --give it an ID so you can reference it later so you can identify it if needed
        CratesGroup:insert(crates[spawnCount])
        --crates[spawnCount]:setStrokeColor(255, 127, 36 )
        crates[spawnCount]:setFillColor(255, 255,255)

        --add label
        local _label = “”…count…""  – turn the integer into a string
        crates[spawnCount].label = display.newText( _label, crates[count].x, crates[count].y, native.systemFont, 30 )
        CratesGroup:insert(crates[spawnCount].label)
        crates[spawnCount].label:setFillColor(255,255,255)
    end

[/lua]

hmmm…weird formatting in my browser, but I think you can see what needs to happen

Nail

Thanks there seems to be one last problem, after one crate is lost and I spawn a new one this error message pops up:

ERROR: Runtime error level1.lua:129: attempt to index field '?' (a nil value) stack traceback: level1.lua:129: in function 'spawnUserCrates' level1.lua:164: in function '?' ?: in function \<?:172\> local function spawnUserCrates(x, y) spawnCount = #crates + 1 count = count + 1 crates[spawnCount] = display.newImage( "crate.png", x, y ) physics.addBody(crates[spawnCount], {density = 0.5, friction = .1}) crates[spawnCount].ID = count --give it an ID so you can reference it later so you can identify it if needed CratesGroup:insert(crates[spawnCount]) crates[spawnCount]:setFillColor(255,255,255) --add label local \_label = ""..count.."" crates[spawnCount].label = display.newText( \_label, crates[count].x, crates[count].y, native.systemFont, 30 )--Line 129 CratesGroup:insert(crates[spawnCount].label) crates[spawnCount].label:setFillColor(255,255,255) end

This would definitely kick an error.

crates[spawnCount].label = display.newText( _label, crates[count].x, crates[count].y, native.systemFont, 30 )–Line 129

hmmmm…let’s debug this

crates[spawnCount].label  … looks good, we know crates[spawnCount] was spawned as it’s above the error line and there are no typos

the API call looks good, so the problem must be one of the parameters

let’s add some print statements and find the bad apple.

add these prints above line 129 to try to find the problem

print("_label == “…_label…”")

print(“crates[count].x == “…crates[count].x…””)

print(“crates[count].y == “…crates[count].y…””)

Where is the problem and why is it a nil value?

Nail

It prints the correct label number, but not the crates[count].x or crates[count].y, so I’m assuming crates[count] is the nil value it is talking about.

Yes, good job!

We are referencing crates[count].x and y for the label’s coordinates, and our debugging showed it to be nil or simply crates[count] doesn’t exist.

So what went wrong?

I didn’t change all your previous code in my untested code block I posted above. I left crates[count].x and y… MISTAKE or a trouble shooting challenge for you?

count is more than the current #crates table, it is the total number of crates spawned to this point.

The x, y reference to locate the label should be crates[spawnCount].x and y.

spawnCount is the index of the crates table we have just spawned and we need to have it’s label have the same coordinates.

I hope you are beginning to see the what the variables spawnCount and count represent.

You need to start developing your debugging skills because simple typos or variable references are going to happen very often as you work and modify your code.

Hope this helps,

Nail

Thank you so much xnailbender, I was able to figure this out thanks to you, the label was creating the error, but I also had to debug the print statements. 

As you say, you are making the ‘crate’ variable nil, so when you try to use it next time (30 or 60 times a second) it will be nil and can’t be used.

A piece of advice: You don’t appear to be setting the ‘crate’ variable as local anywhere and that makes me think you are defining it in one of your functions and expecting it to just be there whenever you want it. That is not going to be reliable…

You have a ‘crates’ table, so anything you do with a crate should reference that table.

Question: In your code, are the 3 sections of code you’ve posted in the same order as the post above? If so, you have some thinking to do about how the code is ordered.

To get you started, I think modifying this line:

if (crate.x \< 0 or crate.x \> display.actualContentWidth + 75) then

To this will help:

if (crate and (crate.x \< 0 or crate.x \> display.actualContentWidth + 75)) then

But it appears that while you are trying to remove a label when a crate is removed, you are not removing the enterFrame listener for it, which means it will continue to be called even though the crate is not there any more.

Thank you for the advice, I do have crate defined as a local at the top of my file. I will give this a try.

Also, adding the finalize eventListener just removes the label eventListener.

I tried this but it still only prints the name of one crate and repeats that forever. Also, I noticed something, the crate that repeats forever is the last crate I placed in the game with the two arrays:

 for i = 1, 6 do for j = 1, 6 do crates[count] = display.newImage( "crate.png", 300 + (i\*90), -5000 - (j\*120) ) physics.addBody(crates[count], {density = 0.1, friction = 1, bounce = 0}) count = count+1 end end

For this one: the 36th crate is the one that prints out forever. If it were i = 1, 3 do and j = 1, 4 do, the 12th crate would be printed forever, so how can I fix this?