private HexPointFlow[] GetFlowByCorner(HexPointCorner corner) { switch (corner.Corner) { // 0 // ^ // | // (X) <= corner // / \ // v v // 1 2 // | T | case HexCorner.North: return new HexPointFlow[] { new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.NorthWest), Corner = HexCorner.NorthEast }, Flow = MapCell.FlowDirectionType.North }, // 0 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.NorthWest), Corner = HexCorner.South }, Flow = MapCell.FlowDirectionType.SouthWest }, // 1 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.NorthEast), Corner = HexCorner.South }, Flow = MapCell.FlowDirectionType.SouthEast } // 2 }; // | // + + // / 0 1 // / ^ ^ // / \ / // + (X) <= corner // | T | // | v // | 2 case HexCorner.NorthEast: return new HexPointFlow[] { new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.NorthEast), Corner = HexCorner.SouthWest }, Flow = MapCell.FlowDirectionType.NorthWest }, // 0 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.NorthEast), Corner = HexCorner.SouthEast }, Flow = MapCell.FlowDirectionType.SouthWest }, // 1 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point, Corner = HexCorner.SouthEast }, Flow = MapCell.FlowDirectionType.South } // 2 }; // | 0 // | ^ // | T | // + (X) <= corner // \ / \ // \ v v // \ 2 1 // + + case HexCorner.SouthEast: return new HexPointFlow[] { new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point, Corner = HexCorner.NorthEast }, Flow = MapCell.FlowDirectionType.North }, // 0 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.East), Corner = HexCorner.South }, Flow = MapCell.FlowDirectionType.NorthWest }, // 1 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point, Corner = HexCorner.South }, Flow = MapCell.FlowDirectionType.SouthWest } // 2 }; // | T | // + + // 2 0 // ^ ^ // \ / // (X) <= corner // | // v // 1 case HexCorner.South: return new HexPointFlow[] { new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point, Corner = HexCorner.SouthEast }, Flow = MapCell.FlowDirectionType.NorthEast }, // 0 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.SouthWest), Corner = HexCorner.SouthEast }, Flow = MapCell.FlowDirectionType.South }, // 1 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point, Corner = HexCorner.SouthWest }, Flow = MapCell.FlowDirectionType.NorthWest } // 2 }; // | 0 // | ^ // | | T // + (X) <= corner // \ / \ // \ v v // \ 2 1 // + + case HexCorner.SouthWest: return new HexPointFlow[] { new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.West), Corner = HexCorner.NorthEast }, Flow = MapCell.FlowDirectionType.North }, // 0 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point, Corner = HexCorner.South }, Flow = MapCell.FlowDirectionType.SouthEast }, // 1 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.West), Corner = HexCorner.South }, Flow = MapCell.FlowDirectionType.SouthWest } // 2 }; // | // + + // / 0 1 // / ^ ^ // / \ / // + (X) <= corner // | | T // | v // | 2 case HexCorner.NorthWest: return new HexPointFlow[] { new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.NorthWest), Corner = HexCorner.SouthWest }, Flow = MapCell.FlowDirectionType.NorthWest }, // 0 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.NorthWest), Corner = HexCorner.SouthEast }, Flow = MapCell.FlowDirectionType.NorthEast }, // 1 new HexPointFlow { Corner = new HexPointCorner { Point = corner.Point.Neighbor(HexDirection.West), Corner = HexCorner.SouthEast }, Flow = MapCell.FlowDirectionType.South } // 2 }; default: throw new Exception(); } }
public void Create(GameStartupSettings settings) { Random rnd = new Random(); log.DebugFormat("Create( {0} )", settings); HeightMap heightmap = CreateHeightMap(settings); float seaLevel = heightmap.FindHeightLevel(settings.OceanRatio * 1.5f, 0.05f); // <-- Values from settings float shoreLevel = heightmap.FindHeightLevel(settings.OceanRatio, 0.05f); // <-- Values from settings float hillLevel = heightmap.FindHeightLevel(0.1f, 0.01f); // <-- Values from settings float mountainLevel = heightmap.FindHeightLevel(settings.PeakRatio, 0.01f); // <-- Values from settings OnProgress(new ProgressNotificationEventArgs(string.Format("Min: {0}, Sea: {1}, shoreLevel: {2}, mountain: {3}, max: {4}", heightmap.Minimum, seaLevel, shoreLevel, mountainLevel, heightmap.Maximum), 1f, 0.1f)); Init(settings.Width, settings.Height); // assign coords for (int i = 0; i < settings.Width; ++i) { for (int j = 0; j < settings.Height; ++j) { this[i, j].Height = heightmap[i, j]; } } Terrain ocean = Provider.Instance.Terrains["Ocean"]; Terrain shore = Provider.Instance.Terrains["Shore"]; // Shore Terrain coast = Provider.Instance.Terrains["Coast"]; Terrain grassland = Provider.Instance.Terrains["Grassland"]; Feature hills = Provider.Instance.Features["Hills"]; Feature mountains = Provider.Instance.Features["Mountains"]; // settle ground plains (ocean, grassland, mountain) RangeConversion<float, Terrain> conv = new RangeConversion<float, Terrain>(grassland); conv.AddMapping(heightmap.Minimum, seaLevel, ocean); conv.AddMapping(seaLevel, shoreLevel, shore); conv.AddMapping(shoreLevel, hillLevel, grassland); //conv.AddMapping(hillLevel, mountainLevel, hill); //conv.AddMapping(mountainLevel, heightmap.Maximum, mountain); for (int i = 0; i < settings.Width; ++i) { for (int j = 0; j < settings.Height; ++j) { this[i, j].Terrain = conv.Find(heightmap[i, j]); if(hillLevel <= heightmap[i,j] && heightmap[i,j] < mountainLevel) this[i, j].Features.Add(hills); else if(mountainLevel <= heightmap[i,j]) this[i, j].Features.Add(mountains); } } OnProgress(new ProgressNotificationEventArgs("Basic Terrain Assignment", 1f, 0.2f)); // find coasts for (int i = 0; i < settings.Width; ++i) { for (int j = 0; j < settings.Height; ++j) { if (this[i, j].IsOcean) { if (ShouldBeCoast(i, j)) this[i, j].Terrain = coast; } } } OnProgress(new ProgressNotificationEventArgs("Find Coasts: " + GetArea(a => a.IsOcean).Count + " ocean tiles, " + GetArea(a => a.IsLand).Count + " land tiles", 1f, 0.3f)); // find river tiles List<MapCell> hillsOrMountains = GetArea(a => a.IsSpring); int currentRiverId = 0; int numOfRivers = Math.Min(hillsOrMountains.Count, settings.NumOfRivers); Array corners = Enum.GetValues(typeof(HexCorner)); while( currentRiverId < numOfRivers) { MapCell spring = hillsOrMountains.PickRandom(); HexCorner randomCorner = (HexCorner)corners.GetValue(rnd.Next(corners.Length)); HexPointCorner hxc = new HexPointCorner { Corner = randomCorner, Point = spring.Point }; HexPointFlow[] flows = GetFlowByCorner(hxc); River currentriver = new River(string.Format("River{0}", currentRiverId)); Rivers.Add(currentriver); DoRiver(flows[rnd.Next(3)], hxc, currentriver, 0); currentRiverId++; } OnProgress(new ProgressNotificationEventArgs("Add Rivers: " + GetArea(a => a.IsRiver).Count + " tiles", 1f, 0.3f)); }
private void DoRiver(HexPointFlow hexPointFlow, HexPointCorner hxc, River river, int iteration) { if (river.Points.Count > 50 || iteration > 100) // paranoia return; if (!IsValid(hxc.Point)) return; if( !river.Points.Select( a => a.Point).Contains(hxc.Point) ) river.Points.Add(new FlowPoint( hxc.Point, hexPointFlow.Flow)); this[hxc.Point].SetRiver(hexPointFlow.Flow); if (this[hxc.Point].IsOcean) return; List<HexPointFlow> flows = new List<HexPointFlow>(GetFlowByCorner(hxc)); // remove not valid and current flow (resp. reverse flow) for (int i = 2; i > -1; i-- ) { if (!IsValid(flows[i].Corner.Point) || Reverse(flows[i].Flow) == hexPointFlow.Flow || flows[i].Flow == hexPointFlow.Flow) flows.RemoveAt(i); } if (flows.Count == 0) return; if( flows.Count == 1) { DoRiver( new HexPointFlow { Corner = flows[0].Corner, Flow = flows[0].Flow }, flows[0].Corner, river, iteration + 1); return; } float height1 = GetHeightAtCorner( flows[0].Corner.Point.X, flows[0].Corner.Point.Y, flows[0].Corner.Corner); float height2 = GetHeightAtCorner( flows[1].Corner.Point.X, flows[1].Corner.Point.Y, flows[1].Corner.Corner); if(height1 < height2) DoRiver(new HexPointFlow { Corner = flows[0].Corner, Flow = flows[0].Flow }, flows[0].Corner, river, iteration + 1); else DoRiver(new HexPointFlow { Corner = flows[1].Corner, Flow = flows[1].Flow }, flows[1].Corner, river, iteration + 1); }