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); }