private void ColourContries() { Debug.Log("Color Countries ___________________________________________________________________________________________________________________"); foreach (assemblyCsharp.Province prov in State.getProvinces().Values) { int provIndex = prov.getIndex(); WorldMapStrategyKit.Province mapProv = map.provinces[provIndex]; int countryIndex = mapProv.countryIndex; int nationIndex = prov.getOwnerIndex(); if (countryIndex != nationIndex) { Debug.Log("Reassign Nation"); mapProv.countryIndex = nationIndex; Region provRegion = mapProv.mainRegion; Country newOwnerCountry = map.countries[nationIndex]; map.CountryTransferProvinceRegion(countryIndex, provRegion, true); } } for (int k = 0; k < map.countries.Length; k++) { Color color = new Color(UnityEngine.Random.Range(0.0f, 0.65f), UnityEngine.Random.Range(0.0f, 0.65f), UnityEngine.Random.Range(0.0f, 0.65f)); Nation nation = State.getNations()[k]; // Debug.Log(nation.getName()); nation.setColor(color); map.ToggleCountrySurface(k, true, color); } }
public void placeArmyOnMap(int provIndex, Nation nation, int id) { map = WMSK.instance; GameObject armyPrefabInstance = Instantiate(Resources.Load <GameObject> ("ToonyTinyPeople/TT_ww1/EarlyEraArmy")); WorldMapStrategyKit.Province prov = map.GetProvince(provIndex); if (nation.getType() == MyEnum.NationType.major || nation.getType() == MyEnum.NationType.minor) { if (State.GerEra() == MyEnum.Era.Early) { armyPrefabInstance = Instantiate(Resources.Load <GameObject> // ("ToonyTinyPeople/TT_ww1/EarlyEraArmy")); ("ToonyTinyPeople/TT_ww1/EarlyEraArmy")); } } else { { armyPrefabInstance = Instantiate(Resources.Load <GameObject> ("Model_Warrior/barbOne")); } } Vector2 position = prov.center; GameObjectAnimator army = armyPrefabInstance.WMSK_MoveTo(position); army.gameObject.AddComponent <GenericSoldierController>(); army.name = id.ToString(); SkinnedMeshRenderer[] smrs = armyPrefabInstance.GetComponentsInChildren <SkinnedMeshRenderer>(); foreach (SkinnedMeshRenderer smr in smrs) { if (smr.name.StartsWith("flagcl")) { Debug.Log("Army of " + nation.getNationName()); smr.material = Resources.Load("Flags/Materials/" + nation.getNationName(), typeof(Material)) as Material; } } if (nation.getType() == MyEnum.NationType.major || nation.getType() == MyEnum.NationType.minor) { army.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f); } else { army.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f); } army.preserveOriginalRotation = true; army.terrainCapability = TERRAIN_CAPABILITY.OnlyGround; army.autoScale = true; army.group = 1; army.transform.localRotation = Quaternion.Euler(-30f, 180f, 0f); army.BlocksRayCast = true; army.attrib["owner"] = nation.getIndex(); army.attrib["id"] = id; }
public void drawRailroadOnMap(assemblyCsharp.Province prov, Nation player) { WorldMapStrategyKit.Province mapProvince = map.provinces[prov.getIndex()]; Vector2 provCenter = mapProvince.center; for (int i = 0; i < prov.Neighbours.Count; i++) { if (PlayerCalculator.getAllProvinces(player).Contains(prov.Neighbours[i])) { // draw rail segment from prv to neighbourProv assemblyCsharp.Province neighbourProvince = State.getProvinces()[prov.Neighbours[i]]; if (neighbourProvince.railroad && !neighbourProvince.Linked.Contains(prov.getIndex()) && !prov.Linked.Contains(neighbourProvince.getIndex())) { WorldMapStrategyKit.Province mapNeighbourProvince = map.provinces[prov.Neighbours[i]]; Vector2 neighbourCenter = mapNeighbourProvince.center; Cell startCell = map.GetCell(provCenter); Cell endCell = map.GetCell(neighbourCenter); List <int> cellIndices = map.FindRoute(startCell, endCell, TERRAIN_CAPABILITY.OnlyGround); if (cellIndices == null) { return; } int positionsCount = cellIndices.Count; Debug.Log("Number of positions: " + positionsCount); Vector2[] positions = new Vector2[positionsCount]; for (int k = 0; k < positionsCount; k++) { positions[k] = map.cells[cellIndices[k]].center; } // Build a railroad along the map coordinates LineMarkerAnimator lma = map.AddLine(positions, Color.white, 0.0f, 0.15f); Texture2D railwayMatt = Resources.Load("Sprites/GUI/railRoad", typeof(Texture2D)) as Texture2D; lma.lineMaterial.mainTexture = railwayMatt; lma.lineMaterial.mainTextureScale = new Vector2(16f, 2f); neighbourProvince.Linked.Add(prov.getIndex()); prov.Linked.Add(neighbourProvince.getIndex()); } } } }
public void ApplyScenarioDataToMap() { string nationsPath = Application.dataPath + "/StreamingAssets/Scenarios/" + scenario + "/Nations"; string provincesPath = Application.dataPath + "/StreamingAssets/Scenarios/" + scenario + "/Provinces"; string[] provFiles = Directory.GetFiles(provincesPath, "*.json"); foreach (string file in provFiles) { string dataAsJson = File.ReadAllText(file); var newProvince = Newtonsoft.Json.JsonConvert.DeserializeObject <assemblyCsharp.Province> (dataAsJson); // Debug.Log("Prov quality size" + newProvince.quality[0]); provinces.Add(newProvince.getIndex(), newProvince); map.GetProvince(newProvince.getIndex()).name = newProvince.getProvName(); map.GetProvince(newProvince.getIndex()).customLabel = newProvince.getProvName(); } string[] nationFiles = Directory.GetFiles(nationsPath, "*.json"); foreach (string file in nationFiles) { string dataAsJson = File.ReadAllText(file); var newNation = Newtonsoft.Json.JsonConvert.DeserializeObject <assemblyCsharp.Nation>(dataAsJson); nations.Add(newNation.getIndex(), newNation); Debug.Log("Nation Name: " + newNation.getNationName()); Debug.Log("Nation's Capital " + newNation.capital); // Debug.Log("Nation Name: " + newNation.getNationName()); // Debug.Log("Number of Provinces " + newNation.getAllProvinceIndexes().Count); map.GetCountry(newNation.getIndex()).name = newNation.getNationName(); map.GetCountry(newNation.getIndex()).customLabel = newNation.getNationName(); map.CountryRename("Country" + newNation.getIndex(), newNation.getNationName()); for (int i = 0; i < newNation.getProvinces().Count; i++) { int provIndex = newNation.getProvinces()[i]; WorldMapStrategyKit.Province prov = map.GetProvince(provIndex); prov.countryIndex = newNation.getIndex(); } } }
void ProvinceSubstractProvinceEnclaves(int provinceIndex, Region region, Poly2Tri.Polygon poly) { List <Region> negativeRegions = new List <Region>(); for (int oc = 0; oc < _countries.Length; oc++) { Country ocCountry = _countries[oc]; if (ocCountry.hidden || ocCountry.provinces == null) { continue; } Region mainCountryRegion = ocCountry.regions[ocCountry.mainRegionIndex]; if (!mainCountryRegion.rect2D.Overlaps(region.rect2D)) { continue; } for (int op = 0; op < ocCountry.provinces.Length; op++) { Province opProvince = ocCountry.provinces[op]; if (opProvince == provinces[provinceIndex]) { continue; } if (opProvince.regions == null) { ReadProvincePackedString(opProvince); } if (opProvince.regions == null) { continue; } if (opProvince.regionsRect2D.Overlaps(region.rect2D, true)) { Region oProvRegion = opProvince.regions[opProvince.mainRegionIndex]; if (region.Contains(oProvRegion)) // just check main region of province for speed purposes { negativeRegions.Add(oProvRegion.Clone()); } } } } // Collapse negative regions in big holes for (int nr = 0; nr < negativeRegions.Count - 1; nr++) { for (int nr2 = nr + 1; nr2 < negativeRegions.Count; nr2++) { if (negativeRegions[nr].Intersects(negativeRegions[nr2])) { Clipper clipper = new Clipper(); int control = negativeRegions[nr].points.Length; clipper.AddPath(negativeRegions[nr], PolyType.ptSubject); clipper.AddPath(negativeRegions[nr2], PolyType.ptClip); clipper.Execute(ClipType.ctUnion); negativeRegions.RemoveAt(nr2); nr = -1; break; } } } // Substract holes int negativeRegionsCount = negativeRegions.Count; for (int r = 0; r < negativeRegionsCount; r++) { int pointCount = negativeRegions[r].points.Length; Vector2[] pp = new Vector2[pointCount]; for (int p = 0; p < pointCount; p++) { Vector2 point = negativeRegions[r].points[p]; Vector2 midPoint = negativeRegions[r].center; pp[p] = point + (midPoint - point) * 0.0001f; // prevents Poly2Tri issues when enclave boarders are to near from region borders } Poly2Tri.Polygon polyHole = new Poly2Tri.Polygon(pp); poly.AddHole(polyHole); } }
/// <summary> /// Highlights the province region specified. Returns the generated highlight surface gameObject. /// Internally used by the Map UI and the Editor component, but you can use it as well to temporarily mark a country region. /// </summary> /// <param name="refreshGeometry">Pass true only if you're sure you want to force refresh the geometry of the highlight (for instance, if the frontiers data has changed). If you're unsure, pass false.</param> public GameObject HighlightProvinceRegion(int provinceIndex, int regionIndex, bool refreshGeometry) { if (!refreshGeometry && _provinceHighlightedIndex == provinceIndex && _provinceRegionHighlightedIndex == regionIndex) { return(provinceRegionHighlightedObj); } if (provinceRegionHighlightedObj != null) { HideProvinceRegionHighlight(); } if (provinceIndex < 0 || provinceIndex >= provinces.Length || provinces[provinceIndex].regions == null || regionIndex < 0 || regionIndex >= provinces[provinceIndex].regions.Count) { return(null); } if (OnProvinceHighlight != null) { bool allowHighlight = true; OnProvinceHighlight(provinceIndex, regionIndex, ref allowHighlight); if (!allowHighlight) { return(null); } } int cacheIndex = GetCacheIndexForProvinceRegion(provinceIndex, regionIndex); GameObject obj; bool existsInCache = surfaces.TryGetValue(cacheIndex, out obj); if (refreshGeometry && existsInCache) { surfaces.Remove(cacheIndex); DestroyImmediate(obj); existsInCache = false; } bool doHighlight = true; if (_highlightMaxScreenAreaSize < 1f) { // Check screen area size Region region = provinces[provinceIndex].regions[regionIndex]; doHighlight = CheckScreenAreaSizeOfRegion(region); } if (doHighlight) { if (_enableProvinceHighlight && _provinces[provinceIndex].allowHighlight && _countries[_provinces[provinceIndex].countryIndex].allowProvincesHighlight) { if (existsInCache) { provinceRegionHighlightedObj = surfaces[cacheIndex]; if (provinceRegionHighlightedObj == null) { surfaces.Remove(cacheIndex); } else { if (!provinceRegionHighlightedObj.activeSelf) { provinceRegionHighlightedObj.SetActive(true); } Renderer[] rr = provinceRegionHighlightedObj.GetComponentsInChildren <Renderer>(true); for (int k = 0; k < rr.Length; k++) { if (rr[k].sharedMaterial != hudMatProvince && rr[k].sharedMaterial != outlineMatSimple) { rr[k].enabled = true; rr[k].sharedMaterial = hudMatProvince; } } } } else { provinceRegionHighlightedObj = GenerateProvinceRegionSurface(provinceIndex, regionIndex, hudMatProvince); // Add rest of regions? if (_highlightAllProvinceRegions) { Province province = provinces[provinceIndex]; for (int r = 0; r < province.regions.Count; r++) { if (r != regionIndex) { Region otherRegion = province.regions[r]; // Triangulate to get the polygon vertex indices Poly2Tri.Polygon poly = new Poly2Tri.Polygon(otherRegion.points); P2T.Triangulate(poly); GameObject otherSurf = Drawing.CreateSurface(provinceRegionHighlightedObj.name, poly, hudMatProvince, otherRegion.rect2D, Misc.Vector2zero, Misc.Vector2zero, 0, disposalManager); otherSurf.transform.SetParent(provinceRegionHighlightedObj.transform, false); otherSurf.transform.localPosition = Misc.Vector3zero; otherSurf.transform.localRotation = Quaternion.Euler(Misc.Vector3zero); otherSurf.layer = gameObject.layer; } } } } } else { provinceRegionHighlightedObj = null; } } _provinceHighlighted = provinces[provinceIndex]; _provinceHighlightedIndex = provinceIndex; _provinceRegionHighlighted = _provinceHighlighted.regions[regionIndex]; _provinceRegionHighlightedIndex = regionIndex; return(provinceRegionHighlightedObj); }
bool DrawProvinces(List <Country> targetCountries, bool justComputeBorders) { // optimize required lines if (frontiersCacheHit == null) { frontiersCacheHit = new Dictionary <double, Region>(500000); } else { frontiersCacheHit.Clear(); } int tcCount = targetCountries.Count; if (justComputeBorders) { provinceNeighboursComputed = true; // Compute borders but ignore mesh building for (int c = 0; c < tcCount; c++) { Country targetCountry = targetCountries[c]; if (targetCountry.provinces == null || targetCountry.hidden || !targetCountry.showProvinces) { continue; } for (int p = 0; p < targetCountry.provinces.Length; p++) { Province province = targetCountry.provinces[p]; if (province.regions == null) // read province data the first time we need it { ReadProvincePackedString(province); } int prCount = province.regions.Count; for (int r = 0; r < prCount; r++) { Region region = province.regions[r]; region.entity = province; region.regionIndex = r; region.neighbours.Clear(); int numPoints = region.points.Length - 1; for (int i = 0; i < numPoints; i++) { Vector2 p0 = region.points[i]; Vector2 p1 = region.points[i + 1]; double v = (p0.x + p1.x) + MAP_PRECISION * (p0.y + p1.y); Region neighbour; if (frontiersCacheHit.TryGetValue(v, out neighbour)) { if (neighbour != region) { if (!region.neighbours.Contains(neighbour)) { region.neighbours.Add(neighbour); neighbour.neighbours.Add(region); } } } else { frontiersCacheHit[v] = region; } } } } } return(true); // ignore mesh building } if (_showTiles && _currentZoomLevel > _tileLinesMaxZoomLevel) { return(false); } if (frontiersPoints == null) { frontiersPoints = new List <Vector2>(1000000); } else { frontiersPoints.Clear(); } TestNeighbourSegment testFunction; if (_provincesCoastlines) { testFunction = TestProvinceNeighbourSegmentAny; } else { testFunction = TestProvinceNeighbourSegmentInland; } for (int c = 0; c < tcCount; c++) { Country targetCountry = targetCountries[c]; if (targetCountry.provinces == null || targetCountry.hidden || !targetCountry.showProvinces) { continue; } for (int p = 0; p < targetCountry.provinces.Length; p++) { Province province = targetCountry.provinces[p]; if (province.regions == null) // read province data the first time we need it { ReadProvincePackedString(province); } int prCount = province.regions.Count; for (int r = 0; r < prCount; r++) { Region region = province.regions[r]; region.entity = province; region.regionIndex = r; region.neighbours.Clear(); int numPoints = region.points.Length - 1; for (int i = 0; i < numPoints; i++) { testFunction(region, i, i + 1); } // Close the polygon testFunction(region, numPoints, 0); } } } int meshGroups = (frontiersPoints.Count / 65000) + 1; int meshIndex = -1; int[][] provincesIndices = new int[meshGroups][]; Vector3[][] provincesBorders = new Vector3[meshGroups][]; int fpCount = frontiersPoints.Count; for (int k = 0; k < fpCount; k += 65000) { int max = Mathf.Min(fpCount - k, 65000); provincesBorders[++meshIndex] = new Vector3[max]; provincesIndices[meshIndex] = new int[max]; for (int j = k; j < k + max; j++) { provincesBorders[meshIndex][j - k].x = frontiersPoints[j].x; provincesBorders[meshIndex][j - k].y = frontiersPoints[j].y; provincesIndices[meshIndex][j - k] = j - k; } } // Create province layer if needed if (provincesObj != null) { DestroyRecursive(provincesObj); } if (provincesBorders.Length > 0) { provincesObj = new GameObject("Provinces"); if (disposalManager != null) { disposalManager.MarkForDisposal(provincesObj); //provincesObj.hideFlags = HideFlags.DontSave; } provincesObj.transform.SetParent(transform, false); provincesObj.transform.localPosition = Misc.Vector3back * 0.002f; provincesObj.layer = gameObject.layer; for (int k = 0; k < provincesBorders.Length; k++) { GameObject flayer = new GameObject("flayer"); if (disposalManager != null) { disposalManager.MarkForDisposal(flayer); // flayer.hideFlags = HideFlags.DontSave; } flayer.hideFlags |= HideFlags.HideInHierarchy; flayer.transform.SetParent(provincesObj.transform, false); flayer.transform.localPosition = Misc.Vector3zero; flayer.transform.localRotation = Quaternion.Euler(Misc.Vector3zero); flayer.layer = provincesObj.layer; Mesh mesh = new Mesh(); mesh.vertices = provincesBorders[k]; mesh.SetIndices(provincesIndices[k], MeshTopology.Lines, 0); mesh.RecalculateBounds(); if (disposalManager != null) { disposalManager.MarkForDisposal(mesh); // mesh.hideFlags = HideFlags.DontSave; } MeshFilter mf = flayer.AddComponent <MeshFilter>(); mf.sharedMesh = mesh; MeshRenderer mr = flayer.AddComponent <MeshRenderer>(); mr.receiveShadows = false; mr.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; mr.sharedMaterial = provincesMat; } } return(true); }
/// <summary> /// Unpacks province geodata information. Used by Map Editor. /// </summary> /// <param name="province">Province.</param> public void ReadProvincePackedString(IAdminEntity entity) { Province province = (Province)entity; if (province == null || province.packedRegions == null) { return; } string[] regions = province.packedRegions.Split(SPLIT_SEP_ASTERISK, StringSplitOptions.RemoveEmptyEntries); int regionCount = regions.Length; province.regions = new List <Region>(regionCount); float maxVol = float.MinValue; Vector2 minProvince = Misc.Vector2one * 10; Vector2 maxProvince = -minProvince; for (int r = 0; r < regionCount; r++) { string[] coordinates = regions[r].Split(SPLIT_SEP_SEMICOLON, StringSplitOptions.RemoveEmptyEntries); int coorCount = coordinates.Length; Vector2 min = Misc.Vector2one * 10; Vector2 max = -min; Region provinceRegion = new Region(province, province.regions.Count); provinceRegion.points = new Vector2[coorCount]; for (int c = 0; c < coorCount; c++) { float x, y; GetPointFromPackedString(ref coordinates[c], out x, out y); if (x < min.x) { min.x = x; } if (x > max.x) { max.x = x; } if (y < min.y) { min.y = y; } if (y > max.y) { max.y = y; } provinceRegion.points[c].x = x; provinceRegion.points[c].y = y; } FastVector.Average(ref min, ref max, ref provinceRegion.center); provinceRegion.sanitized = true; province.regions.Add(provinceRegion); // Calculate province bounding rect if (min.x < minProvince.x) { minProvince.x = min.x; } if (min.y < minProvince.y) { minProvince.y = min.y; } if (max.x > maxProvince.x) { maxProvince.x = max.x; } if (max.y > maxProvince.y) { maxProvince.y = max.y; } provinceRegion.rect2D = new Rect(min.x, min.y, max.x - min.x, max.y - min.y); provinceRegion.rect2DArea = provinceRegion.rect2D.width * provinceRegion.rect2D.height; float vol = FastVector.SqrDistance(ref min, ref max); // (max - min).sqrMagnitude; if (vol > maxVol) { maxVol = vol; province.mainRegionIndex = r; province.center = provinceRegion.center; } } province.regionsRect2D = new Rect(minProvince.x, minProvince.y, Math.Abs(maxProvince.x - minProvince.x), Mathf.Abs(maxProvince.y - minProvince.y)); }
/// <summary> /// Removes a province /// </summary> /// <param name="provinceIndex">Province index.</param> public bool ProvinceDelete(int provinceIndex) { if (provinceIndex < 0 || provinceIndex >= provinces.Length) { return(false); } // Clears references from mount points if (mountPoints != null) { int mountPointsCount = mountPoints.Count; for (int k = 0; k < mountPointsCount; k++) { if (mountPoints[k].provinceIndex == provinceIndex) { mountPoints[k].provinceIndex = -1; } } } List <Province> newProvinces = new List <Province>(_provinces.Length); // Clears references from cities int countryIndex = _provinces[provinceIndex].countryIndex; if (countryIndex >= 0 && countryIndex < _countries.Length) { string provinceName = _provinces[provinceIndex].name; if (cities != null) { int citiesCount = _cities.Length; for (int k = 0; k < citiesCount; k++) { if (_cities[k].countryIndex == countryIndex && _cities[k].province.Equals(provinceName)) { _cities[k].province = ""; } } } // Remove it from the country array Country country = _countries[countryIndex]; if (country.provinces != null) { for (int k = 0; k < country.provinces.Length; k++) { Province prov = country.provinces[k]; if (prov.regions.Count > 0 && !prov.name.Equals(provinceName)) { newProvinces.Add(country.provinces[k]); } } newProvinces.Sort(ProvinceSizeComparer); country.provinces = newProvinces.ToArray(); } } // Remove from the global array newProvinces.Clear(); for (int k = 0; k < _provinces.Length; k++) { if (k != provinceIndex) { newProvinces.Add(_provinces[k]); } } provinces = newProvinces.ToArray(); return(true); }
/// <summary> /// Generate and replace provinces, city and country data /// </summary> public void GenerateMap() { try { UnityEngine.Random.InitState(seed); GenerateHeightMap(); CreateMapProvinces(); AssignHeightMapToProvinces(true); CreateMapCountries(); CreateMapCities(); UnityEngine.Random.InitState(seedNames); // Replace countries int mapCountriesCount = mapCountries.Count; List <Country> newCountries = new List <Country> (mapCountriesCount); for (int k = 0; k < mapCountriesCount; k++) { MapCountry c = mapCountries [k]; Vector2[] points = c.region.points; if (points == null || points.Length < 3) { continue; } string name = GetUniqueRandomName(0, 4, usedNames); Country newCountry = new Country(name, "World", k); Region region = new Region(newCountry, newCountry.regions.Count); newCountry.regions.Add(region); region.UpdatePointsAndRect(points); map.RefreshCountryGeometry(newCountry); newCountries.Add(newCountry); } map.countries = newCountries.ToArray(); countryChanges = true; // Replace provinces usedNames.Clear(); int mapProvincesCount = mapProvinces.Count; List <Province> newProvinces = new List <Province> (mapProvincesCount); Province[] provinces = _map.provinces; if (provinces == null) { provinces = new Province[0]; } for (int k = 0; k < mapProvincesCount; k++) { MapProvince c = mapProvinces [k]; if (!c.visible) { continue; } Vector2[] points = c.region.points; if (points == null || points.Length < 3) { continue; } int countryIndex = map.GetCountryIndex(c.center); if (countryIndex < 0) { continue; } string name = GetUniqueRandomName(0, 4, usedNames); Province newProvince = new Province(name, countryIndex, k); newProvince.regions = new List <Region> (); Region region = new Region(newProvince, newProvince.regions.Count); newProvince.attrib ["mapColor"] = c.color; newProvince.regions.Add(region); region.UpdatePointsAndRect(points); map.RefreshProvinceGeometry(newProvince); newProvinces.Add(newProvince); Country country = map.countries [countryIndex]; List <Province> countryProvinces = country.provinces != null ? new List <Province> (country.provinces) : new List <Province> (); countryProvinces.Add(newProvince); country.provinces = countryProvinces.ToArray(); } map.provinces = newProvinces.ToArray(); provinceChanges = true; // Replace cities usedNames.Clear(); int mapCitiesCount = mapCities.Count; List <City> newCities = new List <City> (mapCitiesCount); string provinceName = ""; for (int k = 0; k < mapCitiesCount; k++) { MapCity c = mapCities [k]; City newCity; Province prov = map.GetProvince(c.unity2DLocation); if (prov == null) { continue; } provinceName = prov != null ? prov.name : ""; string name = GetUniqueRandomName(0, 4, usedNames); newCity = new City(name, provinceName, prov.countryIndex, c.population, c.unity2DLocation, c.cityClass, k); newCities.Add(newCity); } map.cities = newCities; cityChanges = true; // Generate textures GenerateWorldTexture(); // Apply some complementary style if (changeStyle && heightGradientPreset != HeightMapGradientPreset.Custom) { map.frontiersColor = Color.black; map.frontiersColorOuter = Color.black; map.provincesColor = Color.gray; map.countryLabelsColor = Color.white; map.countryLabelsShadowColor = new Color(0.1f, 0.1f, 0.1f, 0.25f); } if (_map.earthStyle.isScenicPlus()) { _map.earthStyle = EARTH_STYLE.Natural; } // Save map data SaveGeneratedMapData(); map.showFrontiers = true; map.showCountryNames = true; map.waterLevel = seaLevel; map.Redraw(true); } catch (Exception ex) { #if UNITY_EDITOR if (!Application.isPlaying) { Debug.LogError("Error generating map: " + ex.ToString()); EditorUtility.DisplayDialog("Error Generating Map", "An error occured while generating map. Try choosing another 'Seed' value, reducing 'Border Curvature' amount or number of provinces.", "Ok"); } #endif } }
/// <summary> /// Creates a new province with the given region /// </summary> public void ProvinceCreate(Region region) { if (region == null) { return; } // Remove region from source entity IAdminEntity entity = region.entity; if (entity != null) { entity.regions.Remove(region); Country country; // Refresh entity definition if (region.entity is Country) { int countryIndex = _map.GetCountryIndex((Country)region.entity); country = _map.countries [countryIndex]; _map.RefreshCountryGeometry(country); } else { int provinceIndex = map.GetProvinceIndex((Province)region.entity); country = _map.countries [_map.provinces [provinceIndex].countryIndex]; _map.RefreshProvinceGeometry(provinceIndex); } } provinceIndex = map.provinces.Length; provinceRegionIndex = 0; string newProvinceName = GetProvinceUniqueName("New Province"); Province newProvince = new Province(newProvinceName, countryIndex, map.GetUniqueId(new List <IExtendableAttribute> (map.provinces))); Region newRegion = new Region(newProvince, 0); newRegion.UpdatePointsAndRect(region.points); newProvince.regions = new List <Region> (); newProvince.regions.Add(newRegion); map.ProvinceAdd(newProvince); map.RefreshProvinceDefinition(provinceIndex, false); // Update cities List <City> cities = _map.GetCities(region); int citiesCount = cities.Count; if (citiesCount > 0) { for (int k = 0; k < citiesCount; k++) { if (cities [k].province != newProvinceName) { cities [k].province = newProvinceName; cityChanges = true; } } } lastProvinceCount = -1; GUIProvinceName = newProvince.name; SyncGUIProvinceSelection(); ProvinceRegionSelect(); provinceChanges = true; }
/// <summary> /// Draws the province labels for a given country. Note that it will update cached textmesh objects if labels are already drawn. Used internally. /// </summary> void DrawProvinceLabelsInt(Country country) { if (!Application.isPlaying || !_showProvinceNames || !gameObject.activeInHierarchy || country == null || country.hidden || provinces == null || country.provinces == null) { return; } countryProvincesLabelsShown = country; // Set colors provLabelsFont.material.color = _provinceLabelsColor; provLabelsShadowMaterial.color = _provinceLabelsShadowColor; // Create texts GameObject overlay = GetOverlayLayer(true); Transform t = overlay.transform.Find(OVERLAY_TEXT_PROVINCE_ROOT); if (t == null) { textProvinceRoot = new GameObject(OVERLAY_TEXT_PROVINCE_ROOT); if (disposalManager != null) { disposalManager.MarkForDisposal(textProvinceRoot); // textProvinceRoot.hideFlags = HideFlags.DontSave; } textProvinceRoot.layer = overlay.layer; } else { textProvinceRoot = t.gameObject; } if (meshRects == null) { meshRects = new List <MeshRect> (country.provinces.Length); } else { meshRects.Clear(); } float mw = mapWidth; float mh = mapHeight; for (int p = 0; p < country.provinces.Length; p++) { Province province = country.provinces[p]; if (province.regions == null) { ReadProvincePackedString(province); } if (province == null || province.hidden || !province.labelVisible || province.regions == null || province.mainRegionIndex < 0 || province.mainRegionIndex >= province.regions.Count) { continue; } if (_provinceLabelsVisibility == PROVINCE_LABELS_VISIBILITY.Automatic && !_showAllCountryProvinceNames && province != _provinceHighlighted) { continue; } Vector2 center = new Vector2(province.center.x * mapWidth, province.center.y * mh) + province.labelOffset; Region region = province.regions[province.mainRegionIndex]; // Adjusts province name length string provinceName = province.customLabel != null ? province.customLabel : province.name.ToUpper(); bool introducedCarriageReturn = false; if (provinceName.Length > 15) { int spaceIndex = provinceName.IndexOf(' ', provinceName.Length / 2); if (spaceIndex >= 0) { provinceName = provinceName.Substring(0, spaceIndex) + "\n" + provinceName.Substring(spaceIndex + 1); introducedCarriageReturn = true; } } // add caption GameObject textObj; TextMesh tm; Renderer tmRenderer; TextMesh tmShadow = null; if (province.labelTextMeshGO == null) { Color labelColor = province.labelColorOverride ? province.labelColor : _provinceLabelsColor; Font customFont = province.labelFontOverride ?? provLabelsFont; Material customLabelShadowMaterial = province.labelFontShadowMaterial ?? provLabelsShadowMaterial; tm = Drawing.CreateText(provinceName, null, center, customFont, labelColor, _showProvinceLabelsShadow, customLabelShadowMaterial, _provinceLabelsShadowColor, out tmShadow); textObj = tm.gameObject; province.labelTextMesh = tm; province.labelTextMeshGO = tm.gameObject; tmRenderer = textObj.GetComponent <Renderer>(); Bounds bounds = tmRenderer.bounds; province.labelMeshWidth = bounds.size.x; province.labelMeshHeight = bounds.size.y; province.labelMeshCenter = center; textObj.transform.SetParent(textProvinceRoot.transform, false); textObj.transform.localPosition = center; textObj.layer = textProvinceRoot.gameObject.layer; if (_showProvinceLabelsShadow) { province.labelShadowTextMesh = tmShadow; province.labelShadowTextMesh.gameObject.layer = textObj.layer; } } else { tm = province.labelTextMesh; textObj = tm.gameObject; textObj.transform.localPosition = center; tmRenderer = textObj.GetComponent <Renderer>(); } float meshWidth = province.labelMeshWidth; float meshHeight = province.labelMeshHeight; // adjusts caption Rect rect = new Rect(region.rect2D.xMin * mw, region.rect2D.yMin * mh, region.rect2D.width * mw, region.rect2D.height * mh); float absoluteHeight; if (province.labelRotation > 0) { textObj.transform.localRotation = Quaternion.Euler(0, 0, province.labelRotation); absoluteHeight = Mathf.Min(rect.height * _provinceLabelsSize, rect.width); } else if (rect.height > rect.width * 1.45f) { float angle; if (rect.height > rect.width * 1.5f) { angle = 90; } else { angle = Mathf.Atan2(rect.height, rect.width) * Mathf.Rad2Deg; } textObj.transform.localRotation = Quaternion.Euler(0, 0, angle); absoluteHeight = Mathf.Min(rect.width * _provinceLabelsSize, rect.height); } else { absoluteHeight = Mathf.Min(rect.height * _provinceLabelsSize, rect.width); } // adjusts scale to fit width in rect float adjustedMeshHeight = introducedCarriageReturn ? meshHeight * 0.5f : meshHeight; float scale = absoluteHeight / adjustedMeshHeight; if (province.labelFontSizeOverride) { scale = province.labelFontSize; } else { float desiredWidth = meshWidth * scale; if (desiredWidth > rect.width) { scale = rect.width / meshWidth; } if (adjustedMeshHeight * scale < _provinceLabelsAbsoluteMinimumSize) { scale = _provinceLabelsAbsoluteMinimumSize / adjustedMeshHeight; } } // stretchs out the caption float displayedMeshWidth = meshWidth * scale; float displayedMeshHeight = meshHeight * scale; string wideName; int times = Mathf.FloorToInt(rect.width * 0.45f / (meshWidth * scale)); if (times > 10) { times = 10; } if (times > 0) { StringBuilder sb = new StringBuilder(); string spaces = new string(' ', times * 2); for (int c = 0; c < provinceName.Length; c++) { sb.Append(provinceName[c]); if (c < provinceName.Length - 1) { sb.Append(spaces); } } wideName = sb.ToString(); } else { wideName = provinceName; } if (tm.text.Length != wideName.Length) { tm.text = wideName; displayedMeshWidth = tmRenderer.bounds.size.x * scale; displayedMeshHeight = tmRenderer.bounds.size.y * scale; if (_showProvinceLabelsShadow) { tmShadow.text = wideName; } } // apply scale textObj.transform.localScale = new Vector3(scale, scale, 1); // Save mesh rect for overlapping checking if (province.labelOffset == Misc.Vector2zero) { int provinceIndex = GetProvinceIndex(province); float xMin = center.x - displayedMeshWidth * 0.5f; float yMin = center.y - displayedMeshHeight * 0.5f; float xMax = xMin + displayedMeshWidth; float yMax = yMin + displayedMeshHeight; MeshRect mr = new MeshRect(provinceIndex, new Vector4(xMin, yMin, xMax, yMax)); // MeshRect mr = new MeshRect(provinceIndex, new Rect(center.x - displayedMeshWidth * 0.5f, center.y - displayedMeshHeight * 0.5f, displayedMeshWidth, displayedMeshHeight)); meshRects.Add(mr); } } // Simple-fast overlapping checking int cont = 0; bool needsResort = true; int meshRectsCount = meshRects.Count; while (needsResort && ++cont < 10) { meshRects.Sort(overlapComparer); for (int c = 1; c < meshRectsCount; c++) { Vector4 r1 = meshRects[c].rect; for (int prevc = c - 1; prevc >= 0; prevc--) { Vector4 r2 = meshRects[prevc].rect; bool overlaps = !(r2.x > r1.z || r2.z <r1.x || r2.y> r1.w || r2.w < r1.y); if (overlaps) { needsResort = true; int thisProvinceIndex = meshRects[c].entityIndex; Province province = _provinces[thisProvinceIndex]; GameObject thisLabel = province.labelTextMeshGO; // displaces this label float offsety = r1.w - r2.y; offsety = Mathf.Min(province.regions[province.mainRegionIndex].rect2D.height * mh * 0.35f, offsety); thisLabel.transform.localPosition = new Vector3(province.labelMeshCenter.x, province.labelMeshCenter.y - offsety, thisLabel.transform.localPosition.z); // r1 = new Rect(thisLabel.transform.localPosition.x - r1.width * 0.5f, // thisLabel.transform.localPosition.y - r1.height * 0.5f, // r1.width, r1.height); // meshRects[c].rect = r1; float width = r1.z - r1.x; float height = r1.w - r1.y; float xMin = thisLabel.transform.localPosition.x - width * 0.5f; float yMin = thisLabel.transform.localPosition.y - height * 0.5f; float xMax = xMin + width; float yMax = yMin + height; r1 = new Vector4(xMin, yMin, xMax, yMax); meshRects [c].rect = r1; } } } } // Adjusts parent textProvinceRoot.transform.SetParent(overlay.transform, false); textProvinceRoot.transform.localPosition = new Vector3(0, 0, -0.001f); textProvinceRoot.transform.localRotation = Misc.QuaternionZero; textProvinceRoot.transform.localScale = new Vector3(1.0f / mw, 1.0f / mh, 1); // Adjusts alpha based on distance to camera if (Application.isPlaying) { FadeProvinceLabels(); } }
void FadeProvinceLabels() { if (countryProvincesLabelsShown == null || countryProvincesLabelsShown.provinces == null) { return; } // Automatically fades in/out province labels based on their screen size float y0 = _currentCamera.WorldToViewportPoint(transform.TransformPoint(0, 0, 0)).y; float y1 = _currentCamera.WorldToViewportPoint(transform.TransformPoint(0, 1.0f, 0)).y; float th = y1 - y0; float maxAlpha = _provinceLabelsColor.a; float maxAlphaShadow = _provinceLabelsShadowColor.a; float labelFadeMinSize = 0.018f; float labelFadeMaxSize = 0.2f; float labelFadeMinFallOff = 0.005f; float labelFadeMaxFallOff = 0.5f; float mh = mapHeight; for (int k = 0; k < countryProvincesLabelsShown.provinces.Length; k++) { Province province = countryProvincesLabelsShown.provinces[k]; TextMesh tm = province.labelTextMesh; if (tm != null) { // Fade label float labelSize = (province.labelMeshHeight + province.labelMeshWidth) * 0.5f; float screenHeight = labelSize * tm.transform.localScale.y * th / mh; float ad; if (screenHeight < labelFadeMinSize) { ad = Mathf.Lerp(1.0f, 0, (labelFadeMinSize - screenHeight) / labelFadeMinFallOff); } else if (screenHeight > labelFadeMaxSize) { ad = Mathf.Lerp(1.0f, 0, (screenHeight - labelFadeMaxSize) / labelFadeMaxFallOff); } else { ad = 1.0f; } float newAlpha = ad * maxAlpha; if (tm.color.a != newAlpha) { tm.color = new Color(tm.color.r, tm.color.g, tm.color.b, newAlpha); } // Fade label shadow TextMesh tmShadow = province.labelShadowTextMesh; if (tmShadow != null) { newAlpha = ad * maxAlphaShadow; if (tmShadow.color.a != newAlpha) { tmShadow.color = new Color(tmShadow.color.r, tmShadow.color.g, tmShadow.color.b, maxAlphaShadow * ad); } } } } }
/// <summary> /// Creates a new country based on a given region. Existing region is removed from its source entity. /// </summary> /// <param name="region">Region.</param> public void CountryCreate(Region region) { // Remove region from source entity IAdminEntity entity = region.entity; entity.regions.Remove(region); Country country; // Refresh entity definition if (region.entity is Country) { int countryIndex = _map.GetCountryIndex((Country)region.entity); country = _map.countries[countryIndex]; _map.RefreshCountryGeometry(country); } else { int provinceIndex = map.GetProvinceIndex((Province)region.entity); country = _map.countries[_map.provinces[provinceIndex].countryIndex]; _map.RefreshProvinceGeometry(provinceIndex); } // Create the new country string uniqueName = GetCountryUniqueName(country.name); Country newCountry = new Country(uniqueName, country.continent, map.GetUniqueId(new List <IExtendableAttribute>(map.countries))); if (entity is Country) { newCountry.regions.Add(region); } else { Region newRegion = new Region(newCountry, 0); newRegion.UpdatePointsAndRect(region.points); newCountry.regions.Add(newRegion); } countryIndex = map.CountryAdd(newCountry); countryRegionIndex = 0; lastCountryCount = -1; GUICountryName = ""; ReloadCountryNames(); countryChanges = true; // Update cities List <City> cities = _map.GetCities(region); if (cities.Count > 0) { for (int k = 0; k < cities.Count; k++) { if (cities [k].countryIndex != countryIndex) { cities [k].countryIndex = countryIndex; cityChanges = true; } } } // Update mount points List <MountPoint> mp = _map.GetMountPoints(region); if (mp.Count > 0) { for (int k = 0; k < mp.Count; k++) { if (mp [k].countryIndex != countryIndex) { mp [k].countryIndex = countryIndex; mountPointChanges = true; } } } // Transfer any contained province if (entity is Country) { List <Province> provinces = _map.GetProvinces(region); for (int k = 0; k < provinces.Count; k++) { Province prov = provinces[k]; if (prov.regions == null) { _map.ReadProvincePackedString(prov); } if (prov.regions == null) { continue; } if (_map.CountryTransferProvinceRegion(countryIndex, prov.mainRegion, false)) { provinceChanges = true; } } } map.Redraw(); CountryRegionSelect(); }
/// <summary> /// Exports the geographic data in packed string format with reduced quality. /// </summary> public string GetCountryGeoDataLowQuality() { // step 1: duplicate data IAdminEntity[] entities; if (editingMode == EDITING_MODE.COUNTRIES) { entities = map.countries; } else { entities = map.provinces; } List <IAdminEntity> entities1 = new List <IAdminEntity>(entities); for (int k = 0; k < entities1.Count; k++) { entities1[k].regions = new List <Region>(entities1[k].regions); for (int r = 0; r < entities[k].regions.Count; r++) { entities1[k].regions[r].points = new List <Vector2>(entities1[k].regions[r].points).ToArray(); } } // step 2: ensure near points between neighbours float MAX_DIST = 0.00000001f; // int join = 0; for (int k = 0; k < entities1.Count; k++) { for (int r = 0; r < entities1[k].regions.Count; r++) { Region region1 = entities1[k].regions[r]; for (int p = 0; p < entities1[k].regions[r].points.Length; p++) { // Search near points for (int k2 = 0; k2 < region1.neighbours.Count; k2++) { for (int r2 = 0; r2 < entities1[k2].regions.Count; r2++) { Region region2 = entities1[k2].regions[r2]; for (int p2 = 0; p2 < entities1[k2].regions[r2].points.Length; p2++) { float dist = (region1.points[p].x - region2.points[p2].x) * (region1.points[p].x - region2.points[p2].x) + (region1.points[p].y - region2.points[p2].y) * (region1.points[p].y - region2.points[p2].y); if (dist < MAX_DIST) { region2.points[p2] = region1.points[p]; // join++; } } } } } } } // step 2: simplify Dictionary <Vector2, bool> frontiersHit = new Dictionary <Vector2, bool>(); List <IAdminEntity> entities2 = new List <IAdminEntity>(entities1.Count); int savings = 0, totalPoints = 0; float FACTOR = 1000f; for (int k = 0; k < entities1.Count; k++) { IAdminEntity refEntity = entities1[k]; IAdminEntity newEntity; if (refEntity is Country) { newEntity = new Country(refEntity.name, ((Country)refEntity).continent, map.GetUniqueId(new List <IExtendableAttribute>(map.countries))); } else { newEntity = new Province(refEntity.name, ((Province)refEntity).countryIndex, map.GetUniqueId(new List <IExtendableAttribute>(map.provinces))); } for (int r = 0; r < refEntity.regions.Count; r++) { Region region = refEntity.regions[r]; int numPoints = region.points.Length; totalPoints += numPoints; List <Vector2> points = new List <Vector2>(numPoints); frontiersHit.Clear(); Vector3[] blockyPoints = new Vector3[numPoints]; for (int p = 0; p < numPoints; p++) { blockyPoints[p] = new Vector2(Mathf.RoundToInt(region.points[p].x * FACTOR) / FACTOR, Mathf.RoundToInt(region.points[p].y * FACTOR) / FACTOR); } points.Add(region.points[0] * WMSK.MAP_PRECISION); for (int p = 1; p < numPoints - 1; p++) { if (blockyPoints[p - 1].y == blockyPoints[p].y && blockyPoints[p].y == blockyPoints[p + 1].y || blockyPoints[p - 1].x == blockyPoints[p].x && blockyPoints[p].x == blockyPoints[p + 1].x) { savings++; continue; } if (!frontiersHit.ContainsKey(blockyPoints[p])) // add neighbour references { frontiersHit.Add(blockyPoints[p], true); points.Add(region.points[p] * WMSK.MAP_PRECISION); } else { savings++; } } points.Add(region.points[numPoints - 1] * WMSK.MAP_PRECISION); if (points.Count >= 5) { Region newRegion = new Region(newEntity, newEntity.regions.Count); newRegion.points = points.ToArray(); newEntity.regions.Add(newRegion); } } if (newEntity.regions.Count > 0) { entities2.Add(newEntity); } } Debug.Log(savings + " points removed of " + totalPoints + " (" + (((float)savings / totalPoints) * 100.0f).ToString("F1") + "%)"); StringBuilder sb = new StringBuilder(); for (int k = 0; k < entities2.Count; k++) { IAdminEntity entity = entities2[k]; if (k > 0) { sb.Append("|"); } sb.Append(entity.name + "$"); if (entity is Country) { sb.Append(((Country)entity).continent + "$"); } else { sb.Append(map.countries[((Province)entity).countryIndex].name + "$"); } for (int r = 0; r < entity.regions.Count; r++) { if (r > 0) { sb.Append("*"); } Region region = entity.regions[r]; for (int p = 0; p < region.points.Length; p++) { if (p > 0) { sb.Append(";"); } Vector2 point = region.points[p]; sb.Append(point.x.ToString() + ","); sb.Append(point.y.ToString()); } } } return(sb.ToString()); }
/// <summary> /// Merges all provinces in each country so their number fits a given range /// </summary> /// <param name="min">Minimum number of provinces.</param> /// <param name="max">Maximum number of provinces.</param> public void ProvincesEqualize(int min, int max, int countryIndex) { if (min < 1 || countryIndex < 0 || countryIndex >= map.countries.Length) { return; } if (max < min) { max = min; } map.showProvinces = true; map.drawAllProvinces = true; Country country = map.countries [countryIndex]; if (country == null || country.provinces == null) { return; } int targetProvCount = UnityEngine.Random.Range(min, max); int provCount = country.provinces.Length; float provStartSize = 0; while (provCount > targetProvCount) { // Take the smaller province and merges with a neighbour float minAreaSize = float.MaxValue; int provinceIndex = -1; for (int p = 0; p < provCount; p++) { Province prov = country.provinces [p]; if (prov == null) { continue; } if (prov.regions == null) { map.ReadProvincePackedString(prov); } if (prov.regions == null || prov.regions.Count == 0 || prov.mainRegion.neighbours == null || prov.mainRegion.neighbours.Count == 0) { continue; } if (prov.regionsRect2DArea < minAreaSize && prov.regionsRect2DArea > provStartSize) { minAreaSize = prov.regionsRect2DArea; provinceIndex = map.GetProvinceIndex(prov); } } if (provinceIndex < 0) { break; } provStartSize = minAreaSize; // Get the smaller neighbour int neighbourIndex = -1; Province province = map.provinces [provinceIndex]; int neighbourCount = province.mainRegion.neighbours.Count; minAreaSize = float.MaxValue; for (int n = 0; n < neighbourCount; n++) { Region neighbour = province.mainRegion.neighbours [n]; Province neighbourProvince = (Province)neighbour.entity; if (neighbourProvince != null && neighbourProvince != province && neighbourProvince.countryIndex == countryIndex && neighbour.rect2DArea < minAreaSize) { int neighbourProvIndex = map.GetProvinceIndex(neighbourProvince); if (neighbourProvIndex >= 0) { minAreaSize = neighbour.rect2DArea; neighbourIndex = neighbourProvIndex; } } } if (neighbourIndex < 0) { continue; } // Merges province into neighbour string provinceSource = map.provinces [provinceIndex].name; string provinceTarget = map.provinces [neighbourIndex].name; int prevProvCount = country.provinces.Length; if (!map.ProvinceTransferProvinceRegion(neighbourIndex, map.provinces [provinceIndex].mainRegion, false)) { Debug.LogWarning("Country: " + map.countries [countryIndex].name + " => " + provinceSource + " failed merge into " + provinceTarget + "."); break; } provCount = country.provinces.Length; if (provCount == prevProvCount) { break; // can't merge more provinces } } provinceChanges = true; cityChanges = true; mountPointChanges = true; }
void GenerateWorldTexture() { // Create background texture int backgroundTextureWidth = mapGenerationQuality == MapGenerationQuality.Draft ? 256 : this.backgroundTextureWidth; int backgroundTextureHeight = mapGenerationQuality == MapGenerationQuality.Draft ? 128 : this.backgroundTextureHeight; if (backgroundTexture == null || backgroundTexture.width != backgroundTextureWidth || backgroundTexture.height != backgroundTextureHeight) { backgroundTexture = new Texture2D(backgroundTextureWidth, backgroundTextureHeight, TextureFormat.RGBA32, true); } int bufferLen = backgroundTextureWidth * backgroundTextureHeight; if (backgroundColors == null || backgroundColors.Length != bufferLen) { backgroundColors = new Color[bufferLen]; } Color backColor = seaColor; backColor.a = 0; backgroundColors.Fill <Color> (backColor); int provincesCount = _map.provinces.Length; for (int k = 0; k < provincesCount; k++) { Province prov = _map.provinces [k]; if (prov.regions == null) { _map.ReadProvincePackedString(prov); if (prov.regions == null) { continue; } } Region region = prov.regions [0]; if (gradientPerPixel) { _map.RegionPaintHeights(backgroundColors, backgroundTextureWidth, backgroundTextureHeight, region, heights, seaLevel, currentHeightmapWidth, currentHeightmapHeight, heightGradient); } else { Color provColor = prov.attrib ["mapColor"]; provColor.a = 1; _map.RegionPaint(backgroundColors, backgroundTextureWidth, backgroundTextureHeight, region, provColor); } } backgroundTexture.SetPixels(backgroundColors); backgroundTexture.Apply(); // Set height to 0 out of land areas if (heightMapTexture != null) { if (currentHeightmapWidth == backgroundTextureWidth && currentHeightmapHeight == backgroundTextureHeight) { for (int k = 0; k < backgroundColors.Length; k++) { if (backgroundColors [k].a == 0) { heights [k] = 0; heightColors [k] = Misc.ColorClear; } else { heightColors [k].r = heightColors [k].g = heightColors [k].b = heightColors [k].a = heights [k]; } } } else { for (int k = 0, y = 0; y < currentHeightmapHeight; y++) { int backy = y * backgroundTextureHeight / currentHeightmapHeight; int backyy = backy * backgroundTextureWidth; for (int x = 0; x < currentHeightmapWidth; x++, k++) { int backx = x * backgroundTextureWidth / currentHeightmapWidth; if (backgroundColors [backyy + backx].a == 0) { heights [k] = 0; heightColors [k] = Misc.ColorClear; } else { heightColors [k].r = heightColors [k].g = heightColors [k].b = heightColors [k].a = heights [k]; } } } } heightMapTexture.SetPixels(heightColors); heightMapTexture.Apply(); } }