public void Initialize(IWorld world, int seed) { m_World = world; m_Seed = seed; m_GenHelper = CreateGenerationHelper(seed); m_GenContextPool = new ConcurrentBag <GenerationContext>(); }
protected virtual GenerationHelper CreateGenerationHelper(int seed) { Random random = new Random(seed); GenerationHelper helper = new GenerationHelper { Seed = seed, DepthNoise = new GenericNoise <PerlinNoise>(new PerlinNoise(random.Next()), 8, 0.5f), MainNoise = new GenericNoise <PerlinNoise>(new PerlinNoise(random.Next()), 8, 0.5f), MaxNoise = new GenericNoise <PerlinNoise>(new PerlinNoise(random.Next()), 8, 0.5f), MinNoise = new GenericNoise <PerlinNoise>(new PerlinNoise(random.Next()), 8, 0.5f), SurfaceNoise = new GenericNoise <PerlinNoise>(new PerlinNoise(random.Next()), 8, 0.5f), BiomeWeights = new float[5, 5], GenLayers = CreateGenLayers(seed) }; InitBiomeWeights(helper.BiomeWeights); return(helper); }
public override void Generate(IWorld world, ChunkPos pos, BlockData[,,] blocks, Quaternion[,,] rotations, byte[,] heightMap, GenerationHelper helper, GenerationContext context) { pos = ChunkPos.Get(pos.X / ChunkWidth, pos.Z / ChunkWidth); // 。。。 int range = m_Range; BiomeData biome = context.Biomes[ChunkWidth / 2, ChunkWidth / 2]; Random random = new Random(helper.Seed); int rand1 = random.Next(); int rand2 = random.Next(); // 遍历周围 (range * 2 + 1) * (range * 2 + 1) 的区块,默认 range = 8 for (int x = pos.X - range; x <= pos.X + range; x++) { for (int z = pos.Z - range; z <= pos.Z + range; z++) { int randX = x * rand1; int randZ = z * rand2; random = new Random(randX ^ randZ ^ helper.Seed); RecursiveGenerate(world, ChunkPos.Get(x, z), pos, blocks, biome, random); } } }
public override void Generate(IWorld world, ChunkPos pos, BlockData[,,] blocks, Quaternion[,,] rotations, byte[,] heightMap, GenerationHelper helper, GenerationContext context) { int minHeight = m_MinHeight; int maxHeight = m_MaxHeight; int count = m_Count; BlockData ore = world.BlockDataTable.GetBlock(m_OreBlock); int chunkSeed = pos.X ^ pos.Z ^ helper.Seed ^ ore.ID; Random random = new Random(chunkSeed); if (minHeight > maxHeight) { int tmp = minHeight; minHeight = maxHeight; maxHeight = tmp; } else if (maxHeight == minHeight) { if (minHeight < ChunkHeight - 1) { ++maxHeight; } else { --minHeight; } } for (int i = 0; i < count; i++) { int x = pos.X + random.Next(ChunkWidth); int y = random.Next(minHeight, maxHeight); int z = pos.Z + random.Next(ChunkWidth); Generate(x, y, z, blocks, random, ore, count); } }
public override void Generate(IWorld world, ChunkPos pos, BlockData[,,] blocks, Quaternion[,,] rotations, byte[,] heightMap, GenerationHelper helper, GenerationContext context) { BiomeData biome = context.Biomes[8, 8]; Random random = new Random(pos.X ^ pos.Z ^ helper.Seed); BlockData plantBlock = world.BlockDataTable.GetBlock(m_PlantBlock); int height = random.Next(m_MaxPlantHeightDelta) + m_MinPlantHeight; int count = random.Next(m_PlantType switch { PlantType.Grass => biome.GrassPerChunk, PlantType.Flower => biome.FlowersPerChunk, PlantType.Cacti => biome.CactiPerChunk, PlantType.Mushroom => biome.MushroomsPerChunk, _ => throw new NotImplementedException() });
public abstract void Generate(IWorld world, ChunkPos pos, BlockData[,,] blocks, Quaternion[,,] rotations, byte[,] heightMap, GenerationHelper helper, GenerationContext context);
private void GenerateBasicTerrain(IWorld world, ChunkPos pos, BlockData[,,] blocks, GenerationHelper helper, GenerationContext context) { int x = pos.X / 16; int z = pos.Z / 16; // 产生高度图 GenerateDensityMap(new Vector3Int(x * 4, 0, z * 4), helper, context); BlockData airBlock = world.BlockDataTable.GetBlock(AirBlock); BlockData stoneBlock = world.BlockDataTable.GetBlock(StoneBlock); BlockData waterBlock = world.BlockDataTable.GetBlock(WaterBlock); // 进行线性插值 for (int xHigh = 0; xHigh < 4; xHigh++) { for (int zHigh = 0; zHigh < 4; zHigh++) { for (int yHigh = 0; yHigh < 32; yHigh++) { float yPart111 = context.DensityMap[xHigh, yHigh, zHigh]; float yPart121 = context.DensityMap[xHigh, yHigh, zHigh + 1]; float yPart211 = context.DensityMap[xHigh + 1, yHigh, zHigh]; float yPart221 = context.DensityMap[xHigh + 1, yHigh, zHigh + 1]; float yDensityStep11 = (context.DensityMap[xHigh, yHigh + 1, zHigh] - yPart111) * 0.125f; float yDensityStep12 = (context.DensityMap[xHigh, yHigh + 1, zHigh + 1] - yPart121) * 0.125f; float yDensityStep21 = (context.DensityMap[xHigh + 1, yHigh + 1, zHigh] - yPart211) * 0.125f; float yDensityStep22 = (context.DensityMap[xHigh + 1, yHigh + 1, zHigh + 1] - yPart221) * 0.125f; for (int yLow = 0; yLow < 8; yLow++) { float density111 = yPart111; float density121 = yPart121; float xDensityStep11 = (yPart211 - yPart111) * 0.25f; float xDensityStep21 = (yPart221 - yPart121) * 0.25f; for (int xLow = 0; xLow < 4; xLow++) { float zDensityStep11 = (density121 - density111) * 0.25f; float blockValue = density111 - zDensityStep11; for (int zLow = 0; zLow < 4; zLow++) { int posX = xHigh * 4 + xLow; int posY = yHigh * 8 + yLow; int posZ = zHigh * 4 + zLow; if ((blockValue += zDensityStep11) > 0) { blocks[posX, posY, posZ] = stoneBlock; } else if (posY < SeaLevel) { blocks[posX, posY, posZ] = waterBlock; } else { blocks[posX, posY, posZ] = airBlock; } } density111 += xDensityStep11; density121 += xDensityStep21; } yPart111 += yDensityStep11; yPart121 += yDensityStep12; yPart211 += yDensityStep21; yPart221 += yDensityStep22; } } } } }
public override void Generate(IWorld world, ChunkPos pos, BlockData[,,] blocks, Quaternion[,,] rotations, byte[,] heightMap, GenerationHelper helper, GenerationContext context) { // 生物群系生成 NativeInt2DArray biomeIds = helper.GenLayers.GetInts(pos.X - 8, pos.Z - 8, 32, 32, Allocator.TempJob); for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { context.Biomes[j, i] = world.BiomeDataTable.GetBiome(biomeIds[(int)(0.861111f * j * 4), (int)(0.861111f * i * 4)]); } } biomeIds.Dispose(); // 基本地形生成 GenerateBasicTerrain(world, pos, blocks, helper, context); // 获取生物群系 biomeIds = helper.GenLayers.GetInts(pos.X, pos.Z, 16, 16, Allocator.TempJob); for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { context.Biomes[j, i] = world.BiomeDataTable.GetBiome(biomeIds[j, i]); } } biomeIds.Dispose(); // 设置生物群系 // for (int height = 0; height < 64; ++height) // { // for (int i = 0; i < 4; ++i) // { // for (int j = 0; j < 4; ++j) // { // columns[(height * 4 + i) * 4 + j].BiomeConfigData = (int)_biomesForGeneration[j * 4, i * 4].GetBiomeId(); // } // } // } // 添加生物群系特有方块 ReplaceBiomeBlocks(world, pos, blocks, helper, context); }
private void ReplaceBiomeBlocks(IWorld world, ChunkPos pos, BlockData[,,] blocks, GenerationHelper helper, GenerationContext context) { helper.SurfaceNoise.Noise(context.SurfaceMap, new Vector3(pos.X + 0.1f, 0, pos.Z + 0.1f), new Vector3(0.0625f, 1f, 0.0625f)); for (int x1 = 0; x1 < 16; x1++) { for (int z1 = 0; z1 < 16; z1++) { GenerateBiomeTerrain(x1, z1, world, blocks, context); } } }
private void GenerateDensityMap(Vector3Int noiseOffset, GenerationHelper helper, GenerationContext context) { Vector3 depthOffset = new Vector3(noiseOffset.x + 0.1f, 0.0f, noiseOffset.z + 0.1f); Vector3 depthScale = new Vector3(DepthNoiseScale.x, 1.0f, DepthNoiseScale.z); helper.DepthNoise.Noise(context.DepthMap, depthOffset, depthScale); Vector3 noiseScale = new Vector3(CoordinateScale, HeightScale, CoordinateScale); // 生成 3 个 5 * 5 * 33 的噪声 helper.MainNoise.Noise(context.MainNoiseMap, noiseOffset, Vector3.Scale(noiseScale, MainNoiseScale)); helper.MinNoise.Noise(context.MinLimitMap, noiseOffset, noiseScale); helper.MaxNoise.Noise(context.MaxLimitMap, noiseOffset, noiseScale); // chunk遍历 for (int x1 = 0; x1 < 5; x1++) { for (int z1 = 0; z1 < 5; z1++) { float scale = 0; float groundYOffset = 0; float totalWeight = 0; // 中心点生物群系 BiomeData centerBiome = context.Biomes[z1 + 2, x1 + 2]; // 求 scale 和 groundYOffset 的加权平均值 for (int x2 = 0; x2 < 5; x2++) { for (int z2 = 0; z2 < 5; z2++) { BiomeData biome = context.Biomes[z1 + z2, x1 + x2]; float curGroundYOffset = BiomeDepthOffset + biome.BaseHeight * BiomeDepthWeight; // biomeDepthOffSet = 0 float curScale = BiomeScaleOffset + biome.HeightVariation * BiomeScaleWeight; // biomeScaleOffset = 0 // parabolicField 为 10 / √(该点到中心点的距离^2 + 0.2) float weight = helper.BiomeWeights[z2, x2] / (curGroundYOffset + 2.0f); if (biome.BaseHeight > centerBiome.BaseHeight) { weight *= 0.5f; } scale += curScale * weight; groundYOffset += curGroundYOffset * weight; totalWeight += weight; } } scale = scale / totalWeight; groundYOffset = groundYOffset / totalWeight; scale = scale * 0.9f + 0.1f; groundYOffset = (groundYOffset * 4.0f - 1.0f) / 8.0f; // 取一个 -0.36 ~ 0.125 的随机数,这个随机数决定了起伏的地表 float random = (context.DepthMap[x1, 0, z1] - 0.5f) * 2 / 8000f; if (random < 0) { random *= -0.3f; } random = random * 3.0f - 2.0f; if (random < 0) { random *= 0.5f; if (random < -1) { random = -1f; } random /= 1.4f; random /= 2.0f; } else { if (random > 1) { random = 1f; } random *= 0.125f; } float groundYOffset1 = groundYOffset; float scale1 = scale; // groundYOffset 有 -0.072 ~ 0.025 的变动量 groundYOffset1 = groundYOffset1 + random * 0.2f; groundYOffset1 = groundYOffset1 * BaseSize / 8.0f; // 这个是大概的地面 y 坐标 float groundY = BaseSize + groundYOffset1 * 4.0f; // baseSize = 8.5,应该代表了平均地表高度 68 // 注意这个 y * 8 才是最终的y坐标 for (int y = 0; y < 33; y++) { // result 偏移量,这个是负数则趋向固体,是正数则趋向液体和空气 float offset = (y - groundY) * StretchY * 128.0f / 256.0f / scale1; // scale 大概在 0.1 ~ 0.2 这样... if (offset < 0) { offset *= 4f; } // 并不保证 lowerLimit < upperLimit,不过没有影响 float lowerLimit = (context.MinLimitMap[x1, y, z1] - 0.5f) * 160000 / LowerLimitScale; // lowerLimitScale = 512 float upperLimit = (context.MaxLimitMap[x1, y, z1] - 0.5f) * 160000 / UpperLimitScale; // upperLimitScale = 512 float t = ((context.MainNoiseMap[x1, y, z1] - 0.5f) * 160000 / 10.0f + 1.0f) / 2.0f; // 这个函数 t < 0 则取 lowerLimit,t > 1 则取 upperLimit,否则以 t 为参数在上下限间线性插值 float result = Mathf.Lerp(lowerLimit, upperLimit, t) - offset; // y = 30 ~ 32 if (y > 29) { // 在原 result 和 -10 之间线性插值,这样 y > 240 的方块就会越来越少,最后全变成空气 float t2 = (float)(y - 29) / 3f; result = result * (1f - t2) + -10f * t2; } context.DensityMap[x1, y, z1] = (float)result; } } } }