Spawn objects in loop with tap-listeners

Please forgive the total n00b question. I’m new to the Corona SDK (and programming in general, save for some VB and reading Frank Zammetti’s excellent book) and I’ve run into a problem. Having tried several things and searched extensively, I just can’t get my head around this…

Background: As a learning exercise I’m trying to write a game where there are six ‘thingies’. Each thingy will be given a ‘score’ based on random properties and the thingy with the highest score will be the “right” choice. The user will tap their choice and then they will be told if they have selected correctly or not.

I’m work on my ‘draw level’ function which will spawn the thingies. This function should produce 6 images on the screen and then make each of those six images identifiable by tap.

This is the code I’ve written:

 

for i=1,6,1 do

  thingy[i] = display.newImageRect(“graphics/thingy.png”, 67, 122, true);

  thingy[i].name = (“thingy”…i);

  thingy[i].id = i;

  thingy[i].x = (positionSpacing * i) - (positionSpacing / 2);

  thingy[i].y = display.contentCenterY;

  table.insert(thingy[i], gc.gameDG);

  print(thingy[i].name…" “…thingy[i].x…” index "…thingy[i].id); --for debug

  thingy[i]:addEventListener(“tap”, gc.positionTapped);

 

end

This creates the things on the screen happily. So then I define a function to react to the tapping of the thing:

function gc:positionTapped(event)

  utils:log(sceneName, “positionSelected()”);

  print(self.id);

 

end

The utils:log function is there for debug, and works correctly. But the print self.id doesn’t work. I’m expecting it to give me thingy id (which should be i as defined in the loop). It returns ‘nil’.

I tried changing the spawn loop to be:

for i=1,6,1 do

  thingy[i] = display.newImageRect(“graphics/thingy.png”, 67, 122, true);

  thingy[i].name = (“thingy”…i);

  thingy[i].id = i;

  thingy[i].x = (positionSpacing * i) - (positionSpacing / 2);

  thingy[i].y = display.contentCenterY;

  table.insert(thingy[i], gc.gameDG);

  print(thingy[i].name…" “…thingy[i].x…” index "…thingy[i].id); --for debug

  thingy[i]:addEventListener(“tap”, gc:positionTapped);

 

 end

And the loop crashes out with “function arguments expected near )”

So I changed it again to be:

for i=1,6,1 do

  thingy[i] = display.newImageRect(“graphics/thingy.png”, 67, 122, true);

  thingy[i].name = (“thingy”…i);

  thingy[i].id = i;

  thingy[i].x = (positionSpacing * i) - (positionSpacing / 2);

  thingy[i].y = display.contentCenterY;

  table.insert(thingy[i], gc.gameDG);

  print(thingy[i].name…" “…thingy[i].x…” index "…thingy[i].id); --for debug

  thingy[i]:addEventListener(“tap”, gc:positionTapped());

 

end

and it crashes out with “Runtime error assertion failed!” during the loop, as does:

 thingy[i]:addEventListener(“tap”, gc.positionTapped(thingy[i].id));

and so does:

 thingy[i]:addEventListener(“tap”, gc.positionTapped(i));

I’ve been reading and googling for three days and still can’t find the answer. I’d be really thankful if you’d please take pity on a n00b and help me out. :slight_smile:

I’m assuming you are creating the “thingy” table above the code you posted like this.

thingy = {}

Your first spawning loop looks like it should work from first glance.  I always assign an object.id = i as you do to track each specific object.

I don’t use “self”, I use event.target when I get variable attributes from a touch event, not really sure why, but it works.

Try

print("event.target.id == ", event.target.id)

and see if you print your expected id.

Hope this helps,

Nail

Hi Nail,

I gave that a go, when one of the ‘thingies’ is clicked in the simulator I get a runtime error: attempt to index local ‘event’ (a nil value).  Could it be that the listener isn’t passing the ‘event’ completely?

James.

not sure why, but I never use “tap”, I use “touch” as the event listener. Then in the listener function do like this…

if event.phase == "began then

elseif event.phase == “moved” then

elseif event.phase == “ended” then

end

This allows for different things to happen during different phases of the event.

Sorry, I’m just not that familiar with “tap”

Nail

You want to “return true” at the end of your event listener also.

function gc:positionTapped(event)

if event.phase == “began” then

 

elseif event.phase == “ended” then

  utils:log(sceneName, “positionSelected()”);

 

print("event.target.id == ", event.target.id);

end

return true

end

Hi Again,

Still no joy.  The posiitonTapped function now looks like this:

[lua]

function gc:positionTapped(event)

   utils:log(sceneName, “positionSelected()”);

   if event.phase == “began” then

   elseif event.phase ==“moved” then

   elseif event.phase == “ended” then

      print(self.id);

   end 

   

   return true;

   

end

[/lua]

When I click a thingy, the error is: Runtime error /Users/jnewburrie/code/gameCore.lua:90: attempt to index local ‘event’ (a nil value)

line 90 is:  “if event.phase == “began” then”

I don’t use the 3rd step variable in my  “for” iterations either, but by using “1” as you do, I don’t see why it won’t work correctly.

for i = 1, 6, 1

I just use:

for i = 1, 6 and skip the 3rd step variable

Nail

I just tried removing the ‘step’ variable. The ‘draw’ loop still works correctly, but the event still isn’t passing…

try adding local to thingy table

local thingy = {}

tried that, no joy. :frowning:

you are inserting gc.gameDG into the thingy[i] table.

comment out the line and see what happens.

–table.insert(thingy[i], gc.gameDG

still no joy :frowning:

arrrgh!

have you replaced “tap” with “touch” when adding the event listener?

it could be a scope issue.

try adding a function in the gc module with the spawn loop and call it from the module you are currently spawing the thingy’s from

you’ve got to replace the “:” with a “.” in the listener function

change:  function gc:positionTapped(event)

to:  function gc.positionTapped(event)

change it when you add the event listener also.

and give it a try

this works, your code is close.

I don’t know why the lua tags create 1 long line of code so I just posted it raw.

main.lua-----

local gc = require(“gc”)

display.setStatusBar( display.HiddenStatusBar )

local positionSpacing = 30

local thingy = {}

local gcGroup = display.newGroup()  --add a display group so you can remove the objects later

local function spawnThingys()
    for i=1,6 do
        
        thingy[i] = display.newCircle(0, 0, 10)
        
        thingy[i].x = (positionSpacing * i);
        
        thingy[i].y = 100;
        
        thingy[i]:setFillColor(0, 0, 255)
        
        thingy[i].name = (“thingy”…i);
        
        thingy[i].id = i;
        
        gcGroup:insert(thingy[i])
        
        print(thingy[i].name…" “…thingy[i].x…” index “…thingy[i].id); --for debug
        
        – insert thingy[i] into gc.gameDG so you can reference it I guess, you had it backwards
        
        table.insert(gc.gameDG, thingy[i])
        
        --here’s how you call the variable from the gc.gameDG table if you want to from that module
        
        print(“gc.gameDG.thingy[”…i…”].id == ", gc.gameDG[i].id)
        
        thingy[i]:addEventListener(“touch”, gc.positionTapped);
    end     
    return gc.gameDG
end

spawnThingys()

gc.lua----

local gc = {}
gc.gameDG = {}

–function gc:positionTapped(event)
    
 function gc.positionTapped(event)   
    
    if event.phase == “began” then
    elseif event.phase == “ended” then
        
        --utils:log(sceneName, “positionSelected()”);
        --print(self.id);
        print("event.target.id == ", event.target.id)

    end
    return true
    
end

Hope this helps

Nail

Hey Nail,

You found the answer a post-ago!

I changed the “:” with a “.” in the listener function:

function gc:positionTapped(event)

 

to:  

 

function gc.positionTapped(event)

 

Thanks for your help :slight_smile:

ya, I know.  I didn’t see the trouble at first because I know you can access gc:createThingy from another module, still not sure why the event listener had to have a “.” though.   Just the way it is I guess.

I posted the code because I believe you were inserting your table backwards and then the code goes on to show how to call the new inserted table variable.

It was a fun debugging session, I learned a couple of things, glad I could help.

GL

Nail

I’m assuming you are creating the “thingy” table above the code you posted like this.

thingy = {}

Your first spawning loop looks like it should work from first glance.  I always assign an object.id = i as you do to track each specific object.

I don’t use “self”, I use event.target when I get variable attributes from a touch event, not really sure why, but it works.

Try

print("event.target.id == ", event.target.id)

and see if you print your expected id.

Hope this helps,

Nail