/// <summary> /// Creates a finished map (placing cliffs, smoothing them, turning/mirroring the map, etc.) /// </summary> /// <param name="half"> The half to work on. </param> /// <param name="function"> The way to create the complete map. </param> /// <returns> The finished map. </returns> public MapPhenotype CreateFinishedMap(Half half, Enums.MapFunction function) { var tempMap = this.CreateCompleteMap(half, function); tempMap.PlaceCliffs(); tempMap.SmoothCliffs(); tempMap = tempMap.CreateCompleteMap(half, function); return(tempMap); }
/// <summary> /// Creates a map where one part has been turned onto the other part of the map. /// </summary> /// <param name="half"> The half to work on. </param> /// <param name="function"> The way to create the complete map. </param> /// <returns> The complete map. </returns> public MapPhenotype CreateCompleteMap(Half half, Enums.MapFunction function) { this.mapHalf = half; var newHeightLevels = (HeightLevel[, ]) this.HeightLevels.Clone(); var newMapItems = (Item[, ]) this.MapItems.Clone(); var rocks = (bool[, ]) this.DestructibleRocks.Clone(); // Figures out which part of the map that should be looked at. var xStart = (half == Half.Right) ? this.XSize / 2 : 0; var xEnd = (half == Half.Left) ? this.XSize / 2 : this.XSize; var yStart = (half == Half.Top) ? this.YSize / 2 : 0; var yEnd = (half == Half.Bottom) ? this.YSize / 2 : this.YSize; for (var y = yStart; y < yEnd; y++) { var otherY = y; // If we mirror top or bottom or turn the map, find the height to copy to. if ((function == Enums.MapFunction.Mirror && (half == Half.Top || half == Half.Bottom)) || function == Enums.MapFunction.Turn) { otherY = this.YSize - y - 1; } for (var x = xStart; x < xEnd; x++) { var otherX = x; // If we mirror left or right or turn the map, find the width to copy to. if ((function == Enums.MapFunction.Mirror && (half == Half.Left || half == Half.Right)) || function == Enums.MapFunction.Turn) { otherX = this.XSize - x - 1; } newHeightLevels[otherX, otherY] = this.HeightLevels[x, y]; newMapItems[otherX, otherY] = this.MapItems[x, y]; rocks[otherX, otherY] = this.DestructibleRocks[x, y]; } } var newMap = new MapPhenotype(newHeightLevels, newMapItems, rocks); return(newMap); }
/// <summary> /// Updates the list of cliff positions. /// </summary> /// <param name="half"> /// The half to look for cliffs on. /// </param> public void UpdateCliffPositions(Half half) { var xStart = (half == Half.Right) ? this.XSize / 2 : 0; var xEnd = (half == Half.Left) ? this.XSize / 2 : this.XSize; var yStart = (half == Half.Top) ? this.YSize / 2 : 0; var yEnd = (half == Half.Bottom) ? this.YSize / 2 : this.YSize; this.CliffPositions.Clear(); for (var x = xStart; x < xEnd; x++) { for (var y = yStart; y < yEnd; y++) { if (this.HeightLevels[x, y] == HeightLevel.Cliff) { this.CliffPositions.Add(new Tuple <int, int>(x, y)); } } } }
/// <summary> /// Initializes a new instance of the <see cref="CellularAutomata"/> class that takes an existing height map instead of creating and seeding a new one. /// </summary> /// <param name="xSize"> The x size of the map. </param> /// <param name="ySize"> The y size of the map. </param> /// <param name="half"> The half of the map to work on. </param> /// <param name="map"> The existing height map. </param> /// <param name="r"> The random object. </param> public CellularAutomata(int xSize, int ySize, Enums.Half half, Enums.HeightLevel[,] map, Random r = null) { this.Map = (Enums.HeightLevel[, ])map.Clone(); this.random = r ?? MapHelper.Random; this.XSize = xSize; this.YSize = ySize; // Figure out which part of the map that should be looked at. // Make sure we work on a bit more than half the map, in order to avoid that the edge along the middle does not have // "empty" neighbours from the beginning. this.caXStart = (half == Enums.Half.Right) ? (this.XSize / 2) - (int)(this.XSize * 0.1) : 0; this.caXEnd = (half == Enums.Half.Left) ? (this.XSize / 2) + (int)(this.XSize * 0.1) : this.XSize; this.caYStart = (half == Enums.Half.Top) ? (this.YSize / 2) - (int)(this.YSize * 0.1) : 0; this.caYEnd = (half == Enums.Half.Bottom) ? (this.YSize / 2) + (int)(this.YSize * 0.1) : this.YSize; this.ruleSet = new Ruleset(); this.LoadBasicRuleset(); }
/// <summary> /// Initializes a new instance of the <see cref="CellularAutomata"/> class. /// </summary> /// <param name="xSize"> The x size of the map. </param> /// <param name="ySize"> The y size of the map. </param> /// <param name="half"> The half of the map to work on. </param> /// <param name="oddsOfHeight1"> The odds of a tile being changed to height 1. </param> /// <param name="oddsOfHeight2"> The odds of a tile being changed to height 2. </param> /// <param name="maxRangeToGroupPoint"> The max range to the group points. </param> /// <param name="groupPoints"> The number of points where terrain should be grouped during the initial seeding. </param> /// <param name="generateHeight2"> Determines if the cellular automata should generate height2 or not. </param> /// <param name="r"> The random to use. If null, will use the MapHelper Random. </param> public CellularAutomata( int xSize, int ySize, Enums.Half half, double oddsOfHeight1 = 0.4, double oddsOfHeight2 = 0.2, int maxRangeToGroupPoint = 15, int groupPoints = 3, bool generateHeight2 = true, Random r = null) { this.Map = new Enums.HeightLevel[xSize, ySize]; this.random = r ?? MapHelper.Random; this.XSize = xSize; this.YSize = ySize; // Figure out which part of the map that should be looked at. // Make sure we work on a bit more than half the map, in order to avoid that the edge along the middle does not have // "empty" neighbours from the beginning. this.caXStart = (half == Enums.Half.Right) ? (this.XSize / 2) - (int)(this.XSize * 0.1) : 0; this.caXEnd = (half == Enums.Half.Left) ? (this.XSize / 2) + (int)(this.XSize * 0.1) : this.XSize; this.caYStart = (half == Enums.Half.Top) ? (this.YSize / 2) - (int)(this.YSize * 0.1) : 0; this.caYEnd = (half == Enums.Half.Bottom) ? (this.YSize / 2) + (int)(this.YSize * 0.1) : this.YSize; // Create points around which the terrain should be grouped var groupList = new List <Position>(); for (var i = 0; i < groupPoints; i++) { var x = this.random.Next(this.caXStart, this.caXEnd); var y = this.random.Next(this.caYStart, this.caYEnd); groupList.Add(new Position(x, y)); } for (var y = this.caYStart; y < this.caYEnd; y++) { for (var x = this.caXStart; x < this.caXEnd; x++) { var odds = this.random.NextDouble(); if (groupList.Count > 0) { var closest = (double)MapHelper.ClosestTo(new Position(x, y), groupList, maxRangeToGroupPoint); if (closest <= maxRangeToGroupPoint) { odds = odds - ((maxRangeToGroupPoint - closest) / (maxRangeToGroupPoint * 3)); } // ReSharper disable once RedundantCast if (closest < (int)(maxRangeToGroupPoint / 2)) { odds = odds / 2; } } if (generateHeight2 && odds < oddsOfHeight2) { this.Map[x, y] = Enums.HeightLevel.Height2; } else if (odds < oddsOfHeight1) { this.Map[x, y] = Enums.HeightLevel.Height1; } } } this.ruleSet = new Ruleset(); this.LoadRuleset(); }