For our virtual creatures, affectionately termed "blobs", the goal is to encourage a diverse range of forms. We've built in a significant degree of freedom, allowing them to evolve into any shape or structure, as long as they adhere to certain guidelines:
This framework ensures that while our blobs have the freedom to evolve and diversify, they remain within a coherent and manageable system.
Given that a blob's structure resembles a tree, we've chosen the QuadTree as our data structure for representing a blob's gene. Interestingly, while each block can potentially connect to four other blocks, due to the restriction that one anchor point always links back to its parent, the resultant tree structure is a ternary tree.
Yet, we opt for a quad tree over a ternary tree. The reason lies in our need to preserve not only the hierarchical information of each block (i.e., identifying its parent) but also its positional details. Specifically, we need to know which anchor point of the block is linked to its parent. This nuanced representation allows us to identify block locations via indices.
Within our tree design:
None.Parent or Child, where parent is an indicator and child is a GenoNode that contains block's information.In our structure, every blob's morphyology can be represented by a unique gene, but not every possible gene relate to a valid structure. So, when a gene is randomly generated, or mutated, we need to check if the new gene corresponds to a valid morphyology structure.
Usually, there are two types of invalidate gene, as shown in the graph below:
The first type of invalidation is easy to prevent if we simply limit the size of child blocks, but the second one is hard to prevent by limiting the generation rule. So, instead of modifying the genration rule, we just check the validation each time there are mophyological changes.
You can find checker function here.