From f207e1c83fcbaf089bab9e6cd9ca924a3e3a8a4e Mon Sep 17 00:00:00 2001 From: sadpmpk Date: Fri, 30 Dec 2022 04:26:42 -0500 Subject: [PATCH] Update 'Step 0: ECS Architecture' --- Step-0%3A-ECS-Architecture.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Step-0%3A-ECS-Architecture.md b/Step-0%3A-ECS-Architecture.md index 8534ae3..dd4273f 100644 --- a/Step-0%3A-ECS-Architecture.md +++ b/Step-0%3A-ECS-Architecture.md @@ -56,4 +56,21 @@ The first three maps are to quickly accesses the respective entities and compone Due to the implementation of the data structure, it can only handle void pointer. Although it is possible to implement a map to a struct pointer, I didn't really bother. Therefore, the pointer obtained has to be casted according. For safer development, I should look into implementing a map to struct instead. The `to_add` and `to_remove` fields are to handle _iterator invalidation_. This is explained in the lecture series. This arises when the data structure is modified _while_ iterating through it. When adding or removing an entity, they are not immediately added to the map but is added to the respective fields. After that, the entity manager will be updated to properly include the newly added entity and drop the removed entity. Due to this design, this update procedure has to be explicitly called. -# Memory Pool \ No newline at end of file +# Memory Pool +In a game, it is expected than entities can be created and removed at any time, thus it makes sense to use dynamic allocation for them (using malloc/free). However, it does have performance drawback. Particularly, I am not too fond of the slower call speed and memory fragmentation that can happen due to this. +One way to solve this is to implement a memory pool for the entities and components. This way, a new entity will merely draw from the pool, and a removed entity will just return to the pool. No new allocation needed. This is covered by the lecture series as well, though it is much later down the series. +This is actually a premature optimisation, which is bad. However, I thought it would be fun to implement a memory pool. That's why I did it. +**Note: this does not get rid of dynamic allocation usage. The library SC will make use of it for obvious reasons.** +The mempool struct can be seen in `mempool.c`: +``` +typedef struct MemPool +{ + void * const buffer; + const unsigned long max_size; + const unsigned long elem_size; + bool * use_list; + struct sc_queue_uint free_list; +}MemPool_t; +``` +The first three fields are generic fields about the memory pool. The `use_list` and the `free_list` are used to keep track of which elements are free and in use. +A queue is used for the free list so that each element can be used evenly. A boolean array is used to keep track of whether an element is in use. It's a bit easier on the mind doing this way although it is not as memory efficient. \ No newline at end of file