In this series of posts I will be testing architectures and algorithms for ECS simulation. Particular those related to procedural generation and worlds with a large number interacting agents. I think about the simulations controlling things like a sim city style game or ecological simulation as opposed to first person centered game like an RPG or shooter. The main difference being in an RPG even if there thousands of agents in a world only the ones the player are simulated at any moment. Whereas in a sim city type game all the parts of the city are simulated each tick and can interact with each other. So in a zombie shooter with 1,000 zombies there are 1000 zombie player actions plus some physics interaction between zombies(handled by Unity), whereas in forest Sim city there are 1000 x 1000 possible animal interactions. So a system needs to efficiently find and execute only those interactions that will occur.
One possible solution I may explore later is letting unity physics do this work by attaching multiple colliders to each agent. For example A deer may have 1m eat collider that only colliders with plants. It may have 100m sight collider that collides with other animals and 15m smell collider the collides with other animals.
I also want to look at existing models of real world ecology models, so I will start by building a very simple model from a paper looking at the ecology of sleep.
Acerbi, A., McNamara, P. & Nunn, C.L. To sleep or not to sleep: the ecology of sleep in artificial organisms. BMC Ecol 8, 10 (2008). https://doi.org/10.1186/1472-6785-8-10
In the Method part of the paper these use ODD to describe model. In my implementation each 40x40 grid of patches is identified by a simID and there 100 of these levels. Each on has one agent and 40 sleep patches and 40 different food patches. Food patches start with 15~200 food and eating reduces the food by 1. Each tick an agent can eat, sleep or move. The choice is controlled by one of 24 gene. Each gene determines what the agent will attempt to for the 60 ticks that ake 1 hour. If it tries to eat and it on patch with > 1 food it gain 3 food energy and the patch is depleted by 1, otherwise it moves and lose one food energy, either way it looses 1 sleep energy. Sleep works similarly except sleep patches are not depleted. there is a third gene for choose. If either of the foodFitness or energy fitness is 0.1 greater than the other it treis to do the lower fitness, otherwise it tries to do what it did last hour. Fitness is a sigmoid function based on food energy or sleep fitness. At the end of 7 days (each tick is 1 minute) the 20 agents with the best fitness make 5 offspring each and each gene has a 5% chance to mutate to a random gene among the three types.
At first tracked patches as entities with a food value (int 0~200) and a sleep value (bool) each entity was created and a ref was store in Entity[40x40x100] the agent would ask static function for the patch it was on. This worked fine for 40x40x10 but making these 160K of entities was too slow. Since the sleep value is constant for any patch after setup and if the food value is 0 it is also constant,only a single emptyPatch and a single sleepPatch were needed. this meant only about 4K of patches were needed. These still slow at 3 minutes to setup. so I change the Entity[40x40x100] lookups for dictionary<int3, entity> lookup. Empty patch were not stored in the dictionary only sleep and food patches. if a index was not found in the dictionary the single emptyPatch was returned. This took 12 seconds to setup and 90 seconds to run 7days for 100 agents.
The code is available here https://github.com/ryuuguu/ECS_EcologyOfSleep. It has an incomplete UI since it was only made to test ECS model ideas. All test were run in the editor. Package version was Entities 0.5.0 preview.17
Speed Tests
These tests are run for 1 day of ticks not 7 so in actual runs generation times would be 7x longer. Clear is removing patches and agents from lists used during the run and storing them for reuse. New time is setup of new patches locations and settings. Both are main thread only.
5000 agents would mean a dictionary length of 400K and 200K of food patches. This seems to be a problem, causing the editor stall for more than 10 minutes. it might end up working but I did not wait. If this size were needed, patches could be replaced single byte integers instead of entities and function to manage them.
100 agents, 0s Clear, 0s New, 12s generation
500 agents, 3s 7s 13s
1000 agents, 12s 20s 14s
5000 agents, locks up
My conclusion is ECS can handle 200K of fish in example so the problem is my main thread code for generating and tracking entities architecture. The actual number of agents the ECS jobs could handle I do not know because my main thread setup stopped working.