« first day (4110 days earlier)      last day (926 days later) » 

11:37 AM
@DMGregory Thanks ! :)
Besides that... what makes more sense in terms of archebased ecs architecture ? Storing the components in an archetype as a struct of arrays ( Player[], Transform[], Rotation[] ) or storing them as an array of structs ( (Player, Transform, Rotation)[] ) ? ^^
I'd recommend testing that, SOA could be more cache friendly if you access a specific component after another, but if your processing is instead more towards "Take this Player, Transform and Rotation component, do things to them, then move to the next entity", you might have better memory access pattern using AOS
@Tyyppi_77 Alright ^^ Its just pretty hard to come along with an implementation in c#... i would knew how i could implement aos ( by using pointers basically )... but i have no clue how to implement it as soa yet. But the performance difference shouldnt be that huge right ? So probably it doesnt really matter what to choose ? ^^
I really can't comment on generics of performance. In trivial cases data layout can be a massive difference, dunno about more complex game systems
12:32 PM
Well guess i need to test it then :D Thanks !
I think you'll have an easier time with SOA here, because not every system is exclusive to an archetype. You might have a SpriteRenderer component that's used in an archetype for decals (together with just a Transform), and in an archetype for walls/obstacles (together with a Transform and a BoxCollider component), and in an archetype for movable objects (with a Transform, BoxCollider, and Rigidbody)...
Your SpriteRendering system probably doesn't care about that physics stuff though. It just wants to consume parallel arrays of SpriteRenderers and their matching Transforms.
By keeping those components in distinct arrays, the system doesn't need to know how to fish the components it wants out of the archetype's structure for each index.
That makes it a bit easier for each system to peek at just the parts of an archetype it cares about.
12:48 PM
@DMGregory Thats right, thanks ^^ Do you have any idea how that would look like in c# ? Each archetype needs to look like this basically : Archetype{ A[], B[], C[].... XXX[] so using generics here wont work. All i can imagine right now is using code generation, but i have no experience in that topic. Are there other ways ?
You could make an archetype an array of arrays of components, together with a lookup table that maps a component type to its index in the array. Then it could expose something like GetComponentArray<T> that gets the correct array and casts it to the correct type to return it.
@DMGregory Ah i see ^^ But wouldnt this produce more cache misses ? And probably even boxing ?
Fortunately you need to do the lookup only once for each archetype, and then you have straight sequential/contiguous iteration over an array of the correct concrete type for all the instances of that archetype. So mispredictions/misses when looking up the component table are rare compared to the bulk of your work.
I don't think it incurs any boxing, since the value passed between functions is the true concrete type. We just have a less restrictive container for long-term storage. There will be casting overhead because the runtime has to verify the runtime type matches, but again this is once per archetype, not per instance.
So the decal archetype's array might look like
_components = new Component[][] { new Transform[_maxCapacity], new SpriteRenderer[_maxCapacity] };
Note how the contained arrays are the right types all along, we just have them in a more permissive container for storage/indexing.
1:16 PM
So if i understood you correctly... this would be a valid archetype : Archetype{ Types[] types, void* componentArrays } then we could get the certain component array by... if the first type is Transform for example we could get the array by (Transform*)componentArrays[0] and acess the indexes via myTransformPtr[0] ^^
Just saw that you posted something different xD
Well a Component[][] array would require Transform and SpriteRenderer to have a common base right ? Would that work with pure structs ?
Not that different - same basic idea.
I think you might be able to work around that by making the outer array a System.Array type. Let's see...
Yep, this is valid C#:
System.Array[] _components = new System.Array[] { new Vector3[3], new Quaternion[3], new Color[3] };
And I can pull out the third vector with something like ((Vector3[])_components[0])[2]
@DMGregory This is insane ! :D I didnt knew that this class exists... It looks way nicer and is much easier to use. Thanks ! ^^
It has some overhead, so I don't want to claim this is free. ;) But again hopefully you have far fewer system-archetype interactions than system-instance interactions, so it's unlikely to be a bottleneck.
1:33 PM
@DMGregory Well i guess thats acceptable :D
Besides that... it would be great to disable/enable certain components on entities. How could we integrate this in our archetypes ? ^^
Hmmm, that's trickier if you're trying to optimize for cache/throughput.
If you want to disable a whole instance, you can swap it to the end of the active instances and decrement your active count, and then only iterate over the first activeCount entries of each array. That keeps the iteration dense.
But if you need to enable/disable components one by one, your best bet is probably an enabled flag in the data for the components that support disabling. Then you can have a branch in your iteration loop that skips them. That means less benefit from prediction and caching, but if it's infrequent it should be fine.
Another option is to "lend" the entity to another archetype that has only the active components on it. The original archetype's copy stays around - swapped to the inactive pile as described above - so you don't lose the data stored on the inactive components. When the component is re-enabled, copy the entity's other data back from the archetype you lent it to, and re-activate it in this archetype. But this gets hairy if you need to enable/disable multiple components in arbitrary orders.
    class Archetype {
        System.Type[] _componentTypes;
        System.Array[] _components;

        int _capacity;
        public int Count { get; private set; }

        public Archetype(int capacity, params System.Type[] componentTypes) {

            _capacity = capacity;
            _componentTypes = componentTypes;

            _components = new System.Array[componentTypes.Length];
            for( int i = 0; i < componentTypes.Length; i++) {
                _components[i] = System.Array.CreateInstance(componentTypes[i], _capacity);
Just tested this and it seems to work. You can do something like new Archetype(8, typeof(Transform), typeof(SpriteRenderer))
1:59 PM
Thanks a lot ! ^^ The idea with swapping them around is actually pretty cool... the easiest however is to wrap each component into another struct which contains that flag you mentioned :D well i will see whats easier to implement. And thanks for the code ! ^^
I don't recommend making it a universal wrapper like that. There's likely to be no reason to "disable" many component types - like having a position. An entity has a position component or it doesn't. Having a disabled position doesn't make sense.
That makes sense :D
4 hours later…
6:00 PM
Why the fuck is my particle pool a vector of unique_ptrs..? I've decided to just ditch data locality and any benefit I could get from something like a pool...
6:59 PM

« first day (4110 days earlier)      last day (926 days later) »