firing series of projectiles

I am currently trying to get a snippet of code working to have 10 projectiles fire 1 after another. For the life of me I can’t figure out how to get them to respond to the touch listener. The only projectile that fires is the last one generated. I know I"m getting the 10 projectiles generated offscreen from a higher function as they display in terminal. Below is my code, and I have spent a good 6 hours on it and would appreciate a second (or third) set of eyes. I know I’m missing something obvious but I am totally blind to it. Let me know if I need to post more code. Thanks!

[lua]local function fireRifle(event)
for a=1, 10, 1 do
if event.phase == “began” then
if event.time - timeLastBullet >= 650 then
bolt.x = player.x + 28
bolt.y = player.y - 20
transition.to(bolt, {time = 2000, bolt:setLinearVelocity(500, 0),
onComplete = function(bolt) bolts = nil; end
})
print(“FIRE!”)
timeLastBullet = event.time
end
end[/lua]

[import]uid: 135394 topic_id: 29183 reply_id: 329183[/import]

Hi ajaxzon,

You loop through the index [lua]a[/lua] 10 times, but within the loop, you never use that index, so the loop will not do anything differently each time it runs. Instead, the loop will just modify the position and velocity of whatever the variable [lua]bolt[/lua] refers to 10 times. Presumably that variable refers to the last bolt you created.

When you create the bolts, you could/should store them in a table called [lua]bolts[/lua]. Then, within your loop, you would modify their position and velocity using [lua]bolt[a][/lua].

Last, I see you’re using [lua]transition.to[/lua], but I think you may be better served by using [lua]timer.performWithDelay[/lua]. For example, you might write [lua]timer.performWithDelay(2000 + 300*a, function() bolts[a]:setLinearVelocity(500,0) end)[/lua], which would begin firing the bolts after 2 seconds and stagger them by 0.3 seconds between each fire.

  • Andrew [import]uid: 109711 topic_id: 29183 reply_id: 117375[/import]

Auk, Thanks for the suggestions! I did actually generate a table for the projectiles previously, but was running into a serious brick wall when trying to refer to them in my loop. Below is how I generated the table(caveat: I am using LIME, so I need to create the projectiles such that they are on the same layer as my player character, or the projectiles get out of sync, fire offscreen, and general pandemonium ensues :-))
[lua] local onShotSpawn = function(object)
for a = 1, 10 do
bolt = display.newRect(0, 0, 15, 5)
bolt.name = (“bolt”… a)
bolt.id = a
bolt.x = 800
bolt.y = 600
bolt:setFillColor(255, 0, 0)
physics.addBody(bolt, “kinematic”, {density = 10.0, friction = 0, bounce = 0})
bolt.myName = “bolt”
bolts:insert(bolt)
print(“bold.name=”…bolt.name)
end
end
onShotSpawn()[/lua]

This all works great, I see the bolts generated in terminal and everything is hunky dory.

Now, when it comes to actually firing the projectiles, I am running into a bear of an issue. Adding the table reference of [a] throws me an error of:

attempt to index field '?' (a nil value)  

Here is the code I have for iterating and firing the projectiles. Leaving off the reference to the bolt table just fires the last bolt, as you referenced above. What am I missing? I’ve been staring at this particular code a combined 22 hours and I can’t figure out what I’m doing wrong.
[lua]local function fireRifle(event)
for a=1, bolts.numChildren, 1 do
if event.phase == “began” then
if event.time - timeLastBullet >= 650 then
if player.direction == DIRECTION_RIGHT then
bolt.x = player.x + 28
bolt.y = player.y - 20
timer.performWithDelay(2000 + 300*a, bolt:setLinearVelocity(500,0))
print(“bolt.name=”…bolt.name)
timeLastBullet = event.time

end
end
end
end[/lua] [import]uid: 135394 topic_id: 29183 reply_id: 117394[/import]

Hi ajaxzon,

Try the following slightly modified version and let me know if it works. The two changes are (1) made bolt a local variable in your onShotSpawn function, and (2) changed all instances of bolt to bolts[a] in your fireRifle function.

[blockcode]
local onShotSpawn = function(object)
for a = 1, 10 do
local bolt = display.newRect(0, 0, 15, 5)
bolt.name = (“bolt”… a)
bolt.id = a
bolt.x = 800
bolt.y = 600
bolt:setFillColor(255, 0, 0)
physics.addBody(bolt, “kinematic”, {density = 10.0, friction = 0, bounce = 0})
bolt.myName = “bolt”
bolts:insert(bolt)
print(“bold.name=”…bolt.name)
end
end
[/blockcode]

[blockcode]
local function fireRifle(event)
for a=1, bolts.numChildren, 1 do
if event.phase == “began” then
if event.time - timeLastBullet >= 650 then
if player.direction == DIRECTION_RIGHT then
bolts[a].x = player.x + 28
bolts[a].y = player.y - 20
timer.performWithDelay(2000 + 300*a, bolts[a]:setLinearVelocity(500,0))

print(“bolts[a].name=”…bolts[a].name)

timeLastBullet = event.time
end
end
end
end
[/blockcode] [import]uid: 109711 topic_id: 29183 reply_id: 117397[/import]

I actually tried that route at about 1:30 AM last night to no avail. The projectiles are generated just fine, but this causes the bolts to get out of sync from the movement of the player. In addition, it only fires the first projectile. If I attempt to fire another projectile while the first is in flight, it removes the flying projectile and fires the current. I’m thinking that this is going to be super-manual and I’m going to have to generate the projectiles in code without concatenating/iterating through them. If you have any other suggestions let me know though. Thanks for your time! [import]uid: 135394 topic_id: 29183 reply_id: 117410[/import]

I would discourage you from doing a “super-manual” solution – there’s certainly a way to make this work in a more systematic fashion.

It’s good that you already tried the route I was suggesting. I’d be curious if you encounter the same issues you described if you paste in the code I suggested above (or rather, the slightly fixed version I suggest below).

I wouldn’t be surprised if the projectiles are “out of sync” with the player, because the x,y coordinates are set, and fixed, at the time the fireRifle function is called. Instead, you could/should move that part of the code to within the timer.performWithDelay – see below.

Also, I realize that I should have placed a closure around the timer.performWithDelay in my sample, which I’ve fixed below.

[blockcode]
local function fireRifle(event)
for a=1, bolts.numChildren, 1 do
if event.phase == “began” then
if event.time - timeLastBullet >= 650 then
if player.direction == DIRECTION_RIGHT then
timer.performWithDelay(2000 + 300*a, function()
bolts[a].x = player.x + 28
bolts[a].y = player.y - 20
bolts[a]:setLinearVelocity(500,0))

print(“bolts[a].name=”…bolts[a].name)
end)

– Not sure what is your intention with this next line, but it may belong in the timer.performWithDelay as well
timeLastBullet = event.time
end
end
end
end
[/blockcode] [import]uid: 109711 topic_id: 29183 reply_id: 117458[/import]

I was able to develop a solution thanks for your input! Here is the massaged code:

[lua]local function fireRifle(event)
if(event.phase == “began”) then
for a=1, bolts.numChildren, 1 do
if(bolts[a].isAlive == false) then
bolts[a].isAlive = true
bolts[a].x = player.x + 30
bolts[a].y = player.y - 28
bolts[a]:setLinearVelocity(200,0)
print(“bolts.name =”…bolts[a].name)
break
–end
end
end
end
end[/lua]

But the actual function telling the bolts what to do wasn’t even the problem. I’m using LIME as my “de facto” level developer because dropping physics in is much more intuitive. Anyway, the missing piece was the below:

[lua]map:getTileLayer(“Playarea”):addObject(bolts)[/lua]

I had this portion set to (bolt) and not (bolts), which was allowing the last projectile generated to be fired, and didn’t allow the entire bolt table to be iterated through. So it works like a dream. Now I need to develop the collisions handler, and figure out why I need that BREAK notation, and I’m off and running!

Thanks so much for your help. There are tons of mobile development platforms but Corona is great, exactly because of the user base. Having a separate set of eyes is always a benefit. Thanks again! [import]uid: 135394 topic_id: 29183 reply_id: 117602[/import]