/// <summary> /// Check if a population can access CellPos. /// </summary> public bool CanAccess(Population population, Vector3Int cellPos) { // if accessible // check if the nth bit is set (i.e. accessible for the population) if (AccessMap.ContainsKey(cellPos) && PopulationToID.ContainsKey(population)) { if (((AccessMap[cellPos] >> PopulationToID[population]) & 1L) == 1L) { return(true); } } // population can't access the position return(false); }
/// <summary> /// Update any populations that have access to the given positions. /// </summary> /// <param name="positions">The tiles that were updated (added wall, river, etc.)</param> public void UpdateAccessMapChangedAt(List <Vector3Int> positions) { List <int> UnaffectedID = new List <int>(); HashSet <Population> AffectedPopulations = new HashSet <Population>(); foreach (Population population in Populations) { UnaffectedID.Add(PopulationToID[population]); } foreach (Vector3Int position in positions) { if (!AccessMap.ContainsKey(position)) { continue; } else { long mask = AccessMap[position]; for (int i = 0; i < UnaffectedID.Count; i++) { if (((mask >> UnaffectedID[i]) & 1L) == 1L) { AffectedPopulations.Add(PopulationByID[UnaffectedID[i]]); UnaffectedID.RemoveAt(i); } } } } // Most intuitive implementation: recalculate map for all affected populations foreach (Population population in AffectedPopulations) { Debug.Log("Updating access map for " + population.gameObject.name); CleanupAccessMap(PopulationToID[population]); GenerateMap(population); } }
/// <summary> /// Populate the access map for a population with depth first search. /// </summary> /// <param name="population">The population to be generated, assumed to be in Populations</param> /// <remarks>When this is called that means the terrain had changed for sure</remarks> private void GenerateMap(Population population) { Stack <Vector3Int> stack = new Stack <Vector3Int>(); HashSet <Vector3Int> accessible = new HashSet <Vector3Int>(); HashSet <Vector3Int> unaccessible = new HashSet <Vector3Int>(); Vector3Int cur; List <Vector3Int> newAccessibleLocations = new List <Vector3Int>(); List <Vector3Int> newLiquidLocations = new List <Vector3Int>(); List <float[]> newLiquidCompositions = new List <float[]>(); if (!this.AccessibleArea.ContainsKey(population)) { this.AccessibleArea.Add(population, new List <Vector3Int>()); } // Number of shared tiles long[] SharedTiles = new long[maxPopulation]; TileDataController gridSystemReference = GameManager.Instance.m_tileDataController; // starting location Vector3Int location = gridSystemReference.WorldToCell(population.transform.position); stack.Push(location); // Clear TypesOfTerrain for given population this.TypesOfTerrain[population] = new int[(int)TileType.TypesOfTiles]; // iterate until no tile left in list, ends in iteration 1 if population.location is not accessible while (stack.Count > 0) { // next point cur = stack.Pop(); if (accessible.Contains(cur) || unaccessible.Contains(cur)) { // checked before, move on continue; } // Check tiles that are under construction, make them inaccessible //if (this.buildBufferManager.IsConstructing(cur.x,cur.y)) //{ // unaccessible.Add(cur); // population.HasAccessibilityChanged = true; // continue; //} // check if tilemap has tile and if population can access the tile (e.g. some cannot move through water) GameTile tile = gridSystemReference.GetGameTileAt(cur); // Get liquid tile info if (tile != null && tile.type == TileType.Liquid) { float[] composition = new float[] { 0, 0, 0 }; LiquidbodyController.Instance.GetLiquidContentsAt(cur, out composition, out bool constructing); if (!this.populationAccessibleLiquidCompositions.ContainsKey(population)) { this.populationAccessibleLiquidCompositions.Add(population, new List <float[]>()); } if (!this.populationAccessibleLiquidLocations.ContainsKey(population)) { this.populationAccessibleLiquidLocations.Add(population, new List <Vector3Int>()); } newLiquidCompositions.Add(composition); newLiquidLocations.Add(cur); } if (tile != null && population.Species.AccessibleTerrain.Contains(tile.type)) { // save the accessible location accessible.Add(cur); // save to accessible location newAccessibleLocations.Add(cur); TypesOfTerrain[population][(int)tile.type]++; if (!AccessMap.ContainsKey(cur)) { AccessMap.Add(cur, 0L); } AccessMap[cur] |= 1L << PopulationToID[population]; // Collect info on how the population's space overlaps with others for (int i = 0; i < Populations.Count; i++) { SharedTiles[i] += (AccessMap[cur] >> PopulationToID[Populations[i]]) & 1L; } // check all 4 tiles around, may be too expensive/awaiting optimization stack.Push(cur + Vector3Int.left); stack.Push(cur + Vector3Int.up); stack.Push(cur + Vector3Int.right); stack.Push(cur + Vector3Int.down); } else { // save the Vector3Int since it is already checked unaccessible.Add(cur); } population.HasAccessibilityChanged = true; } // Amount of accessible area //Spaces[population] = accessible.Count; // Store the info on overlapping space int id = PopulationToID[population]; SharedSpaces[id] = SharedTiles; // Update the new info for pre-existing populations for (int i = 0; i < SharedSpaces[id].Length; i++) { if (PopulationByID.ContainsKey(i) && SharedSpaces[id][i] != 0) { SharedSpaces[i][id] = SharedSpaces[id][i]; } } // Update space if (population.HasAccessibilityChanged) { this.AccessibleArea[population] = newAccessibleLocations; this.populationAccessibleLiquidCompositions[population] = newLiquidCompositions; this.populationAccessibleLiquidLocations[population] = newLiquidLocations; } }