ESC with data oriented approach, I can't figure out how to keep my components in the same memory array

Started by
3 comments, last by Shaarigan 3 years, 6 months ago

Basically, the language doesn't matter, I tried both C# and Golang, but I can't, for the life of me, figure out how to have components be inside an array inside my Entity Manager. I am referring to the modern ECS where entities are ID's, Systems handle the logic and Components are just Data. I can easily implement the basic ECS that has components tied to the Entity but I am trying to have them inside an array coupled together. ( https://youtu.be/JxI3Eu5DPwE?t=347​ this refers to the idea I am trying to achieve, basically have the same components together in memory to minimize cache misses). Any help on this? I cannot figure out how exactly to do it, I looked at 10+ examples and they all use ECS that has the components tied to the entity. This is okay but I'd love to try and achieve the same memory components, and that would benefit the performance as this is a server-side simulation.

Basically, Entity-ID, Component - Data, System - Logic.

Entity Manager has SpriteComponents array<SprComp> = … , AIComponents array<AIComp>…

update{ SpriteSystem.update(SprieComponents) (or components themselves hold the arrays)}

Any help on how to achieve this or an example in any language would be really beneficial, any resource, any tip, whatever. If anything, adding me to discord and actually letting me ask a couple more questions would be really helpful as well! I have a general idea but I cannot figure out how to actually implement it, like how do I construct the entity so that the component is held closely together in memory, while still keeping the reference to the same entity. Performance is somewhat important as I'd like to minimize resources that the server uses ( also I am a performance freak so…) .

Advertisement

Basically, the language doesn't matter, I tried both C# and Golang

Well, basically you are wrong about that ? While I don't know Golang, there are definatenly languages that make this kind of stuff easy - the prominent being c++. Most high-level languages won't give you many tools to really pack abitrary data-structure into one area of memory.

Your best bet in C# would be to declare your components as “struct” and hope the runtime does the right packing. This will work well for small components, but if you start getting into sizes larger then say 32 byte c# wil probably still allocate the structs on the heap.

On the contrary side, I can account to that doing that kind of packing is really not that important in ECS, especially if your components got larger. I only got minimal gains going from “each entity has an array of its own components” to “components are continously stored in one memory-area per type”, and it did come at the cost of a lot of headaches (having to make sure to never corrupt memory when components get added/removed, …). The most benefit I personally got was by precalculating all components for a given systems iteration, so the work there is minimal. (I'm working inC++, but in any high-level language I really wouldn't bother with the memory-thing at all, and I'd probably not do it again if I had the choice).

i hope this is ok for u:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;

namespace whatever
{
     public class ai
     {
         public ai()
         {
             foo = 1;
         }
         
         public int foo;
     }
    
     public class phys
     {
         public phys()
         {
             foo = 2;
         }
          public int foo ;
     }
    
     public class anim
     {
         public anim()
         {
             foo = 3;
         }
         public int foo;
     }
    
     public class gfx
     {
         public gfx()
         {
             foo = 4;
         }
         public int foo;
     }
   
    public class Program
    {
        [StructLayout(LayoutKind.Explicit, Pack=1)]
        public struct entity
        {
            public entity(int b1, int b2)
            {
                a = new ai[b1];
                for (int i=0; i<b1; ++i)
                    a[i] = new ai(); 

				// alloc mem for arrays
                p = new phys[b2];
                
                 for (int i=0; i<b2; ++i)
                 	  // then alloc mem for each so p is not p[0]!!!
                     p[i] = new phys();
 
            }

           [FieldOffset(0)]
            public ai[] a;
           [FieldOffset(8)]
            public phys[] p;
        }
        
        public static void Main(string[] args)
        {
           entity e = new entity(8, 4);
           e.a[3].foo = 3;
            
           Console.WriteLine("Hello, World! {0}", Marshal.SizeOf(typeof(entity)));
            
           Console.WriteLine("csharp is weird: {0}", e.a[0].foo);
           Console.WriteLine("csharp is weird: {0}", e.a[3].foo);
           Console.WriteLine("csharp is weird: {0}", e.p[0].foo);

        }
    }
}

i hope this is what u wanted, hope this helps;

i leave it as an exercise for u to complete the code and understand the rest of it;

That's it … all the best ?

Same, no experience with GoLang but C# a lot and here you have to differentiate between two kinds of allocations, byRef and byValue allocation. Classes are always stored as byRef types while structs may differe how they are used. If you declare a struct as a class member or even an array of structs, you allocate the memory inside the parent data structure, which means that memory is allocated inside the class or array. If you have structs that for example implement an interface and you pass them as a reference to that interface, they get boxed, which means that heap is allocated to copy the struct content to and return a pointer to the heap instead. So they are transformed into byRef as well.

So you see it is possible to have continous arrays of value types instead of pointer references also in C#.

You now should specify your system a little more, what do you want to achieve?

I played around with ECS in C# as well (don't ge tconfused from EntityFramework which is not ECS related) and have had success using dynamic keyword and write my own IDynamicMetaObjectProvider and DynamicMetaObject classes. This allows every class to provide an EntityId struct and use the benefits of the DLR to dynamically add and remove components (I call them properties) regardles if the object implements those methods or is a generic one. I intended to use that for our HTML render library to handle objects based on their components when rendered or raising an event in the DOM.

You can have a look at the package on GitHub if you need some reference code

This topic is closed to new replies.

Advertisement