public static void CreateOreVeins(TerrainData terrain, Random random, double xk, double yk) { var veinMaterials = Materials.GetMaterials(MaterialCategory.Mineral).Select(mi => mi.ID).ToArray(); for (int i = 0; i < 100; ++i) { var start = GetRandomSubterraneanLocation(terrain, random); var mat = veinMaterials[random.Next(veinMaterials.Length)]; int len = random.Next(20) + 3; int thickness = random.Next(4) + 1; var vx = random.NextDouble() * 2 - 1; var vy = random.NextDouble() * 2 - 1; var vz = vx * xk + vy * yk; var v = new DoubleVector3(vx, vy, -vz).Normalize(); for (double t = 0.0; t < len; t += 1) { var p = start + (v * t).ToIntVector3(); CreateOreSphere(terrain, random, p, thickness, mat, random.NextDouble() * 0.75, 0); } } }
public static TerrainData CreateBallMap(IntSize3 size, int innerSide = 0) { var map = new TerrainData(size); int side = MyMath.Min(size.Width, size.Height, size.Depth); int r = side / 2 - 1; int ir = innerSide / 2 - 1; Parallel.For(0, size.Depth, z => { for (int y = 0; y < size.Height; ++y) for (int x = 0; x < size.Width; ++x) { var pr = Math.Sqrt((x - r) * (x - r) + (y - r) * (y - r) + (z - r) * (z - r)); var p = new IntVector3(x, y, z); if (pr < r && pr >= ir) map.SetTileDataNoHeight(p, TileData.GetNaturalWall(MaterialID.Granite)); else map.SetTileDataNoHeight(p, TileData.EmptyTileData); } }); map.RescanLevelMap(); return map; }
public static void CreateGrass(TerrainData terrain, Random random, int grassLimit) { var grid = terrain.TileGrid; var heightMap = terrain.HeightMap; int w = terrain.Width; int h = terrain.Height; var materials = Materials.GetMaterials(MaterialCategory.Grass).ToArray(); for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { int z = heightMap[y, x]; var p = new IntPoint3(x, y, z); if (z < grassLimit) { var td = grid[p.Z, p.Y, p.X]; if (Materials.GetMaterial(td.TerrainMaterialID).Category == MaterialCategory.Soil && (td.TerrainID.IsFloor() || td.TerrainID.IsSlope())) { td.InteriorID = InteriorID.Grass; td.InteriorMaterialID = materials[random.Next(materials.Length)].ID; grid[p.Z, p.Y, p.X] = td; } } } } }
public static TerrainData CreateNoiseTerrain(IntSize3 size, Random random) { var terrain = new TerrainData(size); var noise = CreateTerrainNoise(); var noisemap = CreateTerrainNoiseMap(noise, new IntSize2(size.Width, size.Height)); FillFromNoiseMap(terrain, noisemap); terrain.RescanLevelMap(); double xk = (random.NextDouble() * 2 - 1) * 0.01; double yk = (random.NextDouble() * 2 - 1) * 0.01; TerrainHelpers.CreateBaseMinerals(terrain, random, xk, yk); TerrainHelpers.CreateOreVeins(terrain, random, xk, yk); TerrainHelpers.CreateOreClusters(terrain, random); RiverGen.Generate(terrain, random); int soilLimit = size.Depth * 4 / 5; TerrainHelpers.CreateSoil(terrain, soilLimit); int grassLimit = terrain.Depth * 4 / 5; TerrainHelpers.CreateVegetation(terrain, random, grassLimit); return terrain; }
public static void CreateOreClusters(TerrainData terrain, Random random) { var clusterMaterials = Materials.GetMaterials(MaterialCategory.Gem).Select(mi => mi.ID).ToArray(); for (int i = 0; i < 100; ++i) { var p = GetRandomSubterraneanLocation(terrain, random); CreateOreCluster(terrain, random, p, clusterMaterials[random.Next(clusterMaterials.Length)]); } }
public void Render(TerrainData terrain, IntVector3 pos) { if (pos.Z == m_size.Depth) RenderTerrain(terrain); else RenderSliceXY(terrain, pos.Z); RenderSliceXZ(terrain, pos.Y); RenderSliceYZ(terrain, pos.X); }
public static void CreateSlopes(TerrainData data, int baseSeed) { var plane = data.Size.Plane; plane.Range().AsParallel().ForAll(p => { int z = data.GetHeight(p); int count = 0; Direction dir = Direction.None; var r = new MWCRandom(p, baseSeed); int offset = r.Next(8); // Count the tiles around this tile which are higher. Create slope to a random direction, but skip // the slope if all 8 tiles are higher. // Count to 10. If 3 successive slopes, create one in the middle int successive = 0; for (int i = 0; i < 10; ++i) { var d = DirectionExtensions.PlanarDirections[(i + offset) % 8]; var t = p + d; if (plane.Contains(t) && data.GetHeight(t) > z) { if (i < 8) count++; successive++; if (successive == 3) { dir = DirectionExtensions.PlanarDirections[((i - 1) + offset) % 8]; } else if (dir == Direction.None) { dir = d; } } else { successive = 0; } } if (count > 0 && count < 8) { var p3d = new IntPoint3(p, z); var td = data.GetTileData(p3d); td.TerrainID = dir.ToSlope(); data.SetTileData(p3d, td); } }); }
public static void Generate(TerrainData terrain, Random random) { var riverGen = new RiverGen(terrain, random); if (riverGen.CreateRiverPath()) { riverGen.AdjustRiver(); } else { Trace.TraceError("Failed to create river"); } }
public static unsafe TerrainData LoadTerrain(string path, string expectedName, IntSize3 expectedSize) { if (File.Exists(path) == false) return null; using (var stream = File.OpenRead(path)) { TerrainData terrain; using (var br = new BinaryReader(stream, Encoding.Default, true)) { var name = br.ReadString(); if (name != expectedName) return null; int w = br.ReadInt32(); int h = br.ReadInt32(); int d = br.ReadInt32(); var size = new IntSize3(w, h, d); if (size != expectedSize) return null; terrain = new TerrainData(size); } fixed (TileData* v = terrain.m_tileGrid) { byte* p = (byte*)v; int len = terrain.Size.Volume * sizeof(TileData); using (var memStream = new UnmanagedMemoryStream(p, 0, len, FileAccess.Write)) CopyTo(stream, memStream, len); } fixed (byte* p = terrain.m_levelMap) { int len = terrain.Size.Plane.Area * sizeof(byte); using (var memStream = new UnmanagedMemoryStream(p, 0, len, FileAccess.Write)) CopyTo(stream, memStream, len); } return terrain; } }
public static void CreateBaseMinerals(TerrainData terrain, Random random, double xk, double yk) { int width = terrain.Width; int height = terrain.Height; int depth = terrain.Depth; var rockMaterials = Materials.GetMaterials(MaterialCategory.Rock).ToArray(); var layers = new MaterialID[20]; { int rep = 0; MaterialID mat = MaterialID.Undefined; for (int z = 0; z < layers.Length; ++z) { if (rep == 0) { rep = random.Next(4) + 1; mat = rockMaterials[random.Next(rockMaterials.Length - 1)].ID; } layers[z] = mat; rep--; } } Parallel.For(0, height, y => { for (int x = 0; x < width; ++x) { int surface = terrain.GetSurfaceLevel(x, y); for (int z = 0; z < surface; ++z) { var p = new IntVector3(x, y, z); int _z = MyMath.Round(z + x * xk + y * yk); _z = _z % layers.Length; if (_z < 0) _z += layers.Length; terrain.SetTileDataNoHeight(p, TileData.GetNaturalWall(layers[_z])); } } }); }
public MainWindow() { const int depth = 5; const int sizeExp = 9; int side = (int)Math.Pow(2, sizeExp); m_size = new IntSize3(side, side, depth); m_terrain = new TerrainData(m_size); m_terrainGen = new DungeonTerrainGenerator(m_terrain, new Random(1)); m_renderer = new Renderer(m_size); this.SliceBmpXY = m_renderer.SliceBmpXY; this.SliceBmpXZ = m_renderer.SliceBmpXZ; this.SliceBmpYZ = m_renderer.SliceBmpYZ; InitializeComponent(); }
void CreateTerrain(IntSize3 size) { TerrainData terrain; switch (m_mapMode) { case GameMap.Ball: terrain = ArtificialGen.CreateBallMap(size); break; case GameMap.Cube: terrain = ArtificialGen.CreateCubeMap(size, 2); break; default: throw new NotImplementedException(); } m_terrainData = terrain; }
public static TerrainData CreateCubeMap(IntSize3 size, int margin) { var map = new TerrainData(size); Parallel.For(0, size.Depth, z => { for (int y = 0; y < size.Height; ++y) for (int x = 0; x < size.Width; ++x) { var p = new IntVector3(x, y, z); if (x < margin || y < margin || z < margin || x >= size.Width - margin || y >= size.Height - margin || z >= size.Depth - margin) map.SetTileDataNoHeight(p, TileData.EmptyTileData); else map.SetTileDataNoHeight(p, TileData.GetNaturalWall(MaterialID.Granite)); } }); map.RescanLevelMap(); return map; }
static TerrainData CreateTerrain(IntSize3 size) { //var random = Helpers.Random; var random = new Random(1); var terrain = new TerrainData(size); var tg = new TerrainGenerator(terrain, random); var corners = new DiamondSquare.CornerData() { NE = 15, NW = 10, SW = 10, SE = 10, }; tg.Generate(corners, 5, 0.75, 2); int grassLimit = terrain.Depth * 4 / 5; TerrainHelpers.CreateVegetation(terrain, random, grassLimit); return terrain; }
public RiverGen(TerrainData terrain, Random random) { m_terrain = terrain; m_random = random; }
static bool CreateOre(TerrainData terrain, IntVector3 p, MaterialID oreMaterialID) { if (!terrain.Contains(p)) return false; var td = terrain.GetTileData(p); if (td.ID != TileID.NaturalWall) return false; if (Materials.GetMaterial(td.MaterialID).Category != MaterialCategory.Rock) return false; td.SecondaryMaterialID = oreMaterialID; terrain.SetTileDataNoHeight(p, td); return true; }
static void CreateOreCluster(TerrainData terrain, Random random, IntVector3 p, MaterialID oreMaterialID) { CreateOreCluster(terrain, p, oreMaterialID, random.Next(6) + 1); }
public MyTarget(TerrainData terrain, IntVector3 origin, SideEdge sourceSide) { m_terrain = terrain; m_origin = origin; m_sourceSide = sourceSide; }
public static void CreateTrees(TerrainData terrain, Random random) { var grid = terrain.TileGrid; var heightMap = terrain.HeightMap; var materials = Materials.GetMaterials(MaterialCategory.Wood).ToArray(); int baseSeed = random.Next(); if (baseSeed == 0) baseSeed = 1; terrain.Size.Plane.Range().AsParallel().ForAll(p2d => { int z = heightMap[p2d.Y, p2d.X]; var p = new IntPoint3(p2d, z); var td = grid[p.Z, p.Y, p.X]; if (td.InteriorID == InteriorID.Grass) { var r = new MWCRandom(p, baseSeed); if (r.Next(8) == 0) { td.InteriorID = r.Next(2) == 0 ? InteriorID.Tree : InteriorID.Sapling; td.InteriorMaterialID = materials[r.Next(materials.Length)].ID; grid[p.Z, p.Y, p.X] = td; } } }); }
static void CreateOreCluster(TerrainData terrain, IntVector3 p, MaterialID oreMaterialID, int count) { bool b = CreateOre(terrain, p, oreMaterialID); if (b == false) return; if (count > 0) { foreach (var d in DirectionExtensions.CardinalUpDownDirections) CreateOreCluster(terrain, p + d, oreMaterialID, count - 1); } }
static void CreateOreSphere(TerrainData terrain, Random random, IntVector3 center, int r, MaterialID oreMaterialID, double probIn, double probOut) { // adjust r, so that r == 1 gives sphere of one tile r -= 1; // XXX split the sphere into 8 parts, and mirror var bb = new IntGrid3(center.X - r, center.Y - r, center.Z - r, r * 2 + 1, r * 2 + 1, r * 2 + 1); var rs = MyMath.Square(r); foreach (var p in bb.Range()) { var y = p.Y; var x = p.X; var z = p.Z; var v = MyMath.Square(x - center.X) + MyMath.Square(y - center.Y) + MyMath.Square(z - center.Z); if (rs >= v) { var rr = Math.Sqrt(v); double rel; if (r == 0) rel = 1; else rel = 1 - rr / r; var prob = (probIn - probOut) * rel + probOut; if (random.NextDouble() <= prob) CreateOre(terrain, p, oreMaterialID); } } }
public static void CreateSoil(TerrainData data, int soilLimit) { int w = data.Width; int h = data.Height; for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { int z = data.GetHeight(x, y); var p = new IntPoint3(x, y, z); if (z < soilLimit) { var td = data.GetTileData(p); td.TerrainMaterialID = MaterialID.Loam; data.SetTileData(p, td); } } } }
void RenderTerrain(TerrainData terrain) { int w = m_size.Width; int h = m_size.Height; TileData[,,] tileGrid; byte[,] levelMap; terrain.GetData(out tileGrid, out levelMap); int min = levelMap.Min(); int max = levelMap.Max(); m_sliceBmpXY.Lock(); unsafe { var pBackBuffer = (uint*)m_sliceBmpXY.BackBuffer; int stride = m_sliceBmpXY.BackBufferStride / 4; Parallel.For(0, h, y => { for (int x = 0; x < w; ++x) { int z = terrain.GetSurfaceLevel(x, y); TileData td; while (true) { var p = new IntVector3(x, y, z); td = terrain.GetTileData(p); if (td.IsEmptyNoWater) { z--; continue; } if (this.ShowWaterEnabled && td.WaterLevel > 0) { var wl = terrain.GetWaterLevel(p + Direction.Up); if (wl > 0) { z++; continue; } } break; } int m = MyMath.Round(MyMath.LinearInterpolation(min, max, 100, 255, z)); var cv = GetTileColor(td); int r = cv.X; int g = cv.Y; int b = cv.Z; r = r * m / 255; g = g * m / 255; b = b * m / 255; var ptr = pBackBuffer + y * stride + x; *ptr = (uint)((r << 16) | (g << 8) | (b << 0)); } }); } m_sliceBmpXY.AddDirtyRect(new Int32Rect(0, 0, m_sliceBmpXY.PixelWidth, m_sliceBmpXY.PixelHeight)); m_sliceBmpXY.Unlock(); }
void RenderSliceYZ(TerrainData terrain, int x) { int w = m_size.Width; int h = m_size.Height; int d = m_size.Depth; m_sliceBmpYZ.Lock(); unsafe { var pBackBuffer = (uint*)m_sliceBmpYZ.BackBuffer; int stride = m_sliceBmpYZ.BackBufferStride / 4; Parallel.For(0, d, z => { for (int y = 0; y < h; ++y) { int mz = d - z - 1; var p = new IntVector3(x, y, mz); var td = terrain.GetTileData(p); uint c; if (td.IsEmpty && td.WaterLevel == 0) c = ColorToRaw(Colors.SkyBlue); else c = IntVector3ToRaw(GetTileColor(td)); var ptr = pBackBuffer + y * stride + z; *ptr = c; } }); } m_sliceBmpYZ.AddDirtyRect(new Int32Rect(0, 0, m_sliceBmpYZ.PixelWidth, m_sliceBmpYZ.PixelHeight)); m_sliceBmpYZ.Unlock(); }
static IntVector3 GetRandomSubterraneanLocation(TerrainData data, Random random) { int x = random.Next(data.Width); int y = random.Next(data.Height); int maxZ = data.GetSurfaceLevel(x, y); int z = random.Next(maxZ); return new IntVector3(x, y, z); }
void OnTimerTick(object sender, EventArgs e) { m_timer.IsEnabled = false; if (m_needCreate) { Stopwatch sw = Stopwatch.StartNew(); int depth = this.Depth; int side = this.Side; m_size = new IntSize3(side, side, depth); this.X = side / 2; this.Y = side / 2; this.Z = depth; //m_terrain = new TerrainData(m_size); this.Renderer = new Renderer(m_size); Notify("Renderer"); sw.Stop(); Trace.TraceInformation("Create took {0} ms", sw.ElapsedMilliseconds); levelSlider.Minimum = 0; levelSlider.Maximum = m_size.Depth; this.Z = m_size.Depth; m_needCreate = false; } if (m_needGenerate) { Stopwatch sw = Stopwatch.StartNew(); var random = new Random(1); m_terrain = NoiseTerrainGen.CreateNoiseTerrain(m_size, random); sw.Stop(); Trace.TraceInformation("Generate took {0} ms", sw.ElapsedMilliseconds); m_needGenerate = false; } if (m_needRender) { Stopwatch sw = Stopwatch.StartNew(); this.Renderer.ShowWaterEnabled = this.ShowWaterEnabled; this.Renderer.Render(m_terrain, new IntVector3(this.X, this.Y, this.Z)); sw.Stop(); Trace.TraceInformation("Render took {0} ms", sw.ElapsedMilliseconds); m_needRender = false; } }
static void FillFromNoiseMap(TerrainData terrainData, SharpNoise.NoiseMap noiseMap) { var max = noiseMap.Data.Max(); var min = noiseMap.Data.Min(); Parallel.For(0, noiseMap.Data.Length, i => { var v = noiseMap.Data[i]; // [-1 .. 1] v -= min; v /= (max - min); // [0 .. 1] v *= terrainData.Depth * 8 / 10; v += terrainData.Depth * 2 / 10; noiseMap.Data[i] = v; }); Parallel.For(0, terrainData.Height, y => { for (int x = 0; x < terrainData.Width; ++x) { var v = noiseMap[x, y]; int iv = (int)v; for (int z = terrainData.Depth - 1; z >= 0; --z) { var p = new IntVector3(x, y, z); /* above ground */ if (z > iv) { terrainData.SetTileDataNoHeight(p, TileData.EmptyTileData); } /* surface */ else if (z == iv) { terrainData.SetTileDataNoHeight(p, TileData.EmptyTileData); } /* underground */ else if (z < iv) { terrainData.SetTileDataNoHeight(p, TileData.GetNaturalWall(MaterialID.Granite)); } else { throw new Exception(); } } } }); }
void CreateTerrain() { var random = Helpers.Random; int side = MyMath.Pow2(MAP_SIZE); var size = new IntSize3(side, side, MAP_DEPTH); var terrain = new TerrainData(size); var tg = new DungeonTerrainGenerator(terrain, random); tg.Generate(1); TerrainHelpers.CreateSoil(terrain, 9999); TerrainHelpers.CreateGrass(terrain, random, 9999); TerrainHelpers.CreateTrees(terrain, random); m_rooms = tg.Rooms; m_terrainData = terrain; }
void RenderSliceXY(TerrainData terrain, int level) { int w = m_size.Width; int h = m_size.Height; m_sliceBmpXY.Lock(); unsafe { var pBackBuffer = (uint*)m_sliceBmpXY.BackBuffer; int stride = m_sliceBmpXY.BackBufferStride / 4; Parallel.For(0, h, y => { for (int x = 0; x < w; ++x) { var p = new IntVector3(x, y, level); var td = terrain.GetTileData(p); uint c; if (td.IsEmpty && td.WaterLevel == 0) c = ColorToRaw(Colors.SkyBlue); else c = IntVector3ToRaw(GetTileColor(td)); var ptr = pBackBuffer + y * stride + x; *ptr = c; } }); } m_sliceBmpXY.AddDirtyRect(new Int32Rect(0, 0, m_sliceBmpXY.PixelWidth, m_sliceBmpXY.PixelHeight)); m_sliceBmpXY.Unlock(); }
public DungeonTerrainGenerator(TerrainData data, Random random) { m_data = data; m_size = data.Size; m_random = random; }