Im working on a simulations where hundreds of thousands of pops have to grow each timestep. Each pop is its own class with a population growth function that grows the pop according to its size, birth rate, and death rate. The pops are told to grow by the tile manager which has all 725k (50 pops per tile, 14.4k tiles) pops in a list. Updating all these pops causes the game to run at 20 fps, however I cant have only some pops grow to preserve balance in the simulation. Is there anyway to optimize this without ripping apart the whole system?
// Pop class
public class Pop
{
// Population
public int population;
//int dependents;
//int workers;
public const float baseBirthRate = 0.04f;
public const float baseDeathRate = 0.037f;
// Stats
public Tile tile;
public State state;
public Culture culture;
public void GrowPopulation(){
float birthRate = 0f;
if (population > 1){
birthRate = baseBirthRate;
if (population > tile.GetMaxPopulation()){
birthRate *= 0.75f;
}
}
float deathRate = baseDeathRate;
float natutalGrowthRate = (birthRate - deathRate) / 12;
int totalGrowth = Mathf.RoundToInt(population * natutalGrowthRate);
if (Random.Range(0f,1f) < (population * Mathf.Abs(natutalGrowthRate)) - Mathf.FloorToInt(population * Mathf.Abs(natutalGrowthRate))){
totalGrowth += (int) Mathf.Sign(natutalGrowthRate);
}
ChangePopulation(totalGrowth);
}
public void SetTile(Tile newTile){
if (tile != null){
tile.pops.Remove(this);
tile.population -= population;
}
tile = newTile;
if (tile != null){
tile.population += population;
tile.pops.Add(this);
SetState(tile.state);
}
}
public void SetState(State newState){
if (state != null){
//state.pops.Remove(this);
state.population -= population;
}
state = newState;
if (state != null){
state.population += population;
/*
if (!state.pops.Contains(this)){
state.pops.Add(this);
}
*/
}
}
public void SetPopulation(int amount){
if (tile != null){
tile.population -= population;
if (state != null){
state.population -= population;
}
}
population = amount;
if (tile != null){
tile.population += population;
if (state != null){
state.population += population;
}
}
}
public void ChangePopulation(int amount){
int totalChange = amount;
// Changes population
if (population + amount < 1){
DeletePop();
} else {
population += amount;
}
// Updates statistics
if (tile != null){
tile.ChangePopulation(totalChange);
}
}
public void DeletePop(){
if (tile != null){
tile.pops.Remove(this);
tile.ChangePopulation(-population);
}
population = 0;
tile = null;
state = null;
}
public static void MergePops(Pop pop1, Pop pop2){
if (pop1.culture == pop2.culture && pop1.tile == pop2.tile){
pop1.ChangePopulation(pop2.population);
pop2.DeletePop();
}
}
}
// Tile class
public class Tile
{
public TileManager tm;
public TileTerrain terrain; public State state = null;
public Vector3Int tilePos;
public bool border;
public bool frontier;
public bool nationalBorder;
public bool coastal = false;
public bool anarchy = false;
public int carryingCapacity {get; private set;}
public List<State> borderingStates = new List<State>();
// Population
public int population;
public List<Pop> pops = new List<Pop>();
public const int maxPops = 25;
public const float baseBirthRate = 0.04f;
public const float baseDeathRate = 0.037f;
public int GetMaxPopulation(){
return Mathf.RoundToInt(10000 * terrain.biome.fertility);
}
public void GrowPopulation(){
Pop[] popsArray = pops.ToArray();
foreach (Pop pop in popsArray){
pop.GrowPopulation();
}
}
public void ChangePopulation(int amount){
int totalChange = amount;
if (population + amount < 1){
totalChange = population * -1;
population = 0;
} else {
population += amount;
}
if (state != null){
state.population += totalChange;
}
}
}
// Function to update pops
void tickTiles(){
foreach (Pop pop in pops.ToArray()){
if (pop.population < 1){
pops.Remove(pop);
pop.DeletePop();
}
pop.GrowPopulation();
}
/*
foreach (var entry in tiles){
Tile tile = entry.Value;
if (tile.population > 0){
tile.GrowPopulation();
}
}
*/
}
Sorry if this post is bad, I’m new around here and I’m happy to provide more information if needed!