Page 2 of 3

Re: Problem with drawing moving sprites.

Posted: Sat Feb 22, 2014 4:08 pm
by davisdude
Fruit[2] isn't touched here because when Fruit[1] is removed, Fruit[2] becomes Fruit[1], while the index is at 2. I hope that makes sense. It's a bit confusing. :P
As for your for-loop, I don't think it affects it, but I'm not sure. Since you're using pairs, I'm assuming you have a table that looks like this:

Code: Select all

Fruits = {
     Apple = { 'Whatever' }
}
?
In that case, I'm pretty sure it's not affected, since their index isn't based numerically. You may want to consult another, more experienced programmer for that, though.

Re: Problem with drawing moving sprites.

Posted: Sat Feb 22, 2014 4:34 pm
by Moonkis
davisdude wrote:Fruit[2] isn't touched here because when Fruit[1] is removed, Fruit[2] becomes Fruit[1], while the index is at 2. I hope that makes sense. It's a bit confusing. :P
As for your for-loop, I don't think it affects it, but I'm not sure. Since you're using pairs, I'm assuming you have a table that looks like this:

Code: Select all

Fruits = {
     Apple = { 'Whatever' }
}
?
In that case, I'm pretty sure it's not affected, since their index isn't based numerically. You may want to consult another, more experienced programmer for that, though.
Yeah, it resizes the table, right that makes sense! I tried iterating it backwards and it fixed the problem! I still have a few questions left.

My EntityManager.objects is indexed with an integer or "numerical" so I can use either pair or ipair, but they have exactly the same result. However if I have one generic "pairs"-loop that JUST updates and then add a new "pairs"-loop right after the update loop that checks if an Entity is alive and calls table.remove if it's dead dosen't cause this. But it should have the same impact? Should't it? I mean the table elements would be skipped this way as well, wouldn't it?

Like this:

Code: Select all

	for i, e in ipairs(EntityManager.objects) do
		if e.update then
			e:update(dt)
		end
	end

	for i, e in ipairs(EntityManager.objects) do
		if e:isAlive() == false then
			table.remove(EntityManager.objects, i)
		end
	end
This fixes the issue, by just moving the table.remove into it's own loop...
Note that this shouldn't be working, it still skips objects now and then, but it fixes the sprite movement...wat?

EDIT:

It might have to be with that other entities inside the array adds other entities (like Player adds Bullets) while doing the e:update(dt), however, removing from a table is not safe using pairs( or ipairs) whether I put it in a new loop or not, the correct way is to do a backwards iteration...

Combining wrongly deleting objects in tables whilst adding to it might be what causes this weird movement, seeing as not all objects gets updated correctly.

Re: Problem with drawing moving sprites.

Posted: Sat Feb 22, 2014 6:21 pm
by davisdude
One minor thing:
- Instead of if e:isAlive() == false then you can do if not e:isAlive() then. Not really important, but I think it looks better, and it takes less time to type. You can do whatever you want to do, though.

As for your solution, that's not the way I would do it, but I guess if it works...
Since your entities are numerically entered anyway, I would recommend the backwards-iterating loop, so you only have to have one loop, not two. I think this solution is not actually working, but I could be wrong. A .love would be nice, just to test.

Re: Problem with drawing moving sprites.

Posted: Sat Feb 22, 2014 6:24 pm
by Moonkis
davisdude wrote:One minor thing:
- Instead of if e:isAlive() == false then you can do if not e:isAlive() then. Not really important, but I think it looks better, and it takes less time to type. You can do whatever you want to do, though.

As for your solution, that's not the way I would do it, but I guess if it works...
Since your entities are numerically entered anyway, I would recommend the backwards-iterating loop, so you only have to have one loop, not two. I think this solution is not actually working, but I could be wrong. A .love would be nice, just to test.
Please add a suggestion of how to do it, I'm still a newbie to Lua and I'm interessted in alternative solutions!

I do have 2 questions:

* How to correctly add item to table WHILE iterating over it?
* I know I can delete items from tables when iterating backwards, but rumors say you can "nil" an index also, how do you do that correctly?

I think those questions are the root and key to this problem of mine :)

Re: Problem with drawing moving sprites.

Posted: Sat Feb 22, 2014 6:37 pm
by davisdude
Moonkis wrote:Please add a suggestion of how to do it, I'm still a newbie to Lua and I'm interessted in alternative solutions!
I'm assuming you're talking about backward iteration for your entities. If so, here's how you would do it:

Code: Select all

for a = #EntityManager.objects, 1, -1 do 
     local Entity = EntityManager.objects[a]
     if Entity.update then
          Entity:update(dt)
     end
     if not Entity:isAlive() then
          table.remove( EntityManager.objects, a )
     end
end
If you don't understand what's going on here, don't hesitate to ask! :)
Moonkis wrote:* How to correctly add item to table WHILE iterating over it?
It depends on the situation. If you want the newly added item to be updated immediately, that would be fairly complex. If you were alright with it being updated later, though, it would be easier.
Here's how you would do the easier one:

Code: Select all

for a = #EntityManager.objects, 1, -1 do 
     local Entity = EntityManager.objects[a]
     if Entity.update then
          Entity:update(dt)
     end
     if not Entity:isAlive() then
          table.remove( EntityManager.objects, a )
     end

     if ThingHappensHereThatMakesNewEntity then
          table.insert( EntityManager.objects, Thing ) -- Thing being what you want inserted.
     end
end
The first option is much more difficult. I'll give it a whirl (warning: code is untested).

Code: Select all

for a = #EntityManager.objects, 1, -1 do 
     local Entity = EntityManager.objects[a]
     if Entity.update then
          Entity:update(dt)
     end
     if not Entity:isAlive() then
          table.remove( EntityManager.objects, a )
     end

     if ThingHappensHereThatMakesNewEntity then
          ShiftTable( a, EntityManager.objects )
          Table[a - 1] = Thing -- Thing still being the added item. 
     end

     local function ShiftTable( Start, Table )
          for e = 1, #Table do
               Table[e + 1] = e
          end
     end
end
That should work, but don't hold me to it. I probably made a mistake somewhere.
Mookis wrote:* I know I can delete items from tables when iterating backwards, but rumors say you can "nil" an index also, how do you do that correctly?

Code: Select all

if not Entity:isAlive() then
     EntityManager.objects[a] = nil
end
Hope this helps! :)

Re: Problem with drawing moving sprites.

Posted: Sat Feb 22, 2014 8:36 pm
by Robin
davisdude wrote:The first option is much more difficult. I'll give it a whirl (warning: code is untested).
That doesn't work (I see three reasons why not). And even if it worked, it would still be wrong, because then you update the current Entity twice (try to work it out in your head to see why).

Re: Problem with drawing moving sprites.

Posted: Sat Feb 22, 2014 9:28 pm
by davisdude
Of course I made a mistake... :cry: How about this?

Code: Select all

function ShiftTable( Table, Index )
	for a = #Table, Index, -1 do
		Table[a + 1] = Table[a]
	end
end

-- Many lines of code later...

for a = #EntityManager.objects, 1, -1 do
	if ThingHappensHereThatMakesNewEntity then
		ShiftTable( EntityManager.objects, a )
		Table[a] = Thing -- Thing still being the added item. 
	end 
	local Entity = EntityManager.objects[a]
	if Entity.update then
		Entity:update(dt)
	end
	if not Entity:isAlive() then
		table.remove( EntityManager.objects, a )
	end
end

Re: Problem with drawing moving sprites.

Posted: Sat Feb 22, 2014 10:53 pm
by Robin
I didn't test it but it seems to fix almost everything I had a problem with (including one thing I had overlooked).

The one problem is this: suppose we have 3 entities ({"a", "b", "c"}), and after processing the first entity, we insert a new one (so when a = 2, ThingHappensHereThatMakesNewEntity is true, somehow).

Code: Select all

{"a", "b", "c"}, a = 3, EntityManager.objects[a] = "c"
-- new entity inserted here:
{"a", "x", "b", "c"}, a = 2, EntityManager.objects[a] = "x"
{"a", "x", "b", "c"}, a = 1, EntityManager.objects[a] = "a"
-- whoops! we've skipped "b"
And sorry to spoil the fun, but with your new implementation, this:

Code: Select all

		ShiftTable( EntityManager.objects, a )
		Table[a] = Thing -- Thing still being the added item. 
is (probably, I haven't checked it) equivalent to:

Code: Select all

		table.insert( EntityManager.objects, a, Thing )

Re: Problem with drawing moving sprites.

Posted: Sat Feb 22, 2014 11:29 pm
by davisdude
Oh, I didn't know you could do that. That's good to know. :)
Just out of curiosity, how would you do it?

Re: Problem with drawing moving sprites.

Posted: Sun Feb 23, 2014 10:48 am
by Moonkis
If we are only iterating and adding in a loop (no removal) is it safe to use the iterator-loops like ipairs and pairs?