So I'm making a game with LOVE, and I'm messing around with a renderer architecture where you submit "commands" which are processed in batch at the end of each frame. (Maybe "architecture" is too strong a word here; I'm just messing about.)
Anyway, I've got a table of these commands (other tables) and I empty the table after processing it. Is it better to table.remove() each element as I process it, or just set the table to {} afterwards? Or doesn't it make any difference?
This totally isn't the time to be optimising, but I'm still curious.
"Questions that don't deserve their own thread" thread
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
- bartbes
- Sex machine
- Posts: 4946
- Joined: Fri Aug 29, 2008 10:35 am
- Location: The Netherlands
- Contact:
Re: "Questions that don't deserve their own thread" thread
As in most cases, the actual solution is measuring. That said, table.remove is fairly slow, especially if you're not removing the last element (so it has to shift the rest down). Whether setting every index to nil as you're iterating over it or creating a new table is faster is a much more interesting question. Though creating a single table is probably not something you should be worrying about.
Re: "Questions that don't deserve their own thread" thread
Thanks.bobbyjones wrote:You could set them to a dummy value. Like "nil". That way you could continue to use ipairs. In another table store the indexes that are "nil". When ever you create a new entity throw it in the first "nil" spot. The benefit of nil vs "nil" is you could still use ipairs. (In luajit ipairs is usually faster)
Another benefit is that ipairs preserves the order. Not sure I will need to keep things in order, but it certainly will not hurt. There is a slight performance penalty since I need to check for the sentry value ("nil") on every iteration.
I am not certain whether I will recycle the slots in the table. It would be simpler without and the order would be preserved. On the other hand, without recycling I will run out of memory eventually.
As usual, benefits and drawbacks. I guess I will think about whether I will need the order. I guess that mostly draw order will matter, and that might require another solution anyway. More stuff to think about.
Re: "Questions that don't deserve their own thread" thread
Thanks for the suggestion. You are correct in that I am using separate tables for all sorts of things. One problem with your suggestion is that for example coordinates are used in different contexts, drawing, collision detection, possibly others. Putting the coordinates in a sort of object with other stuff would require either redundancy or I would end up with a OOP-ish thing, the thing I tried to avoid in the first place.S0lll0s wrote: Also murks: if I understand you correctly, each system has a table like
If that is the case, why don't you do it like thisCode: Select all
positions = { [3] = {10, 20}, [9] = {4, 4}, ... } sprites = { [3] = entity_sprite_one, [9] = entity_sprite_two, ... }
instead? That would probably make your code a lot more readable and the performance impact should be negligible.Code: Select all
entities = { [{ sprite = entity_sprite_one, position = {10, 20} }] = true, [{ sprite = entity_sprite_two, position = {4, 4} }] = true } -- or basically entities = {} -- making a new entity local ent = { sprite = sprite, position = {10, 20} } entities[ent] = true
Using the table as key ('unorderet set' - http://lua-users.org/wiki/TablesTutorial) is probably a good idea here since the item count should not matter most of the time.
I am still considering to keep the component tables separate but add a list of components to the entities in order to make access to components belonging to a certain entity easier. Not sure it is worth the trouble.
Re: "Questions that don't deserve their own thread" thread
I don't see the point in avoiding OOP for the sake of avoiding OOP. Also it's not OOP until you put all the methods in there (and ECS and OOP are not mutually exclusive).murks wrote:Thanks for the suggestion. You are correct in that I am using separate tables for all sorts of things. One problem with your suggestion is that for example coordinates are used in different contexts, drawing, collision detection, possibly others. Putting the coordinates in a sort of object with other stuff would require either redundancy or I would end up with a OOP-ish thing, the thing I tried to avoid in the first place.S0lll0s wrote: instead? That would probably make your code a lot more readable and the performance impact should be negligible.
Using the table as key ('unorderet set' - http://lua-users.org/wiki/TablesTutorial) is probably a good idea here since the item count should not matter most of the time.
I am still considering to keep the component tables separate but add a list of components to the entities in order to make access to components belonging to a certain entity easier. Not sure it is worth the trouble.
Re: "Questions that don't deserve their own thread" thread
I simply want to give the ECS concept a go, as simple and close to the t-machine approach as possible. Except fpr using a DB, as this would complicate stuff too much for my taste, and I think it is unnecessary for a small game.
I think ECS and OOP can be combined, but I also think that it is hard to do sensibly. Since Lua itself is not a OOP language I try to avoid OOP entirely.
Admittedly, for the very simple ECS approach I use in this game there will hardly be any benefit over what you suggest there or a true OOP approach. It is more a learning experience. There are slightly more complicated ways to design a ECS that would, in a somewhat bigger game, provide some benefits. Drawbacks as well of course.
I think ECS and OOP can be combined, but I also think that it is hard to do sensibly. Since Lua itself is not a OOP language I try to avoid OOP entirely.
Admittedly, for the very simple ECS approach I use in this game there will hardly be any benefit over what you suggest there or a true OOP approach. It is more a learning experience. There are slightly more complicated ways to design a ECS that would, in a somewhat bigger game, provide some benefits. Drawbacks as well of course.
Re: "Questions that don't deserve their own thread" thread
I don't think it's wrong or "OOP-ish" to have tables as components. I think this quote bears repeating, especially the parenthesized part...murks wrote:Putting the coordinates in a sort of object with other stuff would require either redundancy or I would end up with a OOP-ish thing, the thing I tried to avoid in the first place.
Now, there are different ideas about what ECS really means. Some people use a lot of functions or methods attached to components (or maybe the components themselves are methods). This is probably what you mean by "OOP-ish." Others believe that components should not have any functionality, and should just be data; after all, the functionality belongs in the systems, right?S0lll0s wrote:Also it's not OOP until you put all the methods in there (and ECS and OOP are not mutually exclusive).
Just because the components should be data, though, doesn't mean they need to be primitive data. They can just as well be tables of things that go together. Do you really want four components for an RGBA value? Would you couch it in a string to avoid a table? There's no advantage to that over using a table.
Here's my personal view on components with functionality versus components with only data; it's just my opinion and you can take it or leave it. In my view an important part of ECS is that systems focus on components and not on entities, since this is where the decoupling benefits come from.
For the most part, components should only contain data, and systems should process that data, but I think it's useful to make an exception for things that need to happen to the entity rather than with its components. Any functionality concerned with the entity (for example, adding or removing the entity in the entity list, or adding/removing components) can (and maybe should) be moved into components, so that systems can be strictly component-centric and can work without any knowledge of entities at all.
Incidentally, you might follow that idea to the conclusion that a system's "process" function should actually receive individual components as its arguments instead of an entity, and if you wanted to modify those components, all primitives would need to be boxed anyway since we have no pass-by-reference for primitives in Lua.
- zorg
- Party member
- Posts: 3465
- Joined: Thu Dec 13, 2012 2:55 pm
- Location: Absurdistan, Hungary
- Contact:
Re: "Questions that don't deserve their own thread" thread
Interestingly, the functionality that handles entities may be called _______Manager classes, in OOP termsairstuck wrote:(...) Any functionality concerned with the entity (for example, adding or removing the entity in the entity list, or adding/removing components)...
Basically, only existing to handle more of one type of something.
Anyway, i agree with airstuck mostly, though where i might disagree, table usage inside components, it's a bit moot for various reasons, including the fact that lua tables don't guarantee that all array elements will be next to each other -in memory-, so no consistent caching-related speedups to be had. (And turning it to a fully SoA approach from AoS is in my eyes, unwieldy)
Still, accessing table members does carry a minute penalty in speed, and it does add up for many entities (more than 10k, say) and so does memory usage.
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Re: "Questions that don't deserve their own thread" thread
I am not quite sure how to understand the part about putting entity management stuff into components. At the moment this stuff is handled outside the ECS itself. Admittedly, I have the feeling that it is the weakest part in my concept and would ideally be handled more elegantly.airstruck wrote: For the most part, components should only contain data, and systems should process that data, but I think it's useful to make an exception for things that need to happen to the entity rather than with its components. Any functionality concerned with the entity (for example, adding or removing the entity in the entity list, or adding/removing components) can (and maybe should) be moved into components, so that systems can be strictly component-centric and can work without any knowledge of entities at all.
Incidentally, you might follow that idea to the conclusion that a system's "process" function should actually receive individual components as its arguments instead of an entity, and if you wanted to modify those components, all primitives would need to be boxed anyway since we have no pass-by-reference for primitives in Lua.
My systems are simple and do not care about entities as such, they just process tables of components. Only when more than one type of component is needed by a system the entity, which is just a number, serves as a link between components belonging together.
Re: "Questions that don't deserve their own thread" thread
I didn't mean that the entity management stuff itself should be put into components, I meant the code that uses the entity manager could be put there. For example, you could have a firing system that looks for a "fire" component that is a function, or a "weapon" component with weapon:fire(). Then you can easily override "fire" for a shotgun weapon that uses the entity manager to create a bunch of "shot" entities at random angles, or an automatic rifle that uses the entity manager to schedule the projectiles to appear one after another, or whatever.murks wrote:I am not quite sure how to understand the part about putting entity management stuff into components.
The "fire" function can be pretty much dedicated to using the entity manager to create things. The stuff that involves other components, like figuring out the angle to fire at, or what kind of projectiles to use, or if it needs to be reloaded, can be done in the firing system and passed into "fire."
FFI structs in place of tables could be an option for squeezing more performance out. In general I figure using ECS is already making a tradeoff between raw speed and convenient design, so you might as well make the design as convenient as possible as long as it's not an issue.zorg wrote:Still, accessing table members does carry a minute penalty in speed, and it does add up for many entities (more than 10k, say) and so does memory usage.
Who is online
Users browsing this forum: Semrush [Bot] and 2 guests