using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; using TransportGame.Model.Road; using TransportGame.Utils; using UnityEngine; namespace TransportGame.Model { [XmlRoot("map")] public class Map { private float[,] heightmap; #region Properties /// /// Gets or sets the biome /// [XmlElement("biome")] public Biome Biome { get; set; } /// /// Gets or sets the water level /// [XmlElement("waterLevel")] public float WaterLevel { get; set; } /// /// Gets the heights array in range [0,1] /// [XmlIgnore()] public float[,] Heightmap { get { return heightmap; } } /// /// Gets or sets the heights as raw bytes /// [XmlElement("heightmap")] public byte[] HeightmapRaw { get { return heightmap.ToByteArray(); } set { heightmap = value.GetFloatMatrix(); } } /// /// Gets width of heightmap /// [XmlIgnore] public int Width { get { return (heightmap == null) ? 0 : heightmap.GetLength(0); } } /// /// Gets height of heightmap /// [XmlIgnore] public int Height { get { return (heightmap == null) ? 0 : heightmap.GetLength(1); } } /// /// Gets or sets the population map /// [XmlArray("populationCenters")] [XmlArrayItem("center")] public List PopulationCenters { get; set; } /// /// Gets or sets the articulation road network /// [XmlElement("roadNetwork")] public RoadNetwork RoadNetwork { get; set; } #endregion #region Constructors /// /// Initializes the map /// /// /// Warning: heights array will be null. /// public Map() { PopulationCenters = new List(); } /// /// Initializes the map /// /// Width /// Height public Map(int width, int height) { heightmap = new float[width, height]; PopulationCenters = new List(); } #endregion /// /// Gets the cell at specified position in range [0, Biome.Height] /// /// X /// Y /// Value public float GetHeight(int x, int y) { return heightmap[x, y] * Biome.Height; } /// /// Sets the height at specified position in range [0, Biome.Height] /// /// X /// Y /// Value public void SetHeight(int x, int y, float value) { heightmap[x, y] = value / Biome.Height; } /// /// Returns true if specified cell is a water cell /// /// X /// Y /// public bool IsWater(int x, int y) { return GetHeight(x, y) <= WaterLevel; } /// /// Returns true if given coordinates is inside the map /// /// X /// Y /// True if coordinates are inside the map public bool IsInside(int x, int y) { return x >= 0 && y >= 0 && x < Width && y < Height; } /// /// Gets steepness in specified point /// /// X /// Y /// Steepness public float GetSteepness(int x, int y) { if (x == 0) x++; if (y == 0) y++; float dx = GetHeight(x - 1, y) - GetHeight(x, y); float dy = GetHeight(x, y - 1) - GetHeight(x, y); return dx * dx + dy * dy; } /// /// Gets population using terrain coordinates /// /// X /// Y /// Population public float GetPopulation(int x, int y) { const int maxDistance = 400; float value = 0; foreach (var point in PopulationCenters) { int x1 = x - point.X; int y1 = y - point.Y; int dist = x1 * x1 + y1 * y1; if (dist < maxDistance * maxDistance) { float influence = 1 - (float)dist / (float)(maxDistance * maxDistance); influence = Mathf.Pow(influence, 3); // Ease value = Mathf.Clamp01(value + influence); } } return value; } } }