Help me stab a tank

I have some code that spawns knife bullets that stick to the enemy until their health runs out, then they vanish. Since they behave differently than normal bullets (i.e. they don’t disappear on impact) I had to write some logic that, upon an enemy’s death, polls the last 500 bullets fired to see if they’re attached to the enemy who just died.

Problem: sometimes the knife removal code, for whatever reason, grabs an already removed knife and tries to remove it again, causing an error and making the world nice and weird.

Here’s the code:

[blockcode]if self ~= nil and self.spec == “knife” and self.stuckIn == event.other then

if #bullets > 500 then
endNum = #bullets - 500
else
endNum = 1
end

for i = endNum, #bullets do

if bullets[i] ~= nil then
if bullets[i].stuckIn == event.other then
–bullet remove self
end
end

end[/blockcode]

When the remove code is called, whether it’s a child.parent removal or a removeself() call, an error is generated the says parent is a nil value or removeself is a nil value. What’s the problem? [import]uid: 89724 topic_id: 17039 reply_id: 317039[/import]

Aaaha! You are facing a classic example of the pitfalls of a table in lua.

when you use the code

for i=1,#bullets do
end

where bullets is an array that has maybe a nil value somewhere, you will get an issue. Here is what happens

let’s say we have the elements 1 to 20 having a value. Then the element 12 is set to nil, the next time we run the loop

for i=1,#bullets do
end

you would expect the value of #bullets to be 20, right? But it will return only 11 as the 12th element is NIL

hope you get this and it can help you cater that into your logi for searching the bullets.

cheers,

?:slight_smile: [import]uid: 3826 topic_id: 17039 reply_id: 63966[/import]

Wow. So can I get around that by making the loop dependent on a definitive number instead of the length of the list? [import]uid: 89724 topic_id: 17039 reply_id: 64012[/import]

Hey, Jayant, how about doing something like this?

[lua]totalCount = 50;
for i=1,totalCount do
if (bullets[i] ~= nil) then
–bullet remove self
end
end[/lua]

In other words, if we keep track of how many bullets are being spawned during the course of the game, and use that total bullet counts for the loop, will it still potentially cause an error like the one x2495iiii described above?

Naomi [import]uid: 67217 topic_id: 17039 reply_id: 64038[/import]

@Naomi,
using a variable is better than trying to get the length of the array. HOWEVER… you have stepped into another trap!!

when you try to remove items, you always start from the last item up to the first item.

so the *best* way to do that would be

for i=totalCount,1,-1 do

end

cheers,

?:slight_smile: [import]uid: 3826 topic_id: 17039 reply_id: 64128[/import]

Ah, of course, Jayant. Thank you for reminding me of the backward loop!

Naomi [import]uid: 67217 topic_id: 17039 reply_id: 64136[/import]

Glad Naomi got some help, but I’m afraid I’m still stuck.

Both replacing the length with a variable and going backwards led to the same nil error. [import]uid: 89724 topic_id: 17039 reply_id: 64145[/import]

You tank must have been stabbed to death therefore you got the errors :wink: Hahahaha…

ok, seriously,
Is the code you are using the same as the one you posted on the top or is it any different? Could you repost what you have and please include the function, not the snippet.

cheers,

?:slight_smile: [import]uid: 3826 topic_id: 17039 reply_id: 64153[/import]

You know you want to stab some tanks.

Here’s the relevant code. The if/else statement is called when the bullet hits something. The bulletShow method is called every frame to make the bullets visible shortly after they leave the barrel of the gun and rotate them properly (I didn’t like the way they looked coming immediately out of the barrel). The error says that the x field in line 27 is nil.

[blockcode]

if self ~= nil and self.spec == “knife” and self.stuckIn == event.other then

if #bullets > 2000 then
endNum = #bullets - 2000
else
endNum = 1
end

numBlt = #bullets

for i = numBlt, endNum, -1 do
if bullets[i] ~= nil then
if bullets[i].stuckIn == event.other then
bullets[i]:removeSelf()
bullets[i] = nil
end
end
end
end

local bulletShow = function()
local bltShowNum = #bullets
if bltShowNum > 2 then
bltShowNum = bltShowNum - 2
if (bullets[bltShowNum] ~= nil) and (bullets[bltShowNum].myLabel ~= “bigbullet” and bullets[bltShowNum].myLabel ~= “blastbullet”)
and bullets[#bullets].stuckIn == turret then
local bulletToA = bullets[bltShowNum].x - halfW
local bulletToO = bullets[bltShowNum].y - halfH
bullets[bltShowNum].isVisible = true
if bullets[bltShowNum].x < halfW then
bullets[bltShowNum].xScale = -1
end
bullets[bltShowNum].rotation = (math.deg(math.atan2 (bulletToO, bulletToA))) + 270
end
end
end

[/blockcode] [import]uid: 89724 topic_id: 17039 reply_id: 64156[/import]

@x2495iiii,
interesting nickname, wanna share how that came into being? Do I read in between as dates? 24/95/4 as a birthdate or something?

Right, about the issue on hand

The error might still persist due to the fact that you are using the #bullets.

A suggestion to avoid that, have a variable at the top of your code

local bulletsFired=0

then everytime you fire a bullet, increment this value by 1

bulletsFired = bulletsFired + 1
and then add the item into your bullets array. That way you do not have to use #bullets, bulletsFired *should* be that number.

another thing, since the arrays get re-ordered, use them as dictionary objects, so where ever you have

bullets[#bullets+1]=newBulletObject

replace that with

bullets[“bullet_” … bulletsFired+1] = newBulletObject

then when you access the same, you can access it using

local temp = bullets[“bullet_”…i]
if temp ~= nil then
– do whatever you want to with this
end

cheers,

?:slight_smile: [import]uid: 3826 topic_id: 17039 reply_id: 64166[/import]

Some very good ideas, thanks.

I was able to easily integrate the bulletsFired variable into the program, but I’m not sure how the bullets[“bullet_” … bulletsFired+1] thing works. I tried putting it in there and the bulletshow method is now fine, but the removeself method in the if/else statement is not.

As for my name, it was inspired by the name of a robot I heard in a movie that was playing in the background when I was creating my first ever online account. The robot’s name was x52495II. I misheard it as x2495II. Then I forgot my password. Twice. i created a new account each time, and instead of following roman numerals, I went with IIII at the end. I don’t remember why I stopped capitalizing the end letters, but that happened at some point. [import]uid: 89724 topic_id: 17039 reply_id: 64182[/import]