1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | // NOTE: u16 stands for unsigned short // Entities are just indices typedef u16 entity; // Enums for attribute types #define ATTRIBUTE_TRANSFORM 0 #define ATTRIBUTE_POSITION 1 #define ATTRIBUTE_VELOCITY 2 #define ATTRIBUTE_RENDER 3 #define ATTRIBUTE_LOGIC 4 #define ATTRIBUTES_TOTAL 5 struct entityData { u16 numEntities; u16 maxEntities; // Indices that are available for reuse u16 maxRemoved; u16 numRemoved; entity *entityRemoved; u16 maxCreateCalls; u16 numCreateCalls; entityCreateCall *listCreateCalls; u16 maxRemoveCalls; u16 numRemoveCalls; entityRemoveCall *listRemoveCalls; // From here follows attribute data u16 numTransform; u16 maxTransform; mat3 *transform; u16 numPosition; u16 maxPosition; vec2 *position; u16 numVelocity; u16 maxVelocity; vec2 *velocity; // Render u16 numRender; u16 maxRender; entityRender *render; // Basically memory arenas, // Allocates data wherever there's free space buffer *vertices; buffer *indices; // Logic u16 numLogic; u16 maxLogic; entityLogic *logic; buffer *logicNodes; // Entity and attribute index maps, I'll talk about them below // col: Attribute type row: entity index value: attribute index u16 *mapIndex; // col: Attribute index row: Attribute type value: entity index u16 *mapEntity; } entityData; |
1 2 3 4 5 6 7 8 9 | entity e = entityCreate(); entityAssignTransform(e); entityAssignPosition(e); entityAssignVelocity(e); entityAssignRenderSprite(e, someSprite, someMaterial); entityAssignLogic(e, someLogicTemplate); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | void entityAssignTransform(entity e) { u16 index = entityData.numTransform; entityData.numTransform++; entityRegisterAttribute(e, index, ATTRIBUTE_TRANSFORM); entityData.transform[index] = mat3Identity(); } void entityRemoveTransform(entity e) { u16 removed = entityGetIndex(e, ATTRIBUTE_TRANSFORM); entityData.numTransform--; // Replace removed attribute with the last one in the matrices entityReplaceAttribute(e, removed, entityFromIndex(entityData.numTransform, ATTRIBUTE_TRANSFORM), entityData.numTransform, ATTRIBUTE_TRANSFORM); // Copy data entityData.transform[removed] = entityData.transform[entityData.numTransform]; } |
1 2 3 4 5 6 | void systemRun(/*extra arguments it may need*/) { for (i = 1; i < entityData.numOfSomething; i++) { // Do things to attribute // Perhaps even fetch other attributes owned by its entity if required. } } |
I was surprised to see this thread risen from the grave. I don't know if I would endorse anything I've written in this thread nowadays. Also I haven't really touched entity systems since then.
Regarding the logic system, it was basically a behavior tree.
Thanks for answering. I had no idea what you meant by logic nodes, other than it was some kind of graph. I am familiar with BTs.
I raised it because I'm interested in graph based scripting, as I think it would be easier and cleaner to make than using a text based script solution. Its just a matter of finding a design that is nice to use.