コード例 #1
0
    public void Generate()
    {
        poolCur          = 0;
        _seedX           = (float)(RD.NextDouble() * 100.0);
        _seedZ           = (float)(RD.NextDouble() * 100.0);
        int[,] heightMap = new int[size.x, size.y];
        ///////////// generate world
        for (int x = 0; x < size.x; x++)
        {
            for (int z = 0; z < size.y; z++)
            {
                float xSample = (x + _seedX) / _relief;
                float zSample = (z + _seedZ) / _relief;
                float noise   = Mathf.PerlinNoise(xSample, zSample) * 1.2f - 0.2f;
                noise = Mathf.Pow(noise, 2);


                heightMap[x, z] = (int)Mathf.Clamp(Mathf.Floor(_maxHeight * noise), 0, 1000);
                // int y = 0;
            }
        }

        //////////////////
        /// STACK begin
        /// 这里提前定义了两座遗迹的位置,需要在生成地形的时候提前平滑他们所在的位置
        const int TOWER_OUTTER_BORDER = 5, TOWER_INNER_BORDER = 10;

        towerpos1 = RD.NextPosition(size.x / 2 - TOWER_OUTTER_BORDER - TOWER_INNER_BORDER, size.y / 2 - TOWER_OUTTER_BORDER - TOWER_INNER_BORDER) + new Vector2Int(TOWER_OUTTER_BORDER, TOWER_INNER_BORDER + size.y / 2);
        towerpos2 = RD.NextPosition(size.x / 2 - TOWER_OUTTER_BORDER - TOWER_INNER_BORDER, size.y / 2 - TOWER_OUTTER_BORDER - TOWER_INNER_BORDER) + new Vector2Int(TOWER_INNER_BORDER + size.x / 2, TOWER_OUTTER_BORDER);
        /// do lerp
        const int TOWER_IS_HIGHER = 1;
        int       towerpos1height = TOWER_IS_HIGHER + heightMap[towerpos1.x, towerpos1.y];
        int       towerpos2height = TOWER_IS_HIGHER + heightMap[towerpos2.x, towerpos2.y];

        const float roundBorderMin = 7f;
        const float roundBorderMax = 11f;

        for (int x = 0; x < size.x; x++)
        {
            for (int z = 0; z < size.y; z++)
            {
                Vector2Int _cur       = new Vector2Int(x, z);
                float      _magnitude = (_cur - towerpos1).magnitude;
                if (_magnitude < roundBorderMax)
                {
                    heightMap[x, z] = (int)Mathf.SmoothStep(towerpos1height, heightMap[x, z], Mathf.Clamp01((_magnitude - roundBorderMin) / (roundBorderMax - roundBorderMin)));
                }
                else
                {
                    _magnitude = (_cur - towerpos2).magnitude;
                    if (_magnitude < roundBorderMax)
                    {
                        heightMap[x, z] = (int)Mathf.SmoothStep(towerpos2height, heightMap[x, z], Mathf.Clamp01((_magnitude - roundBorderMin) / (roundBorderMax - roundBorderMin)));
                    }
                }
            }
        }
        /// STACK end
        //////////////////

        // 整流一波
        bool changed        = true;
        int  maxChangeCount = 5;

        while (maxChangeCount-- > 0 && changed)
        {
            changed = false;
            for (int x = 0; x < size.x; x++)
            {
                for (int z = 0; z < size.y; z++)
                {
                    int tmp = heightMap[x, z], tc = heightMap[x, z], ts = 1;
                    foreach (var item in GetNeiboursVector(x, z))
                    {
                        tc += heightMap[item.x, item.y];
                        ts++;
                    }
                    int tr = (int)Mathf.Round((tc * 1.0F - 0.1f * (5 - ts)) / ts);
                    // VS: int tr = (int)Mathf.Round((tc * 1.0F / ts - 0.1f * (5 - ts));
                    if (tmp != tr)
                    {
                        changed         = true;
                        heightMap[x, z] = tr;
                    }
                }
            }
        }
        for (int x = 0; x < size.x; x++)
        {
            for (int z = 0; z < size.y; z++)
            {
                GameObject ground = Instantiate(pGround, GameUtils.PositionToTranform(new Vector3Int(x, heightMap[x, z], z)), Quaternion.identity);
                ground.transform.SetParent(transform);
                this.map[x, z]              = ground.GetComponent <TerrainUnit>();
                this.map[x, z].position     = new Vector3Int(x, heightMap[x, z], z);
                this.map[x, z].worldManager = this;
            }
        }



        ///////////// Generate Static Terrains

        /////// Rocks
        int collapseNum = (int)(RD.NextDouble() * 0 + 1);

        // 1. collapse
        while (collapseNum-- > 0)
        {
        }
        PoissonDiscSampler sampler;
        int sampleOffset;

        /////// Voids
        // sampleOffset = 5;// 裁去边框
        // sampler = new PoissonDiscSampler(size.x - 2 * sampleOffset, size.y - 2 * sampleOffset, 5f);// 在少2倍边框区域内随机生成点
        // foreach (Vector2 sample in sampler.Samples())
        // {
        //     var dir = (int)(RD.NextDouble() * 4);
        //     Vector3Int dirVector;
        //     switch (dir)
        //     {
        //         case 0:
        //             dirVector = Vector3Int.right; break;
        //         case 1:
        //             dirVector = Vector3Int.left; break;
        //         case 2:
        //             dirVector = new Vector3Int(0, 0, -1); break;
        //         case 3:
        //         default:
        //             dirVector = new Vector3Int(0, 0, 1); break;
        //     }
        //     int i = 0, maxInter = 100;
        //     bool camPlace = true;
        //     while (maxInter-- > 0 && GetUnit((int)sample.x + i * dirVector.x + sampleOffset,
        //                    (int)sample.y + i * dirVector.z + sampleOffset) != null)
        //     {
        //         if (GetUnit((int)sample.x + i * dirVector.x + sampleOffset,
        //                     (int)sample.y + i * dirVector.z + sampleOffset).type != UnitType.Empty)
        //         {
        //             camPlace = false;
        //             break;
        //         }
        //         i++;
        //     }
        //     if (camPlace)
        //     {
        //         i = 1; maxInter = 100;
        //         while (maxInter-- > 0 && GetUnit((int)sample.x + i * dirVector.x + sampleOffset,
        //                   (int)sample.y + i * dirVector.z + sampleOffset) != null)
        //         {
        //             GetUnit((int)sample.x + i * dirVector.x + sampleOffset,
        //                         (int)sample.y + i * dirVector.z + sampleOffset).SetType(UnitType.Void);

        //             i++;
        //         }
        //     }
        // }

        ///////////// TEMPLATE bfs
        // foreach (var item in SpreadBFS(map[15, 15].position,
        //     (a, b) => ((a.position - b.position).magnitude < 2)
        // ))
        // {
        //     GetUnit(item).SetType(UnitType.Spawn);
        // }
        /////////////
        ///  BuffEffect be = GameObject.Find("TestBuff").GetComponent<BuffEffect>();
        // //buff test
        // be.AttachMesh(BuffEffectManager.GetLineByVectors(SpreadBFS(map[15, 15].position,
        //     (a, b) => ((a.position - b.position).magnitude < 2)
        // )));


        ///////////// generate Mines
        //  http://www.twinklingstar.cn/2013/406/stochastic-distributed-ray-tracing/
        //  Poisson Disk Distribution
        sampleOffset = 2;// 裁去边框
        sampler      = new PoissonDiscSampler(size.x - sampleOffset * 2, size.y - sampleOffset * 2, 14f);
        foreach (Vector2 sample in sampler.Samples())
        {
            // // Instantiate(pGround, new Vector3(sample.x,10,sample.y),Quaternion.identity);
            Vector2Int centerPos = new Vector2Int((int)sample.x + sampleOffset, (int)sample.y + sampleOffset);
            if ((centerPos - towerpos1).magnitude < 4 || (centerPos - towerpos2).magnitude < 4 || (centerPos - new Vector2Int(size.x / 2, size.y / 2)).magnitude < 4)
            {
                continue;
            }
            UnitType[,] mineM = StaticTerrain.NextModule();
            for (int _i = 0; _i < mineM.GetLength(0); _i++)
            {
                for (int _j = 0; _j < mineM.GetLength(1); _j++)
                {
                    if (mineM[_i, _j] != UnitType.Empty)
                    {
                        GetUnit(_i - mineM.GetLength(0) / 2 + centerPos.x, _j - mineM.GetLength(1) / 2 + centerPos.y).SetType(mineM[_i, _j]);
                    }
                }
            }
        }
        /////// Towers
        /** GOTO .Generate():1 */

        UnitType[,] tu1 = StaticTerrain.NextTower();
        for (int _i = 0; _i < tu1.GetLength(0); _i++)
        {
            for (int _j = 0; _j < tu1.GetLength(1); _j++)
            {
                GetUnit(_i - tu1.GetLength(0) / 2 + towerpos1.x, _j - tu1.GetLength(1) / 2 + towerpos1.y).SetType(tu1[_i, _j]);
            }
        }
        UnitType[,] tu2 = StaticTerrain.NextTower();
        for (int _i = 0; _i < tu2.GetLength(0); _i++)
        {
            for (int _j = 0; _j < tu2.GetLength(1); _j++)
            {
                GetUnit(_i - tu2.GetLength(0) / 2 + towerpos2.x, _j - tu2.GetLength(1) / 2 + towerpos2.y).SetType(tu2[_i, _j]);
            }
        }
        /////// Grasses
        sampler = new PoissonDiscSampler(size.x, size.y, 10f);
        foreach (Vector2 sample in sampler.Samples())
        {
            foreach (var item in SpreadBFS(new Vector3Int((int)sample.x, 0, (int)sample.y), (me, him) => (me.position - him.position).magnitude < 2f))
            {
                GetUnit(item).SetBuff(UnitBuffType.INCREASE_GRASS);
            }
        }

        ///////////// generate spawn point & player
        map[size.x / 2, size.y / 2].SetType(UnitType.Spawn);
        playerSpawnPoint = new Vector3(size.x / 2 + 0.5f, 15, (size.y / 2) + 0.5f);
        playerInstance   = Instantiate(playerPrefab, playerSpawnPoint, Quaternion.identity);
    }