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 range of one population center (distance how far it influences) /// public float PopulationCenterRange { get; set; } /// /// Gets or sets the articulation road network /// [XmlElement("roadNetwork")] public RoadNetwork RoadNetwork { get; set; } /// /// Gets or sets the building lots /// [XmlElement("lots")] public List BuildingLots { get; set; } /// /// Gets or sets the buildings /// [XmlElement("buildings")] public List Buildings { 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(float x, float y) { return GetHeight((int)x, (int)y) <= WaterLevel; } /// /// Returns true if specified cell is a water cell /// /// Position vector /// public bool IsWater(Vector2 p) { return IsWater(p.X, p.Y); } /// /// Returns true if given coordinates is inside the map /// /// X /// Y /// True if coordinates are inside the map public bool IsInside(float x, float y) { return x >= 0 && y >= 0 && x < Width && y < Height; } /// /// Returns true if given coordinates is inside the map /// /// Position vector /// True if coordinates are inside the map public bool IsInside(Vector2 p) { return IsInside(p.X, p.Y); } /// /// 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 steepness in specified point /// /// X /// Y /// Steepness public float GetSteepness(float x, float y) { return GetSteepness((int)x, (int)y); } /// /// Gets steepness in specified point /// /// Position /// Steepness public float GetSteepness(Vector2 pos) { return GetSteepness((int)pos.X, (int)pos.Y); } /// /// Gets population using terrain coordinates /// /// X /// Y /// Population public float GetPopulation(float x, float y) { return GetPopulation(new Vector2(x, y)); } /// /// Gets population using terrain coordinates /// /// Position /// Population public float GetPopulation(Vector2 p) { float value = 0.05f; foreach (var point in PopulationCenters) { Vector2 diff = p - point; float dist = diff.LengthSq; if (dist < PopulationCenterRange * PopulationCenterRange) { float influence = 1 - (float)dist / (float)(PopulationCenterRange * PopulationCenterRange); influence = Mathf.Pow(influence, 6) * 0.7f; // Ease value = Mathf.Clamp01(value + influence); } } return value; } } }