/// <summary>
        /// Layers multiple Simplex Noises
        /// </summary>
        /// <param name="x">x position in worldspace</param>
        /// <param name="z">Z position in world space</param>
        /// <param name="octaves">Octaves are how many layers you are putting together. If you start with big features, the number of octaves determines how detailed the map will look.</param>
        /// <param name="frequency">The frequency of a layer is how many points fit into the space you've created. So for the mountain scale, you only need a few points, but at the rock scale you may need hundreds of points. In the code above, I start with a small frequency (which equates to large features) and move to higher frequencies which produce smaller details.</param>
        /// <param name="amplitude">The amplitude is how tall the features should be. Frequency determines the width of features, amplitude determines the height. Each octave the amplitude shrinks, meaning small features are also short. This doesn't have to be the case, but for this case it makes pleasing maps.</param>
        /// <param name="lacunarity">Lacunarity is what makes the frequency grow. Each octave the frequency is multiplied by the lacunarity. I use a lacunarity of 2.0, however values of 1.8715 or 2.1042 can help to reduce artifacts in some algorithms. A lacunarity of 2.0 means that the frequency doubles each octave, so if the first octave had 3 points the second would have 6, then 12, then 24, etc. This is used almost exclusively, partly because octaves in music double in frequency. Other values are perfectly acceptable, but the results will vary.</param>
        /// <param name="persistence">Persistence is what makes the amplitude shrink (or not shrink). Each octave the amplitude is multiplied by the gain. I use a gain of 0.65. If it is higher then the amplitude will barely shrink, and maps get crazy. Too low and the details become miniscule, and the map looks washed out. However, most use 1/lacunarity. Since the standard for lacunarity is 2.0, the standard for the gain is 0.5. Noise that has a gain of 0.5 and a lacunarity of 2.0 is referred to as 1/f noise, and is the industry standard.</param>
        /// <param name="offsetValue">Gets added to the value before normalization</param>
        /// <returns></returns>
        public static float FBMSimplex(float x, float z, int octaves, float frequency, float amplitude, float lacunarity = 2, float persistence = 0.5f)
        {
            float total = 0;

            for (int o = 0; o < octaves; o++)
            {
                total     += Noise.GetSimplex(x * frequency, z * frequency) * amplitude;
                frequency *= lacunarity;
                amplitude *= persistence;
            }

            return(NormalizeNoise(total));
        }
예제 #2
0
    //get the block type at a specific coordinate
    BlockType GetBlockType(int x, int y, int z)
    {
        //Core block placement at the bottom.
        if (y <= 1)
        {
            float simplexCore = noise1.GetSimplex(x * 20f, z * 20f);
            int   coreLevel   = simplexCore > 0 ? 1 : 0;
            if (y <= coreLevel)
            {
                return(BlockType.Core);
            }
        }

        float simplex1 = noise1.GetSimplexFractal(x * .8f, z * .8f) * 15;
        float simplex2 = noise1.GetSimplex(x * 3f, z * 3f) * 10 * (noise1.GetSimplex(x * .3f, z * .3f) + .5f);

        float heightMap = simplex1 + simplex2;

        //add the 2d noise to the middle of the terrain chunk
        float baseLandHeight = Chunk.chunkHeight * 0.48f + heightMap;

        //stone layer heightmap
        float simplexStone1 = noise1.GetSimplex(x * 1f, z * 1f) * 10;
        float simplexStone2 = (noise1.GetSimplex(x * 5f, z * 5f) + 0.5f) * 20 * (noise1.GetSimplex(x * 0.3f, z * 0.3f) + 0.5f);

        float stoneHeightMap  = simplexStone1 + simplexStone2;
        float baseStoneHeight = Chunk.chunkHeight * 0.40f + stoneHeightMap;


        BlockType blockType = BlockType.Air;

        //under the surface, dirt block
        if (y <= baseLandHeight)
        {
            blockType = BlockType.Dirt;

            //just on the surface, use a gr+ass type
            if (y > baseLandHeight - 1 && y > WaterChunkObject.waterHeight - 1)
            {
                blockType = BlockType.Grass;
            }

            if (y <= baseStoneHeight)
            {
                blockType = BlockType.Stone;
            }
        }
        //cave generation

        return(blockType);
    }
        public static void GenerateTrees(ChunkPos pos, BlockType[,,] blocks)
        {
            FastNoise.FastNoise noise1 = Chunk.noise1;
            int x = pos.x;
            int z = pos.z;

            System.Random rand = new System.Random(x * 10000 + z);

            float simplex = noise1.GetSimplex(x * .8f, z * .8f);

            if (simplex > 0)
            {
                simplex *= 2f;
                int treeCount = Mathf.FloorToInt((float)rand.NextDouble() * 5 * simplex);

                for (int i = 0; i < treeCount; i++)
                {
                    int xPos = (int)(rand.NextDouble() * 14) + 1;
                    int zPos = (int)(rand.NextDouble() * 14) + 1;

                    int y = Chunk.chunkHeight - 1;
                    //find the ground
                    while (y > WaterChunkObject.waterHeight && blocks[xPos, y, zPos] == BlockType.Air)
                    {
                        y--;
                    }
                    if (blocks[xPos, y, zPos] == BlockType.Leaves || blocks[xPos, y, zPos] == BlockType.Air)
                    {
                        return;
                    }
                    //dirt under tree
                    if (blocks[xPos, y, zPos] == BlockType.Grass)
                    {
                        blocks[xPos, y, zPos] = BlockType.Dirt;
                    }
                    y++;
                    int treeHeight = 4 + (int)(rand.NextDouble() * 4);

                    for (int j = 0; j < treeHeight; j++)
                    {
                        if (y + j < chunkHeight)
                        {
                            blocks[xPos, y + j, zPos] = BlockType.Wood;
                        }
                    }

                    int leavesWidth  = 1 + (int)(rand.NextDouble() * 6);
                    int leavesHeight = (int)(rand.NextDouble() * 3);
                    if (leavesHeight + leavesWidth < 5)
                    {
                        leavesHeight += 2;
                        leavesWidth  += 2;
                    }

                    int iter = 0;
                    for (int y_t = y + treeHeight - 1; y_t <= y + treeHeight - 1 + treeHeight; y_t++)
                    {
                        for (int x_t = xPos - (int)(leavesWidth * .5f) + iter / 2; x_t <= xPos + (int)(leavesWidth * .5f) - iter / 2; x_t++)
                        {
                            for (int z_t = zPos - (int)(leavesWidth * .5f) + iter / 2; z_t <= zPos + (int)(leavesWidth * .5f) - iter / 2; z_t++)
                            {
                                if (y_t >= 0 && y_t < chunkHeight && rand.NextDouble() < .8f)
                                {
                                    if (x_t >= chunkWidth || z_t >= chunkWidth || x_t <= 0 || z_t <= 0)
                                    {
                                        Vector3  blockPos = new Vector3();
                                        ChunkPos cpNextTo = new ChunkPos();
                                        if (z_t > chunkWidth && x_t < 0)
                                        {
                                            cpNextTo = new ChunkPos(pos.x - chunkWidth, pos.z + chunkWidth);
                                            blockPos = new Vector3(x_t + chunkWidth + 1, y_t, z_t - chunkWidth - 1);
                                        }
                                        else if (z_t < 0 && x_t > chunkWidth)
                                        {
                                            cpNextTo = new ChunkPos(pos.x + chunkWidth, pos.z - chunkWidth);
                                            blockPos = new Vector3(x_t - chunkWidth - 1, y_t, z_t + chunkWidth + 1);
                                        }
                                        else if (z_t > chunkWidth && x_t > chunkWidth)
                                        {
                                            cpNextTo = new ChunkPos(pos.x + chunkWidth, pos.z + chunkWidth);
                                            blockPos = new Vector3(x_t - chunkWidth - 1, y_t, z_t - chunkWidth - 1);
                                        }
                                        else if (z_t < 0 && x_t < 0)
                                        {
                                            cpNextTo = new ChunkPos(pos.x - chunkWidth, pos.z - chunkWidth);
                                            blockPos = new Vector3(x_t + chunkWidth + 1, y_t, z_t + chunkWidth + 1);
                                        }
                                        else if (x_t > chunkWidth)
                                        {
                                            cpNextTo = new ChunkPos(pos.x + chunkWidth, pos.z);
                                            blockPos = new Vector3(x_t - chunkWidth - 1, y_t, z_t);
                                        }
                                        else if (x_t < 0)
                                        {
                                            cpNextTo = new ChunkPos(pos.x - chunkWidth, pos.z);
                                            blockPos = new Vector3(x_t + chunkWidth + 1, y_t, z_t);
                                        }
                                        else if (z_t > chunkWidth)
                                        {
                                            cpNextTo = new ChunkPos(pos.x, pos.z + chunkWidth);
                                            blockPos = new Vector3(x_t, y_t, z_t - chunkWidth - 1);
                                        }
                                        else if (z_t < 0)
                                        {
                                            cpNextTo = new ChunkPos(pos.x, pos.z - chunkWidth);
                                            blockPos = new Vector3(x_t, y_t, z_t + chunkWidth + 1);
                                        }
                                        if (TerrainGenerator.holdsToGenerate.ContainsKey(cpNextTo))
                                        {
                                            if (!TerrainGenerator.holdsToGenerate[cpNextTo].ContainsKey(blockPos))
                                            {
                                                TerrainGenerator.holdsToGenerate[cpNextTo].Add(blockPos, BlockType.Leaves);
                                            }
                                        }
                                        else
                                        {
                                            TerrainGenerator.holdsToGenerate.Add(cpNextTo, new Dictionary <Vector3, BlockType>()
                                            {
                                                { blockPos, BlockType.Leaves }
                                            });
                                        }
                                    }
                                    else
                                    {
                                        blocks[x_t, y_t, z_t] = BlockType.Leaves;
                                    }
                                }
                            }
                        }
                        iter++;
                    }
                }
            }
        }