Unicellular – Manager-Driven ECS

Codebase Breakdown • Unity • Custom ECS • Simulation

Overview

A 2D life simulation where colourful unicells roam, fight, and evolve. The project uses a manager-driven ECS-style architecture in Unity to keep systems modular and scalable.

Architecture

Gameplay is coordinated by specialised managers handling entities, economy, camera and UI.

Data Model

Persistent statistics for each unicell are stored in a simple serialisable class.

FieldTypeDescription
SpeciesstringIdentifier for the unicell species
DamagefloatBase attack damage
MaxHealthfloatMaximum health value
LevelintCurrent evolution level
XPfloatAccumulated experience points
XP_ThresholdintXP required for next level
BaseScaleVector2Default sprite scale

Key APIs / Contracts

Entity Manager

public void SpawnUnicells(UnicellSpecies species, int amount);

Economy Manager

public void IncrementUnicellPopulation(string unicellType);

Representative Code Snippets

Spawning species-specific cells – loops through count and initialises each with the correct prefab.

Show code
@EntityManager.cs lines 1422-1468
public void SpawnUnicells(UnicellSpecies species, int Amount)
{
    for (int x = 0; x < Amount; x++)
    {
        switch (species)
        {
            case UnicellSpecies.Blue:
                initialUnicell = Instantiate(blueUnicellPrefab).GetComponent<Unicell>();
                initialUnicell.transform.parent = BlueUnicellsGameObject.transform;
                Initialise(initialUnicell, Unicell.UnicellSpecies.Blue);
                break;
            case UnicellSpecies.Pink:
                initialUnicell = Instantiate(pinkUnicellPrefab).GetComponent<Unicell>();
                initialUnicell.transform.parent = PinkUnicellsGameObject.transform;
                Initialise(initialUnicell, Unicell.UnicellSpecies.Pink);
                break;
            case UnicellSpecies.Yellow:
                initialUnicell = Instantiate(yellowUnicellPrefab).GetComponent<Unicell>();
                initialUnicell.transform.parent = YellowUnicellsGameObject.transform;
                Initialise(initialUnicell, Unicell.UnicellSpecies.Yellow);
                break;
            case UnicellSpecies.Green:
                initialUnicell = Instantiate(greenUnicellPrefab).GetComponent<Unicell>();
                initialUnicell.transform.parent = GreenUnicellsGameObject.transform;
                Initialise(initialUnicell, Unicell.UnicellSpecies.Green);
                break;
            case UnicellSpecies.Purple:
                initialUnicell = Instantiate(purpleUnicellPrefab).GetComponent<Unicell>();
                initialUnicell.transform.parent = PurpleUnicellsGameObject.transform;
                Initialise(initialUnicell, Unicell.UnicellSpecies.Purple);
                break;
            case UnicellSpecies.Red:
                initialUnicell = Instantiate(redUnicellPrefab).GetComponent<Unicell>();
                initialUnicell.transform.parent = RedUnicellsGameObject.transform;
                Initialise(initialUnicell, Unicell.UnicellSpecies.Red);
                break;
            case UnicellSpecies.Orange:
                initialUnicell = Instantiate(orangeUnicellPrefab).GetComponent<Unicell>();
                initialUnicell.transform.parent = OrangeUnicellsGameObject.transform;
                Initialise(initialUnicell, Unicell.UnicellSpecies.Orange);
                break;
        }
        initialUnicell.transform.position = new Vector2((Random.value * Amount * 10) - (Amount / 2f), (Random.value * Amount * 10) - (Amount / 2f));
        initialUnicell.CurrentState = UnicellState.Idle;
        RegisterUnicell(initialUnicell);
    }
}

View on GitHub (lines 1422–1468)

Adjusting target populations – ensures economy goals drive spawning needs.

Show code
@EconomyManager.cs lines 901-930
public void IncrementUnicellPopulation(string UnicellType)
{
    switch (UnicellType)
    {
        case "Blue":
            TargetBlueUnicellPopulation++;
            break;
        case "Pink":
            TargetPinkUnicellPopulation++;
            break;
        case "Yellow":
            TargetYellowUnicellPopulation++;
            break;
        case "Green":
            TargetGreenUnicellPopulation++;
            break;
        case "Purple":
            TargetPurpleUnicellPopulation++;
            break;
        case "Red":
            TargetRedUnicellPopulation++;
            break;
        case "Orange":
            TargetOrangeUnicellPopulation++;
            break;
        default:
            Debug.LogError("EconomyManager IncrementUnicellPopulation() - Unknown UnicellType for target population incrementation");
            break;
    }
}

View on GitHub (lines 901–930)

Performance Notes

Initial profiling focuses on entity spawning and per-frame manager updates; further optimisation is ongoing.

All profiling was recorded in-editor on a Ryzen 7 7800X3D. Demo clips on the main portfolio page show:

  • 1000 Unicells sustaining 144+ fps.
  • 6000 Unicells maintaining roughly 100 fps.
1000 Unicells @ 144+ fps
6000 Unicells @ ~100 fps

Testing & Validation

Functionality is verified through manual playtesting; automated unit tests are not yet available.

Manual playtests were carried out with multiple people. One tester discovered a bug where 64-bit long values were truncated to 32-bit ints; explicit conversions have been added to prevent this from recurring. Automated unit tests are not yet available.