Unityの六角圢マップ氎埪環、䟵食、バむオヌム、円筒圢マップ

パヌト1〜3グリッド、色、セルの高さ

パヌト4〜7粗さ、川、および道路

パヌト8-11氎、地圢、城壁

パヌト12〜15保存ず読み蟌み、テクスチャ、距離

パヌト16〜19道を芋぀ける、プレむダヌチヌム、アニメヌション

パヌト20-23戊争の霧、地図調査、手続き生成

パヌト24〜27氎埪環、䟵食、バむオヌム、円柱地図

パヌト24地域ず䟵食



前のパヌトでは、手続き型マップ生成の基瀎を構築したした。 今回は、土地が発生する可胜性のある堎所を制限し、䟵食を行いたす。

このチュヌトリアルはUnity 2017.1.0で䜜成されたした。


土地を分離しお滑らかにしたす。

地図の境界線


土地をランダムに䞊げるため、土地が地図の端に觊れるこずがありたす。 これは望たしくない堎合がありたす。 氎に制限のある地図には、プレむダヌが端に近づくのを防ぐ自然の障壁が含たれおいたす。 したがっお、地図の端近くの氎䜍より䞊に土地を䞊昇させるこずを犁じるずよいでしょう。

ボヌダヌサむズ


土地は地図の端にどれくらい近いはずですか この質問に察する正しい答えはないため、このパラメヌタヌをカスタマむズ可胜にしたす。 HexMapGeneratorコンポヌネントに2぀のスラむダヌを远加したす。1぀はX軞に沿った゚ッゞに沿った境界線、もう1぀はZ軞に沿った境界線に䜿甚したす。 デフォルト倀の5で0から10たでの間隔を䜿甚しおみたしょう。

  [Range(0, 10)] public int mapBorderX = 5; [Range(0, 10)] public int mapBorderZ = 5; 


マップ境界線スラむダヌ。

土地の䞭心を制限したす


境界線がなければ、すべおのセルが有効です。 境界がある堎合、最小蚱容座暙は増加し、最倧蚱容座暙は枛少したす。 プロットを生成するには蚱容間隔を知る必芁があるため、4぀の敎数フィヌルドを䜿甚しお远跡したしょう。

  int xMin, xMax, zMin, zMax; 

寿叞を䜜成する前に、 GenerateMap制玄を初期化したす。 Random.Range呌び出しのパラメヌタヌずしおこれらの倀を䜿甚するため、実際には最高倀は䟋倖的です。 境界線がない堎合、それらは枬定セルの数に等しいため、マむナス1ではありたせん。

  public void GenerateMap (int x, int z) { 
 for (int i = 0; i < cellCount; i++) { grid.GetCell(i).WaterLevel = waterLevel; } xMin = mapBorderX; xMax = x - mapBorderX; zMin = mapBorderZ; zMax = z - mapBorderZ; CreateLand(); 
 } 

境界線を越えた土地の出珟を厳密に犁止するこずはありたせん。鋭く切り取られた゚ッゞが䜜成されるからです。 代わりに、プロットの生成を開始するために䜿甚されるセルのみを制限したす。 ぀たり、サむトのおおよその䞭心は制限されたすが、サむトの䞀郚は境界゚リアを超えるこずができたす。 これを行うには、 GetRandomCellを倉曎しお、蚱容されるオフセットの範囲内のセルを遞択したす。

  HexCell GetRandomCell () { // return grid.GetCell(Random.Range(0, cellCount)); return grid.GetCell(Random.Range(xMin, xMax), Random.Range(zMin, zMax)); } 





マップの境界は、0×0、5×5、10×10、および0×10です。

すべおのマップパラメヌタヌがデフォルト倀に蚭定されおいる堎合、サむズ5の境界線により、マップの端が土地に觊れないように確実に保護されたす。 ただし、これは保蚌されたせん。 土地は端に近づくこずがあり、いく぀かの堎所で土地に觊れるこずがありたす。

土地が囜境党䜓を暪切る可胜性は、囜境のサむズずサむトの最倧サむズに䟝存したす。 ためらうこずなく、セクションは六角圢のたたです。 半埄のある完党な六角圢 r含む 3r2+3r+1セル。 境界のサむズに等しい半埄を持぀六角圢がある堎合、それらはそれを暪切るこずができたす。 半埄5の完党な六角圢には91個のセルが含たれたす。 デフォルトでは、セクションごずに最倧100セルなので、これは、特に振動がある堎合に、土地が5セルを介しお橋を架けるこずができるこずを意味したす。 これを防ぐには、プロットの最倧サむズを小さくするか、境界線のサむズを倧きくしたす。

六角圢領域のセル数の匏はどのように導出されたすか
半埄が0の堎合、1぀のセルを扱いたす。 䞭心から1の半埄で、6぀の远加のセルがありたす。 6+1。 これらの6぀のセルは、䞭心に接する6぀の䞉角圢の端ず考えるこずができたす。 半埄が2の堎合、これらの䞉角圢に2番目の行が远加されたす。぀たり、䞉角圢でさらに2぀のセルが取埗され、合蚈で 6ドル1 + 2+ 1ドル 。 半埄3の堎合、3番目の行が远加されたす。぀たり、䞉角圢ごずに3぀のセルが远加され、合蚈で 6ドル1 + 2 + 3+ 1ドル 。 などなど。 ぀たり、䞀般的に、匏は次のようになりたす 6sumi=1ri+1=6rr+1/2+1=3rr+1+1=3r2+3r+1。

これをより明確に芋るために、境界サむズを200に蚭定できたす。半埄8の完党な六角圢には217個のセルが含たれるため、土地はマップの端に觊れる可胜性がありたす。 少なくずもデフォルトの境界サむズ倀5を䜿甚する堎合。 境界を10に増やすず、確率は倧幅に䜎䞋したす。



土地区画のサむズは䞀定で200で、地図の境界線は5ず10です。

パンゲア


マップの境界線を増やしお土地の割合を同じに保぀ず、土地が匷制的に小さな領域を圢成するこずに泚意しおください。 この結果、デフォルトで倧きな地図は、単䞀の倧きな土地-超倧陞パンゲア-をいく぀かの小さな島で䜜成する可胜性が非垞に高くなりたす。 境界のサむズが倧きくなるず、この可胜性が高くなり、特定の倀では、超倧陞になるこずがほが保蚌されたす。 ただし、土地の割合が倧きすぎるず、利甚可胜な領域のほずんどがいっぱいになり、その結果、ほが長方圢の土地の塊ができたす。 これを防ぐには、土地の割合を枛らす必芁がありたす。


カヌドの枠線が10の寿叞40。

パンゲアずいう名前はどこから来たのですか
それは䜕幎も前に地球䞊に存圚しおいた最埌の既知の超倧陞の名前でした。 名前はギリシャ語のパンずガむアで構成され、「すべおの自然」たたは「すべおの土地」のようなものを意味したす。


無理なカヌドから守る


目的の土地に到達するたで土地を持ち䞊げ続けるだけで、適切な量の土地を生成したす。 これは、遅かれ早かれ、各セルを氎䜍で䞊げるために機胜したす。 ただし、マップの境界線を䜿甚する堎合、すべおのセルに到達できるわけではありたせん。 高い割合の土地が必芁な堎合、これは発電機の無限の「詊行ず倱敗」に぀ながり、より倚くの土地を調達し、無限のサむクルで行き詰たりたす。 この堎合、アプリケヌションはフリヌズしたすが、これは起こりたせん。

䞍可胜な構成を前もっお確実に芋぀けるこずはできたせんが、無限のサむクルから身を守るこずはできたす。 CreateLand実行されたサむクルの数を単玔に远跡しCreateLand 。 繰り返しが倚すぎる堎合、スタックしおいる可胜性が高く、停止する必芁がありたす。

倧きなマップの堎合、1000回の反埩は蚱容できるように芋え、1䞇回の反埩はすでに䞍合理に思えたす。 そのため、この倀を終了ポむントずしお䜿甚したしょう。

  void CreateLand () { int landBudget = Mathf.RoundToInt(cellCount * landPercentage * 0.01f); // while (landBudget > 0) { for (int guard = 0; landBudget > 0 && guard < 10000; guard++) { int chunkSize = Random.Range(chunkSizeMin, chunkSizeMax - 1); 
 } } 

砎損したマップを取埗した堎合、倚くのセルがすぐに最倧の高さに達するため、10,000回の反埩を実行しおもそれほど時間はかかりたせん。これにより、新しい領域の成長が劚げられたす。

ルヌプを䞭断した埌でも、適切なマップを取埗できたす。 土地の量が足りず、あたりおもしろくないでしょう。 これに関する通知をコン゜ヌルに衚瀺しお、残りのどの土地を䜿甚できなかったかをお知らせしたす。

  void CreateLand () { 
 if (landBudget > 0) { Debug.LogWarning("Failed to use up " + landBudget + " land budget."); } } 


カヌド境界線が10の土地の95は、党額を䜿うこずができたせんでした。

故障したカヌドにはただばら぀きがあるのはなぜですか
海岞線にはばら぀きがありたす。これは、䜜成領域内の高さが高くなりすぎるず、新しい領域では倖偎に成長できないためです。 同じ原則では、区画が最倧の高さに達し、単に欠萜しおいるこずが刀明するたで、区画を土地の小さな領域に成長させるこずはできたせん。 さらに、プロットを䜎くするず、ばら぀きが倧きくなりたす。

ナニティパッケヌゞ

カヌドを分割する


マップの境界線ができたので、マップを基本的に2぀の別々の領域に分割したした。境界線領域ずプロットが䜜成された領域です。 私たちにずっお創造の地域のみが重芁であるため、そのような堎合は1぀の地域の状況ず考えるこずができたす。 リヌゞョンは、単にマップ党䜓をカバヌしおいたせん。 しかし、これが䞍可胜な堎合、地図を土地創造のいく぀かの接続されおいない領域に分割するこずを劚げるものはありたせん。 これにより、倧陞が互いに独立しお圢成され、異なる倧陞が指定されたす。

地図地域


マップの1぀の領域を構造䜓ずしお説明するこずから始めたしょう。 これにより、いく぀かの地域での䜜業が簡玠化されたす。 これのためにMapRegion構造を䜜成しおみたしょう。これには、リヌゞョンの境界フィヌルドのみが含たれおいたす。 HexMapGenerator倖郚ではこの構造を䜿甚しないため、このクラスの内郚でプラむベヌトな内郚構造ずしお定矩できたす。 次に、4぀の敎数フィヌルドを1぀のMapRegionフィヌルドに眮き換えるこずができたす。

 // int xMin, xMax, zMin, zMax; struct MapRegion { public int xMin, xMax, zMin, zMax; } MapRegion region; 

すべおが機胜するためには、 GenerateMap最小倀ず最倧倀のフィヌルドにregion.プレフィックスを远加する必芁がありregion. 。

  region.xMin = mapBorderX; region.xMax = x - mapBorderX; region.zMin = mapBorderZ; region.zMax = z - mapBorderZ; 

たた、 GetRandomCell 。

  HexCell GetRandomCell () { return grid.GetCell( Random.Range(region.xMin, region.xMax), Random.Range(region.zMin, region.zMax) ); } 

いく぀かの地域


耇数の地域をサポヌトするには、1぀のMapRegionフィヌルドMapRegion地域のリストに眮き換えたす。

 // MapRegion region; List<MapRegion> regions; 

この時点で、リヌゞョンを䜜成するための別のメ゜ッドを远加するずよいでしょう。 必芁なリストを䜜成するか、既に存圚する堎合はクリアする必芁がありたす。 その埌、圌は以前に行ったように1぀のリヌゞョンを決定し、それをリストに远加したす。

  void CreateRegions () { if (regions == null) { regions = new List<MapRegion>(); } else { regions.Clear(); } MapRegion region; region.xMin = mapBorderX; region.xMax = grid.cellCountX - mapBorderX; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); } 

GenerateMapでこのメ゜ッドを呌び出したすが、リヌゞョンを盎接䜜成したせん。

 // region.xMin = mapBorderX; // region.xMax = x - mapBorderX; // region.zMin = mapBorderZ; // region.zMax = z - mapBorderZ; CreateRegions(); CreateLand(); 

GetRandomCellが任意の領域でGetRandomCellできるように、 MapRegionパラメヌタヌを指定したす。

  HexCell GetRandomCell (MapRegion region) { return grid.GetCell( Random.Range(region.xMin, region.xMax), Random.Range(region.zMin, region.zMax) ); } 

これで、 RaiseTerraion SinkTerrainずSinkTerrainは、察応する領域をGetRandomCell枡す必芁がありたす。 これを行うには、それぞれにリヌゞョンパラメヌタヌも必芁です。

  int RaiseTerrain (int chunkSize, int budget, MapRegion region) { searchFrontierPhase += 1; HexCell firstCell = GetRandomCell(region); 
 } int SinkTerrain (int chunkSize, int budget, MapRegion region) { searchFrontierPhase += 1; HexCell firstCell = GetRandomCell(region); 
 } 

CreateLandメ゜ッドは、セクションを䞊䞋させる各領域を決定する必芁がありたす。 リヌゞョン間で土地のバランスをずるために、サむクル内のリヌゞョンのリストを繰り返し繰り返したす。

  void CreateLand () { int landBudget = Mathf.RoundToInt(cellCount * landPercentage * 0.01f); for (int guard = 0; landBudget > 0 && guard < 10000; guard++) { for (int i = 0; i < regions.Count; i++) { MapRegion region = regions[i]; int chunkSize = Random.Range(chunkSizeMin, chunkSizeMax - 1); if (Random.value < sinkProbability) { landBudget = SinkTerrain(chunkSize, landBudget, region); } else { landBudget = RaiseTerrain(chunkSize, landBudget, region); } } } if (landBudget > 0) { Debug.LogWarning("Failed to use up " + landBudget + " land budget."); } } 

ただし、プロットの䜎䞋を均等に分散させる必芁がありたす。 これは、すべおの地域でそれらを省略するかどうかを決定しながら行うこずができたす。

  for (int guard = 0; landBudget > 0 && guard < 10000; guard++) { bool sink = Random.value < sinkProbability; for (int i = 0; i < regions.Count; i++) { MapRegion region = regions[i]; int chunkSize = Random.Range(chunkSizeMin, chunkSizeMax - 1); // if (Random.value < sinkProbability) { if (sink) { landBudget = SinkTerrain(chunkSize, landBudget, region); } else { landBudget = RaiseTerrain(chunkSize, landBudget, region); } } } 

最埌に、土地の党量を正確に䜿甚するためには、量がれロになったらすぐにプロセスを停止する必芁がありたす。 これは、リヌゞョンのサむクルのどの段階でも発生する可胜性がありたす。 したがっお、れロサムチェックを内偎のルヌプに移動したす。 実際、このチェックは土地を䞊げた埌にしか実行できたせん。なぜなら、金額を䞋げるずきは決しお䜿われないからです。 完了したら、すぐにCreateLandメ゜ッドを終了できたす。

 // for (int guard = 0; landBudget > 0 && guard < 10000; guard++) { for (int guard = 0; guard < 10000; guard++) { bool sink = Random.value < sinkProbability; for (int i = 0; i < regions.Count; i++) { MapRegion region = regions[i]; int chunkSize = Random.Range(chunkSizeMin, chunkSizeMax - 1); if (sink) { landBudget = SinkTerrain(chunkSize, landBudget, region); } else { landBudget = RaiseTerrain(chunkSize, landBudget, region); if (landBudget == 0) { return; } } } } 

2぀の地域


珟圚、いく぀かの地域のサポヌトがありたすが、私たちはただ1぀だけを求めおいたす。 CreateRegions倉曎しお、マップを垂盎方向に半分に分割したす。 これを行うには、远加された領域のxMax倀を半分にしたす。 次にxMin同じ倀を䜿甚し、再びxMinの元の倀を䜿甚しお、それを2番目の領域ずしお䜿甚したす。

  MapRegion region; region.xMin = mapBorderX; region.xMax = grid.cellCountX / 2; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); region.xMin = grid.cellCountX / 2; region.xMax = grid.cellCountX - mapBorderX; regions.Add(region); 

この段階でカヌドを生成しおも違いはありたせん。 2぀の領域を特定したしたが、それらは1぀の叀い領域ず同じ領域を占めおいたす。 それらを広げるには、それらの間に空きスペヌスを残す必芁がありたす。 これは、マップの境界ず同じ間隔ずデフォルト倀を䜿甚しお、リヌゞョンの境界にスラむダヌを远加するこずで実行できたす。

  [Range(0, 10)] public int regionBorder = 5; 


リヌゞョン境界スラむダヌ。

土地は地域間のスペヌスの䞡偎に圢成できるため、地図の端に土地の橋を䜜る可胜性が高くなりたす。 これを防ぐために、領域の境界を䜿甚しお、分割線ずプロットを開始できる領域の間に土地なしゟヌンを蚭定したす。 これは、隣接する領域間の距離が領域の境界のサむズより2倧きいこずを意味したす。

領域のこの境界を適甚するにxMax最初の領域のxMaxからそれを枛算しxMin 2番目の領域のxMin远加したす。

  MapRegion region; region.xMin = mapBorderX; region.xMax = grid.cellCountX / 2 - regionBorder; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); region.xMin = grid.cellCountX / 2 + regionBorder; region.xMax = grid.cellCountX - mapBorderX; regions.Add(region); 


マップは垂盎方向に2぀の領域に分割されたす。

デフォルト蚭定では、2぀の顕著に分離された領域が䜜成されたすが、1぀の領域ず倧きな地図の境界の堎合のように、正確に2぀の陞地を受け取る保蚌はありたせん。 ほずんどの堎合、2぀の倧きな倧陞で、おそらくいく぀かの島がありたす。 ただし、1぀の地域に2぀以䞊の倧きな島が䜜成される堎合がありたす。 たた、2぀の倧陞が地峡によっお接続される堎合もありたす。

もちろん、XずZを枬定する方法を倉曎するこずにより、マップを氎平方向に分割できたす。2぀の可胜な方向のいずれかをランダムに遞択したしょう。

  MapRegion region; if (Random.value < 0.5f) { region.xMin = mapBorderX; region.xMax = grid.cellCountX / 2 - regionBorder; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); region.xMin = grid.cellCountX / 2 + regionBorder; region.xMax = grid.cellCountX - mapBorderX; regions.Add(region); } else { region.xMin = mapBorderX; region.xMax = grid.cellCountX - mapBorderX; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ / 2 - regionBorder; regions.Add(region); region.zMin = grid.cellCountZ / 2 + regionBorder; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); } 


氎平方向に2぀の領域に分割されたマップ。

幅の広いマップを䜿甚しおいるため、幅が広くお薄い領域が氎平方向に分離しお䜜成されたす。 その結果、これらの地域は、いく぀かの分割された陞地を圢成する可胜性が高くなりたす。

4぀の地域


リヌゞョンの数をカスタマむズ可胜にしお、1〜4぀のリヌゞョンのサポヌトを䜜成したしょう。

  [Range(1, 4)] public int regionCount = 1; 


リヌゞョン数のスラむダヌ。

switchを䜿甚しお、察応するリヌゞョンコヌドの実行を遞択できたす。 デフォルトで䜿甚される1぀の地域のコヌドを繰り返すこずから始め、ケヌス2のために2぀の地域のコヌドを残したす。

  MapRegion region; switch (regionCount) { default: region.xMin = mapBorderX; region.xMax = grid.cellCountX - mapBorderX; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); break; case 2: if (Random.value < 0.5f) { region.xMin = mapBorderX; region.xMax = grid.cellCountX / 2 - regionBorder; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); region.xMin = grid.cellCountX / 2 + regionBorder; region.xMax = grid.cellCountX - mapBorderX; regions.Add(region); } else { region.xMin = mapBorderX; region.xMax = grid.cellCountX - mapBorderX; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ / 2 - regionBorder; regions.Add(region); region.zMin = grid.cellCountZ / 2 + regionBorder; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); } break; } 

switchステヌトメントずは䜕ですか
これは、if-else-if-elseステヌトメントシヌケンスを蚘述する代わりになりたす。 スむッチは倉数に適甚され、どのコヌドを実行する必芁があるかを瀺すためにラベルが䜿甚されたす。 最埌のelseブロックずしお䜿甚されるdefaultラベルもありdefault 。 各オプションは、 breakステヌトメントたたはreturn終了する必芁がありたす。

switchブロックを読みやすい状態に保぀には、通垞、すべおのケヌスを短く、理想的には単䞀のステヌトメントたたはメ゜ッド呌び出しで保持するのが最善です。 リヌゞョンコヌドの䟋ずしおこれは行いたせんが、より興味深いリヌゞョンを䜜成する堎合は、別の方法を䜿甚するこずをお勧めしたす。 䟋

  switch (regionCount) { default: CreateOneRegion(); break; case 2: CreateTwoRegions(); break; case 3: CreateThreeRegions(); break; case 4: CreateFourRegions(); break; } 

3぀の領域は2぀に䌌おいたすが、半分ではなく3぀だけが䜿甚されたす。 この堎合、氎平方向の分離は非垞に狭い領域を䜜成するため、垂盎方向の分離のみのサポヌトを䜜成したした。 その結果、リヌゞョンの境界領域が2倍になっおいるため、新しいサむトを䜜成するためのスペヌスは、2぀のリヌゞョンの堎合よりも少ないこずに泚意しおください。

  switch (regionCount) { default: 
 break; case 2: 
 break; case 3: region.xMin = mapBorderX; region.xMax = grid.cellCountX / 3 - regionBorder; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); region.xMin = grid.cellCountX / 3 + regionBorder; region.xMax = grid.cellCountX * 2 / 3 - regionBorder; regions.Add(region); region.xMin = grid.cellCountX * 2 / 3 + regionBorder; region.xMax = grid.cellCountX - mapBorderX; regions.Add(region); break; } 


3぀の地域。

氎平方向ず垂盎方向の分離を組み合わせお、マップの各コヌナヌに1぀の領域を远加するこずにより、4぀の領域を䜜成できたす。

  switch (regionCount) { 
 case 4: region.xMin = mapBorderX; region.xMax = grid.cellCountX / 2 - regionBorder; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ / 2 - regionBorder; regions.Add(region); region.xMin = grid.cellCountX / 2 + regionBorder; region.xMax = grid.cellCountX - mapBorderX; regions.Add(region); region.zMin = grid.cellCountZ / 2 + regionBorder; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); region.xMin = mapBorderX; region.xMax = grid.cellCountX / 2 - regionBorder; regions.Add(region); break; } } 


4぀の地域。

ここで䜿甚されるアプロヌチは、マップを分割する最も簡単な方法です。 土地の質量によっおほが同じ地域を生成し、その倉動性はマップ生成の他のパラメヌタヌによっお制埡されたす。 ただし、マップが盎線に分割されおいるこずは垞に明らかです。 コントロヌルが必芁なほど、結果の倖芳は少なくなりたす。 したがっお、ゲヌムプレむにほが等しい領域が必芁な堎合、これは正垞です。 しかし、最も倚様で無制限の土地が必芁な堎合は、1぀の地域の助けを借りお造らなければなりたせん。

さらに、マップを分割する他の方法がありたす。 盎線だけに限定するこずはできたせん。 同じサむズのリヌゞョンを䜿甚する必芁はなく、マップ党䜓をカバヌする必芁もありたせん。 穎をあけるこずができたす。 地域の亀差を蚱可したり、地域間の土地の分垃を倉曎したりするこずもできたす。 さらに、各地域に独自のゞェネレヌタヌパラメヌタヌを蚭定するこずもできたすただし、より耇雑ですが。たずえば、地図䞊に倧きな倧陞ず列島を眮くこずができたす。

ナニティパッケヌゞ

䟵食


これたでのずころ、生成したすべおのカヌドはかなり倱瀌で壊れおいたした。 本圓のレリヌフはこのように芋えるかもしれたせんが、時間が経぀に぀れおたすたす滑らかになり、その鋭い郚分は䟵食により鈍くなっおしたいたす。マップを改善するために、この䟵食プロセスを適甚できたす。これは、荒い土地を䜜成した埌、別の方法で行いたす。

  public void GenerateMap (int x, int z) { 
 CreateRegions(); CreateLand(); ErodeLand(); SetTerrainType(); 
 } 
 void ErodeLand () {} 

䟵食率


時間が経過するほど、浞食が倚くなりたす。したがっお、䟵食は氞続的ではなく、カスタマむズ可胜にする必芁がありたす。少なくずも、䟵食はれロであり、これは以前に䜜成されたマップに察応したす。最倧の䟵食は包括的です。぀たり、䟵食力をさらに加えおも地圢は倉化したせん。぀たり、䟵食パラメヌタヌは0〜100の割合である必芁があり、デフォルトでは50になりたす。

  [Range(0, 100)] public int erosionPercentage = 50; 


䟵食スラむダヌ。

䟵食砎壊现胞の怜玢


䟵食により、レリヌフがより滑らかになりたす。私たちの堎合、唯䞀の鋭い郚分は厖です。したがっお、それらは䟵食プロセスのタヌゲットになりたす。厖が存圚する堎合、浞食は最終的に斜面に倉わるたでそれを枛らす必芁がありたす。これは退屈な地圢に぀ながるため、斜面を滑らかにしたせん。これを行うには、厖の䞊にあるセルを特定し、高さを䜎くする必芁がありたす。これらは䟵食されやすい现胞です。

セルが䟵食されやすいかどうかを刀断するメ゜ッドを䜜成したしょう。圌は高さの十分に倧きな違いを芋぀けるたでセルの隣人をチェックするこずによっおこれを決定したす。厖は少なくずも1぀たたは2぀のレベルの高さの差を必芁ずするため、1぀たたは耇数の隣接セルが少なくずも2ステップ䞋にある堎合、セルは䟵食の圱響を受けたす。そのような隣人がいない堎合、セルは䟵食を受けるこずができたせん。

  bool IsErodible (HexCell cell) { int erodibleElevation = cell.Elevation - 2; for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = cell.GetNeighbor(d); if (neighbor && neighbor.Elevation <= erodibleElevation) { return true; } } return false; } 

このメ゜ッドを䜿甚しErodeLandお、すべおのセルをルヌプし、すべおの䟵食しやすいセルを䞀時リストに曞き蟌むこずができたす。

  void ErodeLand () { List<HexCell> erodibleCells = ListPool<HexCell>.Get(); for (int i = 0; i < cellCount; i++) { HexCell cell = grid.GetCell(i); if (IsErodible(cell)) { erodibleCells.Add(cell); } } ListPool<HexCell>.Add(erodibleCells); } 

䟵食しやすい现胞の総数がわかったら、䟵食の割合を䜿甚しお、残りの䟵食しやすい现胞の数を決定できたす。たずえば、パヌセンテヌゞが50の堎合、元の数量の半分が残るたでセルを䟵食する必芁がありたす。パヌセンテヌゞが100の堎合、䟵食を起こしやすい现胞をすべお砎壊するたで停止したせん。

  void ErodeLand () { List<HexCell> erodibleCells = ListPool<HexCell>.Get(); for (int i = 0; i < cellCount; i++) { 
 } int targetErodibleCount = (int)(erodibleCells.Count * (100 - erosionPercentage) * 0.01f); ListPool<HexCell>.Add(erodibleCells); } 

䟵食されやすい土地のセルだけを考慮すべきではありたせんか
. , , .

セル削枛


玠朎なアプロヌチから始めお、䟵食によっお砎壊された现胞の高さを単玔に枛らすず、もはや䟵食されにくくなるず仮定したす。これが圓おはたる堎合、リストからランダムなセルを取り出し、高さを枛らしおからリストから削陀するこずができたす。䟵食を受けやすい必芁な现胞数に達するたで、この操䜜を繰り返したす。

  int targetErodibleCount = (int)(erodibleCells.Count * (100 - erosionPercentage) * 0.01f); while (erodibleCells.Count > targetErodibleCount) { int index = Random.Range(0, erodibleCells.Count); HexCell cell = erodibleCells[index]; cell.Elevation -= 1; erodibleCells.Remove(cell); } ListPool<HexCell>.Add(erodibleCells); 

必芁な怜玢を防ぐためerodibleCells.Removeに、リストの最埌の珟圚のセルを䞊曞きし、最埌の芁玠を削陀したす。私たちはただ圌らの順序を気にしたせん。

 // erodibleCells.Remove(cell); erodibleCells[index] = erodibleCells[erodibleCells.Count - 1]; erodibleCells.RemoveAt(erodibleCells.Count - 1); 



䟵食しやすい现胞の0および100の玠朎な枛少、シヌドマップ1957632474。

䟵食远跡


単玔なアプロヌチにより、䟵食を適甚できたすが、適切な皋床には適甚できたせん。これは、高さが1぀枛少した埌もセルが䟵食を受け続ける可胜性があるためです。したがっお、䟵食の傟向がなくなったずきにのみリストからセルを削陀したす。

  if (!IsErodible(cell)) { erodibleCells[index] = erodibleCells[erodibleCells.Count - 1]; erodibleCells.RemoveAt(erodibleCells.Count - 1); } 


リスト内の䟵食しやすいセルを維持しながら、100䟵食。

したがっお、䟵食ははるかに匷くなりたすが、100を䜿甚しおも、すべおの厖を取り陀くこずはできたせん。その理由は、セルの高さを䜎くするず、その隣のセルの1぀が䟵食を受けやすくなる可胜性があるためです。したがっお、結果ずしお、䟵食を起こしやすい现胞が元より倚くなる可胜性がありたす。

セルを䞋げた埌、すべおの隣接セルを確認する必芁がありたす。䟵食の傟向があるが、ただリストにない堎合は、そこに远加する必芁がありたす。

  if (!IsErodible(cell)) { erodibleCells[index] = erodibleCells[erodibleCells.Count - 1]; erodibleCells.RemoveAt(erodibleCells.Count - 1); } for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = cell.GetNeighbor(d); if ( neighbor && IsErodible(neighbor) && !erodibleCells.Contains(neighbor) ) { erodibleCells.Add(neighbor); } } 


䟵食されたセルはすべお省略されたす。

倚くの土地を節玄したす


これで、すべおの厖が消えるたで䟵食プロセスを継続できたす。これは土地に倧きく圱響したす。土地の倧郚分は消滅し、必芁な土地の割合よりもはるかに少なくなりたした。これは、マップから土地を削陀しおいるために発生したした。

真の䟵食は物質を砎壊したせん。圌女はある堎所からそれを取り出し、別の堎所に眮きたす。同じこずができたす。 1぀のセルが枛少するず、その隣のセルを1぀䞊げる必芁がありたす。実際、1レベルの高さが䞋のセルに転送されたす。これにより、単玔にスムヌゞングしながら、マップの党高が節玄されたす。

これを実珟するには、䟵食補品をどこに移動するかを決定する必芁がありたす。これが䟵食のタヌゲットになりたす。䟵食されるセルのタヌゲットポむントを決定するメ゜ッドを䜜成したしょう。このセルにはブレヌクが含たれおいるため、このブレヌクの䞋にあるセルをタヌゲットずしお遞択するのが論理的です。しかし、䟵食されやすいセルにはいく぀かのブレヌクがある可胜性があるため、すべおの隣接セルをチェックし、すべおの候補を䞀時リストに入れおから、ランダムに1぀を遞択したす。

  HexCell GetErosionTarget (HexCell cell) { List<HexCell> candidates = ListPool<HexCell>.Get(); int erodibleElevation = cell.Elevation - 2; for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = cell.GetNeighbor(d); if (neighbor && neighbor.Elevation <= erodibleElevation) { candidates.Add(neighbor); } } HexCell target = candidates[Random.Range(0, candidates.Count)]; ListPool<HexCell>.Add(candidates); return target; } 

ErodeLand我々はすぐに䟵食されたセルを遞択した埌、暙的现胞を定矩したす。次に、セルの高さを次々に増枛したす。この堎合、タヌゲットセル自䜓が䟵食を受けやすくなる可胜性がありたすが、新しく䟵食されたセルの隣接セルをチェックするず、この状況は解決されたす。

  HexCell cell = erodibleCells[index]; HexCell targetCell = GetErosionTarget(cell); cell.Elevation -= 1; targetCell.Elevation += 1; if (!IsErodible(cell)) { erodibleCells[index] = erodibleCells[erodibleCells.Count - 1]; erodibleCells.RemoveAt(erodibleCells.Count - 1); } 

タヌゲットセルを䞊げたので、このセルの隣接郚分の䞀郚が䟵食を受けなくなる可胜性がありたす。それらを回っお、䟵食を受けやすいかどうかを確認する必芁がありたす。そうでない堎合でも、リストに含たれおいる堎合は、リストから削陀する必芁がありたす。

  for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = cell.GetNeighbor(d); 
 } for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = targetCell.GetNeighbor(d); if ( neighbor && !IsErodible(neighbor) && erodibleCells.Contains(neighbor) ) { erodibleCells.Remove(neighbor); } } 


土地の質量を維持しながら100の䟵食。

䟵食により、地圢がより滑らかになり、䞀郚の゚リアが䜎くなり、他の゚リアが高くなりたす。その結果、土地の質量は増加したり狭くなったりする可胜性がありたす。これにより、土地の割合がいずれかの方向に数パヌセント倉化する可胜性がありたすが、重倧な逞脱はほずんど発生したせん。぀たり、適甚する䟵食が倧きいほど、結果ずしお生じる土地の割合に察する制埡が少なくなりたす。

加速䟵食


䟵食アルゎリズムの有効性を実際に気にする必芁はありたせんが、簡単な改善を行うこずができたす。最初に、䟵食したセルが䟵食可胜かどうかを明瀺的にチェックしたす。そうでない堎合は、基本的にリストから削陀したす。したがっお、タヌゲットセルの隣接セルを走査するずきにこのセルのチェックをスキップできたす。

  for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = targetCell.GetNeighbor(d); if ( neighbor && neighbor != cell && !IsErodible(neighbor) && erodibleCells.Contains(neighbor) ) { erodibleCells.Remove(neighbor); } } 

第二に、タヌゲットセルの間にブレヌクがある堎合にのみ、タヌゲットセルのネむバヌをチェックする必芁がありたしたが、今では必芁ありたせん。これは、隣接セルがタヌゲットセルより1ステップ高い堎合にのみ発生したす。そうである堎合、隣人はリストにあるこずが保蚌されるので、これをチェックする必芁はありたせん。぀たり、䞍必芁な怜玢をスキップできたす。

  HexCell neighbor = targetCell.GetNeighbor(d); if ( neighbor && neighbor != cell && neighbor.Elevation == targetCell.Elevation + 1 && !IsErodible(neighbor) // && erodibleCells.Contains(neighbor) ) { erodibleCells.Remove(neighbor); } 

第䞉に、䟵食しやすいセルの隣接をチェックするずきに、同様のトリックを䜿甚できたす。それらの間に厖がある堎合、隣人は䟵食を受けやすいです。調べるために、を呌び出す必芁はありたせんIsErodible。

  HexCell neighbor = cell.GetNeighbor(d); if ( neighbor && neighbor.Elevation == cell.Elevation + 2 && // IsErodible(neighbor) && !erodibleCells.Contains(neighbor) ) { erodibleCells.Add(neighbor); } 

ただし、タヌゲットセルが䟵食の圱響を受けやすいかどうかを確認する必芁がありたすが、䞊蚘のサむクルではこれが行われなくなりたした。したがっお、タヌゲットセルに察しおこれを明瀺的に実行したす。

  if (!IsErodible(cell)) { erodibleCells[index] = erodibleCells[erodibleCells.Count - 1]; erodibleCells.RemoveAt(erodibleCells.Count - 1); } for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { 
 } if (IsErodible(targetCell) && !erodibleCells.Contains(targetCell)) { erodibleCells.Add(targetCell); } for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { 
 } 

これで、生成された厖の最初の数に察する必芁な割合に、浞食を十分迅速に適甚できたす。タヌゲットセルが䟵食傟向リストに远加される堎所をわずかに倉曎したずいう事実により、結果は最適化前の結果からわずかに倉曎されおいるこずに泚意しおください。





25、50、75、および100の䟵食。

たた、海岞の圢状が倉曎されたにもかかわらず、トポロゞが根本的に倉曎されおいないこずにも泚意しおください。陞地は通垞、接続たたは分離されたたたです。小さな島だけが完党にdrれるこずができたす。レリヌフの詳现は平滑化されおいたすが、䞀般的な圢匏は同じたたです。狭い関節が消えたり、少し成長したりする堎合がありたす。小さな隙間がわずかに埋められたり拡倧したりするこずがありたす。したがっお、䟵食は分割された領域を匷く結び付けたせん。


4぀の完党に䟵食された領域はただ分離されたたたです。

ナニティパッケヌゞ

パヌト25氎埪環



このパヌトでは、土地に湿床を远加したす。

このチュヌトリアルはUnity 2017.3.0で䜜成されたした。


氎埪環を䜿甚しおバむオヌムを決定したす。

雲


この時点たで、マップ生成アルゎリズムはセルの高さのみを倉曎しおいたした。セル間の最倧の違いは、セルが氎の䞊か䞋かでした。さたざたな皮類の地圢を定矩できたすが、これは高さの単玔な芖芚化です。地域の気候を考慮しお、地圢のタむプを指定する方が良いでしょう。

地球の気候は非垞に耇雑なシステムです。幞いなこずに、珟実的な気候シミュレヌションを䜜成する必芁はありたせん。十分に自然に芋えるものが必芁です。気候の最も重芁な偎面は氎埪環です。なぜなら、動怍物は生き残るために液䜓の氎を必芁ずするからです。枩床も非垞に重芁ですが、今のずころ、私たちは本質的に地球の枩床を䞀定に保ち、湿床のみを倉化させ、氎に焊点を圓おおいたす。

氎埪環は、環境内の氎の動きを衚したす。簡単に蚀えば、池は蒞発し、雚が雲になり、再び雚が池に流れ蟌みたす。システムにはさらに倚くの偎面がありたすが、これらの手順をシミュレヌトするだけで、マップ䞊に自然な倖芳の氎の分垃を䜜成するのに十分な堎合がありたす。

デヌタの可芖化


このシミュレヌションに入る前に、関連するデヌタを盎接確認するず䟿利です。これを行うには、テレむンシェヌダヌを倉曎したす。切り替え可胜なプロパティを远加したす。これは、通垞のレリヌフテクスチャの代わりに生のマップデヌタを衚瀺するデヌタ芖芚化モヌドに切り替えるこずができたす。これは、キヌワヌドを定矩する切り替え可胜な属性を持぀floatプロパティを䜿甚しお実装できたす。このため、マテリアルむンスペクタヌにキヌワヌドの定矩を制埡するフラグずしお衚瀺されたす。プロパティ自䜓の名前は重芁ではありたせん。キヌワヌドにのみ興味がありたす。SHOW_MAP_DATAを䜿甚しおいたす。

  Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Terrain Texture Array", 2DArray) = "white" {} _GridTex ("Grid Texture", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Specular ("Specular", Color) = (0.2, 0.2, 0.2) _BackgroundColor ("Background Color", Color) = (0,0,0) [Toggle(SHOW_MAP_DATA)] _ShowMapData ("Show Map Data", Float) = 0 } 


地図デヌタの衚瀺に切り替えたす。

キヌワヌドサポヌトを有効にするシェヌダヌ関数を远加したす。

  #pragma multi_compile _ GRID_ON #pragma multi_compile _ HEX_MAP_EDIT_MODE #pragma shader_feature SHOW_MAP_DATA 

残りの救枈デヌタの堎合ず同様に、単䞀のフロヌトを衚瀺したす。これを実珟するために、キヌワヌドが定矩されたずきに構造にInputフィヌルドを远加したすmapData。

  struct Input { float4 color : COLOR; float3 worldPos; float3 terrain; float4 visibility; #if defined(SHOW_MAP_DATA) float mapData; #endif }; 

頂点プログラムでは、これらのセルのZチャネルを䜿甚しおmapData、垞にセル間で補間されるようにを埋めたす。

  void vert (inout appdata_full v, out Input data) { 
 #if defined(SHOW_MAP_DATA) data.mapData = cell0.z * v.color.x + cell1.z * v.color.y + cell2.z * v.color.z; #endif } 

セルデヌタを衚瀺する必芁がある堎合は、通垞の色ではなく、アルベドフラグメントずしお盎接䜿甚したす。デヌタをレンダリングするずきにグリッドがただオンになるように、グリッドを乗算したす。

  void surf (Input IN, inout SurfaceOutputStandardSpecular o) { 
 o.Albedo = c.rgb * grid * _Color * explored; #if defined(SHOW_MAP_DATA) o.Albedo = IN.mapData * grid; #endif 
 } 

実際にデヌタをシェヌダヌに転送したす。HexCellShaderDataテクスチャデヌタの青いチャネルに䜕かを曞き蟌むメ゜ッドに远加する必芁がありたす。デヌタは、0〜1に制限された単䞀の浮動小数点倀です。

  public void SetMapData (HexCell cell, float data) { cellTextureData[cell.Index].b = data < 0f ? (byte)0 : (data < 1f ? (byte)(data * 255f) : (byte)255); enabled = true; } 

ただし、この決定は研究システムに圱響したす。青色のチャネルデヌタ倀255は、セルの可芖性が移行䞭であるこずを瀺すために䜿甚されたす。このシステムが匕き続き機胜するためには、最倧倀ずしおバむト倀254を䜿甚する必芁がありたす。デタッチメントの移動はすべおのカヌドデヌタを消去するこずに泚意しおください。

  cellTextureData[cell.Index].b = data < 0f ? (byte)0 : (data < 1f ? (byte)(data * 254f) : (byte)254); 

同じ名前でにメ゜ッドを远加しHexCellたす。芁求をシェヌダヌデヌタに転送したす。

  public void SetMapData (float data) { ShaderData.SetMapData(this, data); } 

コヌドの動䜜を確認するにHexMapGenerator.SetTerrainTypeは、マップの各セルのデヌタを蚭定するように倉曎したす。0〜1の間隔で敎数から浮動小数点数に倉換された高さを芖芚化したす。これは、セルの高さから最小の高さを匕いお、最倧の高さから最小の倀を匕いた倀で陀算するこずにより行われたす。陀算浮動小数点を䜜成したしょう。

  void SetTerrainType () { for (int i = 0; i < cellCount; i++) { 
 cell.SetMapData( (cell.Elevation - elevationMinimum) / (float)(elevationMaximum - elevationMinimum) ); } } 

これで、テレむンマテリアルアセットの[ マップデヌタを衚瀺]チェックボックスを䜿甚しお、通垞の地圢ずデヌタの芖芚化を切り替えるこずができたす。



マップ1208905299、通垞の地圢、高さの芖芚化。

気候の創造


気候をシミュレヌトするには、気候デヌタを远跡する必芁がありたす。マップは個別のセルで構成されおいるため、各セルには固有の気候がありたす。ClimateDataすべおの関連デヌタを保存する構造を䜜成したす。もちろん、セル自䜓にデヌタを远加できたすが、マップを生成する堎合にのみ䜿甚したす。したがっお、それらを個別に保存したす。これはHexMapGenerator、のように内郚でこの構造䜓を定矩できるこずを意味したすMapRegion。雲の远跡から始めたす。これは、単䞀のフロヌトフィヌルドを䜿甚しお実装できたす。

  struct ClimateData { public float clouds; } 

リストを远加しお、すべおのセルの気候デヌタを远跡したす。

  List<ClimateData> climate = new List<ClimateData>(); 

次に、気候マップを䜜成する方法が必芁です。たず、気候ゟヌンのリストをクリアしおから、各セルに1぀の芁玠を远加する必芁がありたす。初期の気候デヌタは単玔にれロです。これは暙準のコンストラクタを䜿甚しお実珟できたすClimateData。
  void CreateClimate () { climate.Clear(); ClimateData initialData = new ClimateData(); for (int i = 0; i < cellCount; i++) { climate.Add(initialData); } } 

気候は、地圢䟵食にさらされた埌、救揎の皮類を蚭定する前に䜜成する必芁がありたす。実際には、䟵食は䞻に気候の䞀郚である空気ず氎の動きによっお匕き起こされたすが、これをシミュレヌトしたせん。

  public void GenerateMap (int x, int z) { 
 CreateRegions(); CreateLand(); ErodeLand(); CreateClimate(); SetTerrainType(); 
 } 

SetTerrainTypeセルの高さの代わりにクラりドデヌタを衚瀺できるように倉曎したす。最初は、黒いカヌドのように芋えたす。

  void SetTerrainType () { for (int i = 0; i < cellCount; i++) { 
 cell.SetMapData(climate[i].clouds); } } 

気候倉動


気候シミュレヌションの最初のステップは蒞発です。どのくらいの氎分を蒞発させるべきですかスラむダヌを䜿甚しおこの倀を制埡したしょう。倀0は蒞発なし、1-最倧蒞発を意味したす。デフォルトでは、0.5を䜿甚したす。

  [Range(0f, 1f)] public float evaporation = 0.5f; 


蒞発スラむダヌ。

1぀のセルの気候を圢成するための具䜓的な方法をもう1぀䜜成しおみたしょう。パラメヌタずしおセルむンデックスを指定し、それを䜿甚しお、察応するセルずその気候デヌタを取埗したす。セルが氎面䞋にある堎合、私たちは蒞発しなければならない貯氎池を扱っおいたす。蒞気をすぐに雲に倉え露点ず結露を無芖、セル雲の倀に蒞発を盎接远加したす。これが完了したら、気候デヌタをリストにコピヌしたす。

  void EvolveClimate (int cellIndex) { HexCell cell = grid.GetCell(cellIndex); ClimateData cellClimate = climate[cellIndex]; if (cell.IsUnderwater) { cellClimate.clouds += evaporation; } climate[cellIndex] = cellClimate; } 

の各セルに察しおこのメ​​゜ッドを呌び出しCreateClimateたす。

  void CreateClimate () { 
 for (int i = 0; i < cellCount; i++) { EvolveClimate(i); } } 

しかし、これでは十分ではありたせん。耇雑なシミュレヌションを䜜成するには、现胞の気候を数回圢成する必芁がありたす。これを頻繁に行うほど、結果は良くなりたす。定数倀を遞択しおみたしょう。40サむクル䜿甚したす。

  for (int cycle = 0; cycle < 40; cycle++) { for (int i = 0; i < cellCount; i++) { EvolveClimate(i); } } 

なぜなら、氎で満たされた现胞の䞊の雲の倀を増やすだけであるので、その結果、黒い土地ず癜い貯氎池を手に入れるからです。


氎䞊での蒞発。

雲の散乱


特にたすたす倚くの氎が蒞発するずき、雲は垞に䞀箇所にあるわけではありたせん。圧力差は空気を動かし、それが颚の圢で珟れ、雲も動きたす。

支配的な颚向がない堎合、平均しお现胞の雲はすべおの方向に均等に分散し、隣接する现胞に珟れたす。次のサむクルで新しい雲を生成するずき、セル内のすべおの雲をその隣に分散させたしょう。぀たり、各ネむバヌはセルクラりドから6分の1を受信し、その埌れロたで局所的に枛少したす。

  if (cell.IsUnderwater) { cellClimate.clouds += evaporation; } float cloudDispersal = cellClimate.clouds * (1f / 6f); cellClimate.clouds = 0f; climate[cellIndex] = cellClimate; 

隣人に実際に雲を远加するには、茪になっお呚りを回り、気候デヌタを取埗し、雲の倀を増やしお、リストにコピヌし盎す必芁がありたす。

  float cloudDispersal = cellClimate.clouds * (1f / 6f); for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = cell.GetNeighbor(d); if (!neighbor) { continue; } ClimateData neighborClimate = climate[neighbor.Index]; neighborClimate.clouds += cloudDispersal; climate[neighbor.Index] = neighborClimate; } cellClimate.clouds = 0f; 


散乱雲。

これにより、各サむクルで氎䞭のセルがたすたす倚くの雲を地球芏暡の気候に远加するため、ほが癜いマップが䜜成されたす。最初のサむクルの埌、氎の近くの陞地のセルにも分散する必芁がある雲がありたす。このプロセスは、マップの倧郚分が雲で芆われるたで続きたす。デフォルトパラメヌタを䜿甚したマップ1208905299の堎合、北東郚の倧芏暡な土地の内郚のみが完党に芆われたたたでした。

池は無限の数の雲を生成できるこずに泚意しおください。氎䜍は気候シミュレヌションの䞀郚ではありたせん。実際には、貯氎池は、ほが蒞発速床で氎が逆流するためにのみ保存されたす。぀たり、郚分的な氎埪環のみをシミュレヌトしたす。これは正垞ですが、シミュレヌションが長く行われるほど、気候により倚くの氎が远加されるこずを理解する必芁がありたす。これたでのずころ、氎の損倱はマップの端でのみ発生し、隣接する゚リアがないために散圚する雲が倱われたす。

地図の䞊郚、特に右䞊のセルで氎の損倱を確認できたす。最埌のセルには雲がたったくありたせん。なぜなら、雲は気候が圢成される最埌のセルだからです。圌女はただ隣人から雲を受け取っおいたせん。

すべおの现胞の気候が䞊行しお圢成されるべきではないでしょうか
, . - , . 40 . - , .

降氎量


氎は氞遠に冷たいたたではありたせん。ある時点で、圌女は再び地面に萜ちるはずです。これは通垞、雚の圢で起こりたすが、時には雪、ail、湿った雪になるこずもありたす。これはすべお、䞀般に降氎量ず呌ばれたす。雲の消倱の倧きさず速床は倧きく異なりたすが、カスタムの党球降雚速床を䜿甚したす。倀0は降氎がないこずを意味し、倀1はすべおの雲が即座に消えるこずを意味したす。デフォルト倀は0.25です。これは、各サむクルで雲の4分の1が消えるこずを意味したす。

  [Range(0f, 1f)] public float precipitationFactor = 0.25f; 


降氎係数スラむダヌ。

蒞発埌、雲の散乱前の降氎量をシミュレヌトしたす。これは、貯氎池から蒞発した氎の䞀郚がすぐに沈殿するこずを意味するため、散乱雲の数は枛少したす。陞地では、降氎は雲の消倱に぀ながりたす。

  if (cell.IsUnderwater) { cellClimate.clouds += evaporation; } float precipitation = cellClimate.clouds * precipitationFactor; cellClimate.clouds -= precipitation; float cloudDispersal = cellClimate.clouds * (1f / 6f); 


消える雲。

今、各サむクルで雲の25を砎壊するず、土地は再びほが黒になりたす。雲はわずか数ステップ内陞に移動し、その埌は芋えなくなりたす。

ナニティパッケヌゞ

湿床


降雚は雲を砎壊したすが、気候から氎を陀去すべきではありたせん。地面に萜ちた埌、氎は別の状態でのみ保存されたす。それは倚くの圢で存圚する可胜性があり、それらをたずめお湿床を考慮したす。

湿床远跡


雲ず湿床の2぀の氎の状態を远跡するこずにより、気候モデルを改善する予定です。これを実装するには、ClimateDataフィヌルドに远加したすmoisture。

  struct ClimateData { public float clouds, moisture; } 

最も䞀般化された圢匏では、蒞発は、少なくずも単玔な気候モデルでは、氎分を雲に倉換するプロセスです。これは、蒞発が䞀定の倀ではなく、別の芁因であるべきであるこずを意味したす。したがっお、リファクタリングず名前倉曎を実行evaporationしevaporationFactorたす。

  [Range(0f, 1f)] public float evaporationFactor = 0.5f; 

セルが氎䞭にある堎合、湿床レベルが1であるこずを通知したす。これは、蒞発が蒞発係数に等しいこずを意味したす。しかし今では、寿叞の现胞から蒞発するこずもできたす。この堎合、蒞発を蚈算し、湿床からそれを差し匕き、結果を雲に远加する必芁がありたす。その埌、湿床に降氎量が远加されたす。

  if (cell.IsUnderwater) { cellClimate.moisture = 1f; cellClimate.clouds += evaporationFactor; } else { float evaporation = cellClimate.moisture * evaporationFactor; cellClimate.moisture -= evaporation; cellClimate.clouds += evaporation; } float precipitation = cellClimate.clouds * precipitationFactor; cellClimate.clouds -= precipitation; cellClimate.moisture += precipitation; 

雲は陞地からの蒞発によっお支えられおいるため、雲をさらに内陞に移動できたす。珟圚、倧郚分の土地は灰色になっおいたす。


湿床が蒞発する雲。 雲の代わりに湿床を衚瀺

するSetTerrainTypeように倉曎しおみたしょう。これは、レリヌフのタむプを決定するために䜿甚するためです。

  cell.SetMapData(climate[i].moisture); 


湿床衚瀺。

この時点で、湿床は雲に非垞に䌌おいたすただし、すべおの氎䞭のセルが癜であるこずを陀いおが、すぐに倉化したす。

降雚流出


氎分が现胞から出る唯䞀の方法は蒞発だけではありたせん。氎埪環は、土地に远加された氎分の倧郚分が䜕らかの圢で氎になっおしたうこずを瀺しおいたす。最も顕著なプロセスは、重力の圱響䞋での土地䞊の氎の流れです。実際の河川をシミュレヌトするのではなく、カスタム降雚流出係数を䜿甚したす。それは、より䜎い゚リアに排氎する氎の割合を瀺したす。デフォルトでは25になりたす。

  [Range(0f, 1f)] public float runoffFactor = 0.25f; 


ドレむンスラむダヌ。

川を生成したせんか
.

氎の流出は雲の散乱のように機胜したすが、3぀の違いがありたす。たず、すべおの氎分がセルから陀去されるわけではありたせん。第二に、雲ではなく湿気を運びたす。第䞉に、それは䞋降したす。぀たり、身長が䜎い隣人だけになりたす。排氎係数は、隣接するすべおが䜎い堎合にセルから流出する氎分の量を衚したすが、倚くの堎合、氎分は少なくなりたす。これは、䞋に隣人が芋぀かった堎合にのみセルの湿床を䞋げるこずを意味したす。

  float cloudDispersal = cellClimate.clouds * (1f / 6f); float runoff = cellClimate.moisture * runoffFactor * (1f / 6f); for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = cell.GetNeighbor(d); if (!neighbor) { continue; } ClimateData neighborClimate = climate[neighbor.Index]; neighborClimate.clouds += cloudDispersal; int elevationDelta = neighbor.Elevation - cell.Elevation; if (elevationDelta < 0) { cellClimate.moisture -= runoff; neighborClimate.moisture += runoff; } climate[neighbor.Index] = neighborClimate; } 


より䜎い高さたで排氎する。

結果ずしお、高いセルは氎分を䜎い方に䌝達するため、湿床の分垃はより倚様になりたす。たた、沿岞のセルは氎分を氎䞭のセルに排出するため、沿岞のセルの氎分ははるかに少なくなりたす。この効果を匱めるには、セルが䜎いかどうか、぀たり芋かけの高さを刀断するずきに氎䜍を䜿甚する必芁もありたす。

  int elevationDelta = neighbor.ViewElevation - cell.ViewElevation; 


目に芋える高さを䜿甚したす。

浞透


氎は流れ萜ちるだけでなく、広がり、平らな地圢を浞透し、氎域に隣接する土地に吞収されたす。この効果はほずんど効果がないかもしれたせんが、湿床の分垃を滑らかにするのに圹立ちたすので、シミュレヌションに远加したしょう。デフォルトで0.125に等しいカスタム係数を䜜成しおみたしょう。

  [Range(0f, 1f)] public float seepageFactor = 0.125f; 


挏れスラむダヌ。

浞透はドレむンに䌌おいたすが、隣接セルの高さがセル自䜓ず同じ堎合に䜿甚されたす。

  float runoff = cellClimate.moisture * runoffFactor * (1f / 6f); float seepage = cellClimate.moisture * seepageFactor * (1f / 6f); for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { 
 int elevationDelta = neighbor.ViewElevation - cell.ViewElevation; if (elevationDelta < 0) { cellClimate.moisture -= runoff; neighborClimate.moisture += runoff; } else if (elevationDelta == 0) { cellClimate.moisture -= seepage; neighborClimate.moisture += seepage; } climate[neighbor.Index] = neighborClimate; } 


少し挏れを远加したした。

ナニティパッケヌゞ

雚の圱


私たちはすでに氎埪環の䟡倀あるシミュレヌションを䜜成したしたが、気候の違いを最も明確に瀺す雚の陰がないため、あたり面癜くありたせん。雚の圱は、近隣の地域ず比べお降雚量が著しく少ない地域です。山が雲がそれらに到達するのを劚げるため、そのような領域が存圚したす。それらの䜜成には、高い山ず支配的な颚向が必芁です。

颚


支配的な颚向をシミュレヌションに远加するこずから始めたしょう。支配的な颚の方向は地球の衚面で倧きく異なりたすが、カスタマむズ可胜なグロヌバルな颚の方向で管理したす。デフォルトで北西を䜿甚したしょう。さらに、颚力を1〜10の範囲でデフォルト倀の4に調敎可胜にしたす。

  public HexDirection windDirection = HexDirection.NW; [Range(1f, 10f)] public float windStrength = 4f; 


颚の方向ず匷さ。

支配的な颚の匷さは、雲の党䜓的な分散に察しお衚されたす。颚力が1の堎合、散乱はすべおの方向で同じです。2の堎合、散乱は他の方向よりも颚の方向で2高くなりたす。これを行うには、クラりド散垃匏の陀数を倉曎したす。6個ではなく、5個に颚力を加えたものになりたす。

  float cloudDispersal = cellClimate.clouds * (1f / (5f + windStrength)); 

さらに、颚の方向は、颚が吹く方向を決定したす。したがっお、散乱の䞻な方向ずしお反察方向を䜿甚する必芁がありたす。

  HexDirection mainDispersalDirection = windDirection.Opposite(); float cloudDispersal = cellClimate.clouds * (1f / (5f + windStrength)); 

これで、近傍が散乱の䞻な方向にあるかどうかを確認できたす。もしそうなら、雲の散乱に颚の力を掛けなければなりたせん。

  ClimateData neighborClimate = climate[neighbor.Index]; if (d == mainDispersalDirection) { neighborClimate.clouds += cloudDispersal * windStrength; } else { neighborClimate.clouds += cloudDispersal; } 


北西颚、フォヌス4。

支配的な颚は、土地党䜓に氎分の方向分垃を远加したす。颚が匷いほど、効果は匷くなりたす。

絶察高さ


雚の圱を取埗する2番目の芁玠は山です。私たちは、自然にも同様に山があるずいう厳密な分類はありたせん。絶察的な高さのみが重芁です。実際、空気が山の䞊を移動するず、空気は山に匷制的に䞊昇し、冷华され、氎分が少なくなる可胜性があり、空気が山を通過する前に降氎が発生したす。その結果、反察偎では、也燥した空気、぀たり雚の圱が埗られたす。

最も重芁なこずは、空気が䞊昇するほど、空気が少なくなるこずです。シミュレヌションでは、これを各セルの最倧クラりド倀の匷制的な制限ずしお想像できたす。可芖セルの高さが高いほど、この最倧倀は䜎くなりたす。これを行う最も簡単な方法は、最倧倀を1マむナス芋かけの高さを最倧高さで割った倀に蚭定するこずです。しかし、実際には、最倧でマむナス1で陀算したしょう。これにより、雲のごく䞀郚が最高のセルを通過するこずもできたす。降氎量を蚈算した埌、散乱する前にこの最倧倀を割り圓おたす。

  float precipitation = cellClimate.clouds * precipitationFactor; cellClimate.clouds -= precipitation; cellClimate.moisture += precipitation; float cloudMaximum = 1f - cell.ViewElevation / (elevationMaximum + 1f); HexDirection mainDispersalDirection = windDirection.Opposite(); 

その結果、蚱容されるよりも倚くの雲が埗られた堎合、䜙分な雲を単に湿床に倉換したす。実際、これは実際の山で起こるように、远加の降氎量を远加する方法です。

  float cloudMaximum = 1f - cell.ViewElevation / (elevationMaximum + 1f); if (cellClimate.clouds > cloudMaximum) { cellClimate.moisture += cellClimate.clouds - cloudMaximum; cellClimate.clouds = cloudMaximum; } 


高地が原因の雚の圱。

ナニティパッケヌゞ

シミュレヌションを完了したす


この段階では、すでに氎埪環の非垞に高品質な郚分シミュレヌションが行われおいたす。それを少し敎理しお、セルのレリヌフのタむプを決定するために適甚しおみたしょう。

䞊列蚈算


ネタバレで前述したように、セルが圢成される順序はシミュレヌション結果に圱響したす。理想的には、これはすべきではなく、実際にすべおのセルを䞊行しお圢成したす。これは、圢成の珟圚の段階のすべおの倉化を気候の2番目のリストに適甚するこずによっお、するこずができたすnextClimate。

  List<ClimateData> climate = new List<ClimateData>(); List<ClimateData> nextClimate = new List<ClimateData>(); 

他のすべおの人ず同様に、このリストをクリアしお初期化したす。その埌、各サむクルでリストを亀換したす。この堎合、シミュレヌションは2぀のリストを亀互に䜿甚し、珟圚ず次の気候デヌタを適甚したす。

  void CreateClimate () { climate.Clear(); nextClimate.Clear(); ClimateData initialData = new ClimateData(); for (int i = 0; i < cellCount; i++) { climate.Add(initialData); nextClimate.Add(initialData); } for (int cycle = 0; cycle < 40; cycle++) { for (int i = 0; i < cellCount; i++) { EvolveClimate(i); } List<ClimateData> swap = climate; climate = nextClimate; nextClimate = swap; } } 

セルが隣の気候に圱響を䞎える堎合、珟圚のデヌタではなく、次の気候デヌタを倉曎する必芁がありたす。

  for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = cell.GetNeighbor(d); if (!neighbor) { continue; } ClimateData neighborClimate = nextClimate[neighbor.Index]; 
 nextClimate[neighbor.Index] = neighborClimate; } 

そしお、次の気候デヌタを珟圚の気候リストにコピヌする代わりに、次の気候デヌタを取埗し、それらに珟圚の湿床を远加しお、すべおを次のリストにコピヌしたす。その埌、珟圚のリストのデヌタをリセットしお、次のサむクルで曎新されるようにしたす。

 // cellClimate.clouds = 0f; ClimateData nextCellClimate = nextClimate[cellIndex]; nextCellClimate.moisture += cellClimate.moisture; nextClimate[cellIndex] = nextCellClimate; climate[cellIndex] = new ClimateData(); 

これを行っおいる間、湿床レベルを最倧1に蚭定しお、陞䞊の现胞が氎䞭よりも濡れないようにしたす。

  nextCellClimate.moisture += cellClimate.moisture; if (nextCellClimate.moisture > 1f) { nextCellClimate.moisture = 1f; } nextClimate[cellIndex] = nextCellClimate; 


䞊列コンピュヌティング。

゜ヌス湿床


シミュレヌションでは、特に土地の割合が高いず、也燥した土地が倚くなりすぎる可胜性がありたす。画像を改善するために、デフォルトの0.1のカスタム初期湿床レベルを远加できたす。

  [Range(0f, 1f)] public float startingMoisture = 0.1f; 


䞊は元の湿床のスラむダヌです。

この倀は初期気候リストの湿床に䜿甚したすが、以䞋には䜿甚したせん。

  ClimateData initialData = new ClimateData(); initialData.moisture = startingMoisture; ClimateData clearData = new ClimateData(); for (int i = 0; i < cellCount; i++) { climate.Add(initialData); nextClimate.Add(clearData); } 


元の湿床で。

バむオヌムの定矩


最埌に、セルリリヌフのタむプを蚭定するために、高さの代わりに湿床を䜿甚したす。完党に也燥した土地には雪を䜿甚し、也燥した地域には雪を䜿甚したす。次に、石、十分に湿気のある草、氎が飜和した氎面䞋の现胞に土地を䜿甚したす。0.2の増分で5぀の間隔を䜿甚する最も簡単な方法。

  void SetTerrainType () { for (int i = 0; i < cellCount; i++) { HexCell cell = grid.GetCell(i); float moisture = climate[i].moisture; if (!cell.IsUnderwater) { if (moisture < 0.2f) { cell.TerrainTypeIndex = 4; } else if (moisture < 0.4f) { cell.TerrainTypeIndex = 0; } else if (moisture < 0.6f) { cell.TerrainTypeIndex = 3; } else if (moisture < 0.8f) { cell.TerrainTypeIndex = 1; } else { cell.TerrainTypeIndex = 2; } } else { cell.TerrainTypeIndex = 2; } cell.SetMapData(moisture); } } 


バむオヌム。

均䞀な分垃を䜿甚する堎合、結果はあたり良くなく、䞍自然に芋えたす。0.05、0.12、0.28、0.85など、他のしきい倀を䜿甚するこずをお勧めしたす。

  if (moisture < 0.05f) { cell.TerrainTypeIndex = 4; } else if (moisture < 0.12f) { cell.TerrainTypeIndex = 0; } else if (moisture < 0.28f) { cell.TerrainTypeIndex = 3; } else if (moisture < 0.85f) { cell.TerrainTypeIndex = 1; } 


倉曎されたバむオヌム。

ナニティパッケヌゞ

パヌト26バむオヌムず川



このパヌトでは、氎埪環を河川ず気枩で補完し、さらに興味深いバむオヌムを现胞に割り圓おたす。

チュヌトリアルはUnity 2017.3.0p3を䜿甚しお䜜成されたした。


熱ず氎が地図を掻気づけたす。

川の䞖代


川は氎埪環の結果です。実際、それらは、チャネル䟵食の助けを借りお匕き裂かれた排氎によっお圢成されたす。これは、セルのシンクの倀に基づいお川を远加できるこずを意味したす。ただし、これは実際の川に䌌たものが埗られるこずを保蚌するものではありたせん。川を始めるずき、それは可胜な限り倚くの现胞を通っお流れなければなりたせん。これは、现胞を䞊行しお凊理する氎埪環のシミュレヌションずは䞀臎したせん。さらに、通垞、マップ䞊の河川の数の制埡が必芁です。

川は非垞に異なるため、個別に生成したす。氎埪環シミュレヌションの結果を䜿甚しお川の䜍眮を特定したすが、川はシミュレヌションに圱響したせん。

なぜ川の流れが時々間違っおいるのですか
TriangulateWaterShore , . , . , , . , . , , . («»).

  void TriangulateWaterShore ( HexDirection direction, HexCell cell, HexCell neighbor, Vector3 center ) { 
 if (cell.HasRiverThroughEdge(direction)) { TriangulateEstuary( e1, e2, cell.HasIncomingRiver && cell.IncomingRiver == direction, indices ); } 
 } 

高湿床セル


マップでは、セルに川がある堎合ずない堎合がありたす。さらに、分岐たたは接続できたす。珟実には、川ははるかに柔軟性がありたすが、倧きな川だけを䜜成するこの近䌌倀で察凊する必芁がありたす。最も重芁なこずは、ランダムに遞択される倧きな川の始たりの䜍眮を決定する必芁があるこずです。

川は氎を必芁ずするため、川の氎源は湿床の高いセル内になければなりたせん。しかし、これでは十分ではありたせん。川は斜面を流れ萜ちるので、理想的には源の高さを倧きくする必芁がありたす。氎䜍より䞊のセルが高ければ高いほど、川の氎源の圹割のより良い候補になりたす。セルの高さを最倧の高さで割るこずにより、これをマップデヌタずしお芖芚化できたす。結果が氎䜍に察しお埗られるように、分割する前に䞡方の高さからそれを差し匕きたす。

  void SetTerrainType () { for (int i = 0; i < cellCount; i++) { 
 float data = (float)(cell.Elevation - waterLevel) / (elevationMaximum - waterLevel); cell.SetMapData(data); } } 



湿床ず高床。デフォルト蚭定の倧きなカヌド番号1208905299。

最適な候補は、高湿床ず高さの䞡方を持぀セルです。これらの基準を乗算するこずにより、これらの基準を組み合わせるこずができたす。結果は、河川の氎源の適合床たたは重量の倀になりたす。

  float data = moisture * (cell.Elevation - waterLevel) / (elevationMaximum - waterLevel); cell.SetMapData(data); 


河川の氎源の重み。

理想的には、これらの重みを䜿甚しお、゜ヌスセルのランダム遞択を拒吊したす。正しい重みでリストを䜜成しお遞択するこずはできたすが、これは重芁なアプロヌチであり、生成プロセスの速床が䜎䞋したす。 4぀のレベルに分けられた重芁床のより単玔な分類で十分です。最初の候補は、倀が0.75を超える重みになりたす。良い候補者の重みは0.5からです。適栌な候補者は0.25を超えおいたす。他のすべおのセルは砎棄されたす。それがグラフィカルにどのように芋えるかを芋おみたしょう。

  float data = moisture * (cell.Elevation - waterLevel) / (elevationMaximum - waterLevel); if (data > 0.75f) { cell.SetMapData(1f); } else if (data > 0.5f) { cell.SetMapData(0.5f); } else if (data > 0.25f) { cell.SetMapData(0.25f); } // cell.SetMapData(data); 


河川源の重みのカテゎリ。

この分類スキヌムを䜿甚するず、マップの最も湿気の倚い地域に氎源を持぀河川が埗られる可胜性がありたす。それでも、比范的也燥した地域や䜎い地域で河川を造る可胜性は残っおおり、倉動性が高たりたす。これらの基準に基づいおセルのリストを埋める

メ゜ッドCreateRiversを远加したす。適栌なセルはこのリストに1回、良奜なセルは2回、䞻芁な候補は4回远加されたす。氎䞭のセルは垞に砎棄されるため、確認するこずはできたせん。

  void CreateRivers () { List<HexCell> riverOrigins = ListPool<HexCell>.Get(); for (int i = 0; i < cellCount; i++) { HexCell cell = grid.GetCell(i); if (cell.IsUnderwater) { continue; } ClimateData data = climate[i]; float weight = data.moisture * (cell.Elevation - waterLevel) / (elevationMaximum - waterLevel); if (weight > 0.75f) { riverOrigins.Add(cell); riverOrigins.Add(cell); } if (weight > 0.5f) { riverOrigins.Add(cell); } if (weight > 0.25f) { riverOrigins.Add(cell); } } ListPool<HexCell>.Add(riverOrigins); } 

このメ゜ッドはCreateClimate、湿床デヌタを利甚できるようにするために埌で呌び出す必芁がありたす。

  public void GenerateMap (int x, int z) { 
 CreateRegions(); CreateLand(); ErodeLand(); CreateClimate(); CreateRivers(); SetTerrainType(); 
 } 

分類が完了するず、地図䞊のデヌタの芖芚化を取り陀くこずができたす。

  void SetTerrainType () { for (int i = 0; i < cellCount; i++) { 
 // float data = // moisture * (cell.Elevation - waterLevel) / // (elevationMaximum - waterLevel); // if (data > 0.6f) { // cell.SetMapData(1f); // } // else if (data > 0.4f) { // cell.SetMapData(0.5f); // } // else if (data > 0.2f) { // cell.SetMapData(0.25f); // } } } 

リバヌポむント


いく぀の川が必芁ですかこのパラメヌタヌはカスタマむズ可胜でなければなりたせん。河川の長さはさたざたであるため、河川を収容する陞地セルの数を決定する河川ポむントを䜿甚しお河川を制埡する方が論理的です。最倧20、デフォルト倀10のパヌセンテヌゞでそれらを衚珟したしょう。寿叞の割合ず同様に、これは目暙倀であり、保蚌倀ではありたせん。その結果、適切な土地をカバヌするには短すぎる候補者や川が少なすぎる可胜性がありたす。そのため、最倧パヌセンテヌゞは倧きすぎおはいけたせん。

  [Range(0, 20)] public int riverPercentage = 10; 


スラむダヌパヌセントの川。

セルの数ずしお衚される河川ポむントを決定するには、で生成された陞䞊セルの数を芚えおおく必芁がありたすCreateLand。

  int cellCount, landCells; 
 void CreateLand () { int landBudget = Mathf.RoundToInt(cellCount * landPercentage * 0.01f); landCells = landBudget; for (int guard = 0; guard < 10000; guard++) { 
 } if (landBudget > 0) { Debug.LogWarning("Failed to use up " + landBudget + " land budget."); landCells -= landBudget; } } 

内郚では、CreateRiversで行うのず同じ方法で河川ポむントの数を蚈算できたすCreateLand。

  void CreateRivers () { List<HexCell> riverOrigins = ListPool<HexCell>.Get(); for (int i = 0; i < cellCount; i++) { 
 } int riverBudget = Mathf.RoundToInt(landCells * riverPercentage * 0.01f); ListPool<HexCell>.Add(riverOrigins); } 

さらに、ポむントず゜ヌスセルがただある間、元のリストからランダムなセルを取埗および削陀し続けたす。ポむントの数が完了するず、コン゜ヌルに譊告が衚瀺されたす。

  int riverBudget = Mathf.RoundToInt(landCells * riverPercentage * 0.01f); while (riverBudget > 0 && riverOrigins.Count > 0) { int index = Random.Range(0, riverOrigins.Count); int lastIndex = riverOrigins.Count - 1; HexCell origin = riverOrigins[index]; riverOrigins[index] = riverOrigins[lastIndex]; riverOrigins.RemoveAt(lastIndex); } if (riverBudget > 0) { Debug.LogWarning("Failed to use up river budget."); } 

さらに、川を盎接䜜成する方法を远加したす。パラメヌタヌずしお、圌は初期セルが必芁であり、完了埌、川の長さを返す必芁がありたす。長されロを返すメ゜ッドを保存するこずから始めたす。

  int CreateRiver (HexCell origin) { int length = 0; return length; } 

で远加したサむクルの最埌にこのメ゜ッドを呌び出しCreateRivers、残りのポむントの数を枛らしたす。遞択したセルに川が流れおいない堎合にのみ、新しい川が䜜成されるようにしたす。

  while (riverBudget > 0 && riverOrigins.Count > 0) { 
 if (!origin.HasRiver) { riverBudget -= CreateRiver(origin); } } 

珟圚の川


海たたは他の氎域に流れる川を䜜成するこずは論理的です。゜ヌスから開始するず、すぐに長さ1が取埗されたす。その埌、ランダムな近傍を遞択しお長さを増やしたす。氎䞭セルに到達するたで移動を続けたす。

  int CreateRiver (HexCell origin) { int length = 1; HexCell cell = origin; while (!cell.IsUnderwater) { HexDirection direction = (HexDirection)Random.Range(0, 6); cell.SetOutgoingRiver(direction); length += 1; cell = cell.GetNeighbor(direction); } return length; } 


ランダムな川。

このような玠朎なアプロヌチの結果ずしお、䞻に以前に生成された川の眮き換えにより、ランダムに散らばった川の砎片が埗られたす。隣人が実際に存圚するかどうかを確認しないため、これぱラヌに぀ながるこずさえありたす。サむクルのすべおの方向をチェックし、そこに隣人がいるこずを確認する必芁がありたす。そうである堎合、この方向を朜圚的なフロヌ方向のリストに远加したすが、これは川がこの隣をただ流れおいない堎合のみです。次に、このリストからランダムな倀を遞択したす。

  List<HexDirection> flowDirections = new List<HexDirection>(); 
 int CreateRiver (HexCell origin) { int length = 1; HexCell cell = origin; while (!cell.IsUnderwater) { flowDirections.Clear(); for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = cell.GetNeighbor(d); if (!neighbor || neighbor.HasRiver) { continue; } flowDirections.Add(d); } HexDirection direction = // (HexDirection)Random.Range(0, 6); flowDirections[Random.Range(0, flowDirections.Count)]; cell.SetOutgoingRiver(direction); length += 1; cell = cell.GetNeighbor(direction); } return length; } 

この新しいアプロヌチでは、利甚可胜なフロヌ方向がれロになる堎合がありたす。これが発生するず、川はそれ以䞊流れるこずができなくなり、終了する必芁がありたす。この時点で長さが1の堎合、これは元のセルから挏れるこずができなかったこずを意味したす。぀たり、川がたったくない可胜性がありたす。この堎合、川の長さはれロです。

  flowDirections.Clear(); for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { 
 } if (flowDirections.Count == 0) { return length > 1 ? length : 0; } 


保存された川。

走り去る


これで、䜜成枈みの川を保存できたすが、川の孀立した断片を取埗できたす。これは、高さを無芖しおいるために発生したす。川をより高い高さたで匷制的に流すたびに、HexCell.SetOutgoingRiverこの詊みを䞭断し、川の断裂に至りたした。したがっお、川を䞊に流す方向もスキップする必芁がありたす。

  if (!neighbor || neighbor.HasRiver) { continue; } int delta = neighbor.Elevation - cell.Elevation; if (delta > 0) { continue; } flowDirections.Add(d); 


流れる川。

そのため、川の倚くの断片を取り陀きたすが、いく぀かはただ残っおいたす。この瞬間から、最もmostい川を取り陀くこずは掗緎の問題になりたす。そもそも、川はできるだけ早く流れるこずを奜みたす。圌らは必ずしも最短ルヌトを遞択するずは限りたせんが、この可胜性は高くなりたす。これをシミュレヌトするために、リストに䞋方向を3回远加したす。

  if (delta > 0) { continue; } if (delta < 0) { flowDirections.Add(d); flowDirections.Add(d); flowDirections.Add(d); } flowDirections.Add(d); 

急カヌブを避ける


流䞋に加えお、氎にも慣性がありたす。川は、急に急に曲がるよりも、たっすぐに流れるか、わずかに曲がる傟向がありたす。川の最埌の方向を远跡するこずで、この歪みを远加できたす。電流の朜圚的な方向がこの方向から倧きく逞脱しおいない堎合は、リストに再床远加したす。これは゜ヌスにずっお問題ではないため、垞に远加し盎したす。

  int CreateRiver (HexCell origin) { int length = 1; HexCell cell = origin; HexDirection direction = HexDirection.NE; while (!cell.IsUnderwater) { flowDirections.Clear(); for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { 
 if (delta < 0) { flowDirections.Add(d); flowDirections.Add(d); flowDirections.Add(d); } if ( length == 1 || (d != direction.Next2() && d != direction.Previous2()) ) { flowDirections.Add(d); } flowDirections.Add(d); } if (flowDirections.Count == 0) { return length > 1 ? length : 0; } // HexDirection direction = direction = flowDirections[Random.Range(0, flowDirections.Count)]; cell.SetOutgoingRiver(direction); length += 1; cell = cell.GetNeighbor(direction); } return length; } 

これにより、川がゞグザグに芋える可胜性が倧幅に䜎䞋したす。


急旋回が少ない。

河川合流点


川は、以前に䜜成された川の氎源のすぐ隣を流れるこずがありたす。この川の氎源がより高い高床にない堎合、新しい川が叀い川に流れ蟌むず刀断できたす。その結果、2぀の隣接する川ではなく、1぀の長い川が埗られたす。

これを行うには、入っおくる川がある堎合、たたは珟圚の川の氎源である堎合にのみ、隣人を通過させたす。この方向が䞊向いおいないず刀断したため、倖向きの川があるかどうかを確認したす。もしあれば、再び叀い川を芋぀けたした。これはめったに起こらないので、他の近隣の氎​​源をチェックするこずはせず、すぐに川を合流させたす。

  HexCell neighbor = cell.GetNeighbor(d); // if (!neighbor || neighbor.HasRiver) { // continue; // } if (!neighbor || neighbor == origin || neighbor.HasIncomingRiver) { continue; } int delta = neighbor.Elevation - cell.Elevation; if (delta > 0) { continue; } if (neighbor.HasOutgoingRiver) { cell.SetOutgoingRiver(d); return length; } 



プヌルの前埌の川。

距離を保぀


゜ヌスロヌルの適切な候補者は通垞䞀緒にグルヌプ化されるため、川のクラスタヌを取埗したす。さらに、貯氎池のすぐ近くで氎源をずる川があり、長さ1の川ができたす。氎源を分配しお、川たたは貯氎池に隣接する氎を捚おるこずができたす。私たちはこれを内郚のルヌプで遞択された゜ヌスの隣人をバむパスしたすCreateRivers。ルヌルに違反しおいる隣人を芋぀けた堎合、゜ヌスは私たちに合わず、スキップする必芁がありたす。

  while (riverBudget > 0 && riverOrigins.Count > 0) { int index = Random.Range(0, riverOrigins.Count); int lastIndex = riverOrigins.Count - 1; HexCell origin = riverOrigins[index]; riverOrigins[index] = riverOrigins[lastIndex]; riverOrigins.RemoveAt(lastIndex); if (!origin.HasRiver) { bool isValidOrigin = true; for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = origin.GetNeighbor(d); if (neighbor && (neighbor.HasRiver || neighbor.IsUnderwater)) { isValidOrigin = false; break; } } if (isValidOrigin) { riverBudget -= CreateRiver(origin); } } 

たた、川は盞次いで流れるが、より広い地域をカバヌする傟向がある。



距離なしでそれず。

川を湖で終わらせる


すべおの川が貯氎池に到達するわけではなく、枓谷で動けなくなったり、他の川に阻たれたりしたす。倚くの堎合、実際の川も消えおいるように芋えるため、これは特に問題ではありたせん。これは、たずえば、地䞋に流れたり、湿地に分散したり、也燥したりする堎合に発生する可胜性がありたす。私たちの川はこれを芖芚化できないため、単玔に終わりたす。

ただし、このようなケヌスの数を最小限に抑えるこずを詊みるこずができたす。川を合流させたり、川を䞊に流したりするこずはできたせんが、実際にはよく芋られる湖で終わるようにするこずはできたす。このためにCreateRiver動かなくなった堎合、セル内の氎䜍を䞊げる必芁がありたす。この可胜性は、このセルの近隣の最小高さに䟝存したす。したがっお、近隣を調査するずきにこれを远跡するには、コヌドを少し倉曎する必芁がありたす。

  while (!cell.IsUnderwater) { int minNeighborElevation = int.MaxValue; flowDirections.Clear(); for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = cell.GetNeighbor(d); // if (!neighbor || neighbor == origin || neighbor.HasIncomingRiver) { // continue; // } if (!neighbor) { continue; } if (neighbor.Elevation < minNeighborElevation) { minNeighborElevation = neighbor.Elevation; } if (neighbor == origin || neighbor.HasIncomingRiver) { continue; } int delta = neighbor.Elevation - cell.Elevation; if (delta > 0) { continue; } 
 } 
 } 

立ち埀生しおいる堎合は、たず、ただ゜ヌスにいるかどうかを確認する必芁がありたす。はいの堎合、リバヌをキャンセルしたす。それ以倖の堎合、すべおの隣接セルが少なくずも珟圚のセルず同じかどうかを確認したす。もしそうなら、このレベルたで氎を䞊げるこずができたす。これにより、セルの高さが同じレベルのたたでない限り、1぀のセルから湖が䜜成されたす。その堎合、単玔に氎䜍より1レベル䞋の高さを割り圓おたす。

  if (flowDirections.Count == 0) { // return length > 1 ? length : 0; if (length == 1) { return 0; } if (minNeighborElevation >= cell.Elevation) { cell.WaterLevel = minNeighborElevation; if (minNeighborElevation == cell.Elevation) { cell.Elevation = minNeighborElevation - 1; } } break; } 



湖のない川ず湖のある川の端。この堎合、川の割合は20です。

マップを生成するために䜿甚される氎䜍を超える氎䞭セルがある堎合があるこずに泚意しおください。圌らは海抜の湖を瀺したす。

远加の湖


立ち埀生しおいない堎合でも、湖を䜜成するこずもできたす。これにより、川が湖に出入りする可胜性がありたす。立ち埀生しおいない堎合、湖を䜜成するには、氎䜍を䞊げおから珟圚のセルの高さを䞊げ、セルの高さを䞋げたす。これは、近隣の最小高さが少なくずも珟圚のセルの高さに等しい堎合にのみ適甚されたす。これは、川のサむクルの終わりに、次のセルに進む前に行いたす。

  while (!cell.IsUnderwater) { 
 if (minNeighborElevation >= cell.Elevation) { cell.WaterLevel = cell.Elevation; cell.Elevation -= 1; } cell = cell.GetNeighbor(direction); } 



远加の湖なしで、それらず共に。

いく぀かの湖は矎しいですが、無制限に倚くの湖を䜜成できたす。したがっお、远加の湖のカスタム確率を远加し、デフォルト倀を0.25にしたす。

  [Range(0f, 1f)] public float extraLakeProbability = 0.25f; 

可胜であれば、圌女は远加の湖を生成する可胜性を制埡したす。

  if ( minNeighborElevation >= cell.Elevation && Random.value < extraLakeProbability ) { cell.WaterLevel = cell.Elevation; cell.Elevation -= 1; } 



远加の湖。

耇数のセルを持぀湖を䜜成するのはどうですか
, , , . . : . , . , , , .

ナニティパッケヌゞ

枩床


氎は现胞のバむオヌムを決定できる芁因の1぀にすぎたせん。もう1぀の重芁な芁玠は枩床です。氎のシミュレヌションのように枩床の流れず拡散をシミュレヌトできたすが、興味深い気候を䜜成するには、1぀の耇雑な芁玠のみが必芁です。したがっお、枩床を単玔に保ち、各セルに蚭定しおみたしょう。

枩床ず緯床


枩床に察する最倧の圱響は緯床です。赀道では暑く、極では寒く、䞡極の間はスムヌズに移行したす。DetermineTemperature特定のセルの枩床を返すメ゜ッドを䜜成したしょう。開始するには、セルのZ座暙を次元Zで陀算しお緯床ずしお䜿甚し、この倀を枩床ずしお䜿甚したす。

  float DetermineTemperature (HexCell cell) { float latitude = (float)cell.coordinates.Z / grid.cellCountZ; return latitude; } 

枩床を定矩し、SetTerrainTypeマップデヌタずしお䜿甚したす。

  void SetTerrainType () { for (int i = 0; i < cellCount; i++) { HexCell cell = grid.GetCell(i); float temperature = DetermineTemperature(cell); cell.SetMapData(temperature); float moisture = climate[i].moisture; 
 } } 


枩床ずしおの緯床、南半球。

䞋から䞊に向かっお線圢の枩床募配が増加したす。これを䜿甚しお、南半球をシミュレヌトし、䞋郚に極を、䞊郚に赀道を配眮できたす。しかし、半球党䜓を蚘述する必芁はありたせん。枩床差が小さいか、たったく差がない堎合、面積を小さくするこずができたす。これを行うために、䜎枩ず高枩をカスタマむズ可胜にしたす。これらの枩床を0〜1の範囲で蚭定し、極倀をデフォルト倀ずしお䜿甚したす。

  [Range(0f, 1f)] public float lowTemperature = 0f; [Range(0f, 1f)] public float highTemperature = 1f; 


枩床スラむダヌ。

補間噚ずしお緯床を䜿甚しお、線圢補間を䜿甚しお枩床範囲を適甚したす。緯床は0から1たでの倀ずしお衚されるため、を䜿甚できたすMathf.LerpUnclamped。

  float DetermineTemperature (HexCell cell) { float latitude = (float)cell.coordinates.Z / grid.cellCountZ; float temperature = Mathf.LerpUnclamped(lowTemperature, highTemperature, latitude); return temperature; } 

䜎枩は必ずしも高枩より䜎いわけではないこずに泚意しおください。必芁に応じお、それらを裏返すこずができたす。

半球


これで、枩床を取るず南半球、おそらく北半球をシミュレヌトできたす。ただし、半球間を切り替えるには別の蚭定オプションを䜿甚する方がはるかに䟿利です。列挙ずそのフィヌルドを䜜成したしょう。したがっお、䞡方の半球を䜜成するオプションも远加したす。これはデフォルトで適甚可胜です。

  public enum HemisphereMode { Both, North, South } public HemisphereMode hemisphere; 


半球の遞択。

北半球が必芁な堎合は、1から枛算するこずで緯床を単玔に反転できたす。䞡方の半球をシミュレヌトするには、極を地図の䞊䞋に、赀道を䞭倮に配眮する必芁がありたす。これを行うには、緯床を2倍にしたす。䞋半球は正しく凊理され、䞊の半球は1〜2の緯床になりたす。これを修正するには、1を超えるず2から緯床を匕きたす。

  float DetermineTemperature (HexCell cell) { float latitude = (float)cell.coordinates.Z / grid.cellCountZ; if (hemisphere == HemisphereMode.Both) { latitude *= 2f; if (latitude > 1f) { latitude = 2f - latitude; } } else if (hemisphere == HemisphereMode.North) { latitude = 1f - latitude; } float temperature = Mathf.LerpUnclamped(lowTemperature, highTemperature, latitude); return temperature; } 


䞡方の半球。

これにより、赀道が寒く、極が暖かく、゚キゟチックなマップを䜜成できる可胜性が生たれたす。

寒いほど高い


緯床に加えお、枩床も高床によっお倧きく圱響されたす。平均しお、登るほど寒くなりたす。河川候補で行ったように、これを芁因に倉えるこずができたす。この堎合、セルの高さを䜿甚したす。さらに、このむンゞケヌタは高さずずもに枛少したす。぀たり、1から高さを氎䜍に察する最倧倀で割った倀に等しくなりたす。最高レベルのむンゞケヌタヌがれロにならないように、陀数に远加したす。次に、このむンゞケヌタを䜿甚しお枩床をスケヌリングしたす。

  float temperature = Mathf.LerpUnclamped(lowTemperature, highTemperature, latitude); temperature *= 1f - (cell.ViewElevation - waterLevel) / (elevationMaximum - waterLevel + 1f); return temperature; 


高さは枩床に圱響したす。

枩床倉動


ランダムな枩床倉動を远加するこずで、枩床募配の単玔さを目立たなくするこずができたす。より珟実的にするための小さなチャンスですが、倉動が倧きすぎるず、圌らはarbitrary意的に芋えたす。枩床倉動の力をカスタマむズ可胜にしお、デフォルト倀0.1で最倧枩床偏差ずしお衚珟しおみたしょう。

  [Range(0f, 1f)] public float temperatureJitter = 0.1f; 


枩床倉動スラむダヌ。

このような倉動は、局所的な倉化がほずんどなく、滑らかでなければなりたせん。これにはノむズテクスチャを䜿甚できたす。HexMetrics.SampleNoise0.1でスケヌリングされたセル䜍眮を呌び出しお䜿甚したす。チャンネルWを取り、䞭倮に配眮し、振動係数でスケヌリングしたす。次に、この倀を以前に蚈算された枩床に远加したす。

  temperature *= 1f - (cell.ViewElevation - waterLevel) / (elevationMaximum - waterLevel + 1f); temperature += (HexMetrics.SampleNoise(cell.Position * 0.1f).w * 2f - 1f) * temperatureJitter; return temperature; 



0.1ず1の倀の枩床倉動

。4぀のノむズチャネルからランダムに遞択しお、各マップの倉動にわずかな倉動性を远加できたす。チャンネルを䞀床に蚭定しおからSetTerrainType、カラヌチャンネルのむンデックスを䜜成したすDetermineTemperature。

  int temperatureJitterChannel; 
 void SetTerrainType () { temperatureJitterChannel = Random.Range(0, 4); for (int i = 0; i < cellCount; i++) { 
 } } float DetermineTemperature (HexCell cell) { 
 float jitter = HexMetrics.SampleNoise(cell.Position * 0.1f)[temperatureJitterChannel]; temperature += (jitter * 2f - 1f) * temperatureJitter; return temperature; } 


最倧の力で異なる枩床倉動。

ナニティパッケヌゞ

バむオヌム


湿床ず枩床に関するデヌタが埗られたので、バむオヌムマトリックスを䜜成できたす。このマトリックスにむンデックスを付けるこずにより、バむオヌムをすべおのセルに割り圓お、1぀のデヌタディメンションのみを䜿甚するよりも耇雑なランドスケヌプを䜜成できたす。

バむオヌムマトリックス


気候モデルは倚数ありたすが、いずれも䜿甚したせん。私たちはそれを非垞に単玔にしたす、私たちはロゞックにのみ興味がありたす。也燥ずは砂挠寒いたたは暑いを意味し、砂を䜿甚したす。寒くお濡れおいるずは雪を意味したす。高枩倚湿ずは、倚くの怍物、぀たり草を意味したす。それらの間に、タむガたたはツンドラがありたす。これは、地球の灰色がかったテクスチャずしお指定したす。これらのバむオヌム間の移行を䜜成するには、4x4マトリックスで十分です。

以前は、5぀の氎分間隔に基づいおレリヌフタむプを割り圓おたした。最も也燥したストリップを0.05たで䞋げ、残りを保存したす。枩床垯域には、0.1、0.3、0.6以䞊を䜿甚したす。䟿宜䞊、これらの倀を静的配列に蚭定したす。

  static float[] temperatureBands = { 0.1f, 0.3f, 0.6f }; static float[] moistureBands = { 0.12f, 0.28f, 0.85f }; 

バむオヌムに基づいおレリヌフタむプのみを指定したすが、それを䜿甚しお他のパラメヌタヌを決定できたす。したがっお、個々のバむオヌムの構成を蚘述するHexMapGenerator構造Biomeで定矩したしょう。これたでのずころ、バンプむンデックスず察応するコンストラクタヌメ゜ッドのみが含たれおいたす。

  struct Biome { public int terrain; public Biome (int terrain) { this.terrain = terrain; } } 

この構造を䜿甚しお、行列デヌタを含む静的配列を䜜成したす。X座暙ずしお湿床を䜿甚し、Yずしお枩床を䜿甚したす。最も䜎い枩床のラむンを雪で、2番目のラむンをツンドラで、他の2぀を草で埋めたす。次に、最も也燥した柱を砂挠に眮き換えお、枩床の遞択を再定矩したす。

  static Biome[] biomes = { new Biome(0), new Biome(4), new Biome(4), new Biome(4), new Biome(0), new Biome(2), new Biome(2), new Biome(2), new Biome(0), new Biome(1), new Biome(1), new Biome(1), new Biome(0), new Biome(1), new Biome(1), new Biome(1) }; 


1次元配列のむンデックスを持぀バむオヌムのマトリックス。

バむオヌムの定矩


SetTerrainTypeバむオヌム内の现胞を決定するには、サむクル内の枩床ず湿床の範囲を調べお、必芁なマトリックスむンデックスを決定したす。これらを䜿甚しお、目的のバむオヌムを取埗し、现胞トポグラフィヌのタむプを指定したす。

  void SetTerrainType () { temperatureJitterChannel = Random.Range(0, 4); for (int i = 0; i < cellCount; i++) { HexCell cell = grid.GetCell(i); float temperature = DetermineTemperature(cell); // cell.SetMapData(temperature); float moisture = climate[i].moisture; if (!cell.IsUnderwater) { // if (moisture < 0.05f) { // cell.TerrainTypeIndex = 4; // } // 
 // else { // cell.TerrainTypeIndex = 2; // } int t = 0; for (; t < temperatureBands.Length; t++) { if (temperature < temperatureBands[t]) { break; } } int m = 0; for (; m < moistureBands.Length; m++) { if (moisture < moistureBands[m]) { break; } } Biome cellBiome = biomes[t * 4 + m]; cell.TerrainTypeIndex = cellBiome.terrain; } else { cell.TerrainTypeIndex = 2; } } } 


バむオヌムマトリックスに基づく救枈。

バむオヌムのセットアップ


マトリックスで定矩されたバむオヌムを超えるこずができたす。たずえば、マトリックスでは、すべおの也燥バむオヌムは砂砂挠ずしお定矩されおいたすが、すべおの也燥砂挠が砂で満たされおいるわけではありたせん。非垞に異なっお芋える倚くの岩が倚い砂挠がありたす。それでは、砂挠のセルの䞀郚を石で眮き換えたしょう。これは単に高さに基づいお行いたす。砂は暙高が䜎く、通垞は裞の岩が䞊にありたす。

セルの高さが氎䜍よりも最倧の高さに近いずきに、砂が石に倉わるず仮定したす。これは最初に蚈算できる岩の倚い砂挠の高さの線ですSetTerrainType。セルが砂で満たされ、その高さが十分に倧きい堎合、バむオヌムのレリヌフを石に倉曎したす。

  void SetTerrainType () { temperatureJitterChannel = Random.Range(0, 4); int rockDesertElevation = elevationMaximum - (elevationMaximum - waterLevel) / 2; for (int i = 0; i < cellCount; i++) { 
 if (!cell.IsUnderwater) { 
 Biome cellBiome = biomes[t * 4 + m]; if (cellBiome.terrain == 0) { if (cell.Elevation >= rockDesertElevation) { cellBiome.terrain = 3; } } cell.TerrainTypeIndex = cellBiome.terrain; } else { cell.TerrainTypeIndex = 2; } } } 


砂ず岩の砂挠。

高さに基づく別の倉曎は、枩床に関係なく、也燥しすぎおいない堎合にのみ、最倧の高さのセルを匷制的に雪のピヌクに倉えるこずです。これにより、高枩倚湿の赀道付近で雪がピヌクになる可胜性が高くなりたす。

  if (cellBiome.terrain == 0) { if (cell.Elevation >= rockDesertElevation) { cellBiome.terrain = 3; } } else if (cell.Elevation == elevationMaximum) { cellBiome.terrain = 4; } 


最倧高さの雪のキャップ。

怍物


それでは、バむオヌムに怍物现胞のレベルを決定させたしょう。これを行うにはBiome、怍物のフィヌルドに远加し、コンストラクタヌに含めたす。

  struct Biome { public int terrain, plant; public Biome (int terrain, int plant) { this.terrain = terrain; this.plant = plant; } } 

最も寒くお也燥したバむオヌムでは、怍物はたったくありたせん。他のすべおの点では、気候が暖かく湿っおいるほど、怍物が増えたす。湿床の2番目の列は、最も熱い行の怍物の最初のレベルのみを受け取るため、[0、0、0、1]です。3列目は、雪を陀いおレベルを1぀増やしたす。぀たり、[0、1、1、2]です。そしお、最も濡れた列が再びそれらを増やしたす。぀たり、[0、2、2、3]になりたす。biomesプラント構成を远加しおアレむを倉曎したす。

  static Biome[] biomes = { new Biome(0, 0), new Biome(4, 0), new Biome(4, 0), new Biome(4, 0), new Biome(0, 0), new Biome(2, 0), new Biome(2, 1), new Biome(2, 2), new Biome(0, 0), new Biome(1, 0), new Biome(1, 1), new Biome(1, 2), new Biome(0, 0), new Biome(1, 1), new Biome(1, 2), new Biome(1, 3) }; 


怍物レベルのバむオヌムのマトリックス。

これで、セルの怍物のレベルを蚭定できたす。

  cell.TerrainTypeIndex = cellBiome.terrain; cell.PlantLevel = cellBiome.plant; 


怍物のあるバむオヌム。

怍物は今では異なっお芋えたすか
, . (1, 2, 1) (0.75, 1, 0.75). (1.5, 3, 1.5) (2, 1.5, 2). — (2, 4.5, 2) (2.5, 3, 2.5).

, : (13, 114, 0).

バむオヌムの怍物のレベルを倉曎できたす。たず、雪の地圢にそれらが衚瀺されないようにする必芁がありたす。これは既に蚭定できたす。第二に、ただ最倧倀になっおいない堎合は、川沿いの怍物のレベルを䞊げたしょう。

  if (cellBiome.terrain == 4) { cellBiome.plant = 0; } else if (cellBiome.plant < 3 && cell.HasRiver) { cellBiome.plant += 1; } cell.TerrainTypeIndex = cellBiome.terrain; cell.PlantLevel = cellBiome.plant; 


倉曎された怍物。

氎䞭バむオヌム


その瞬間たで、私たちは氎䞭の现胞を完党に無芖したした。それらに少しのバリ゚ヌションを远加したしょう。それらすべおに地球のテクスチャを䜿甚するわけではありたせん。高さを基にした単玔な゜リュヌションは、より興味深い画像を䜜成するのに十分です。たずえば、氎䜍の1぀䞋のセルに草を䜿甚しおみたしょう。たた、氎䜍より䞊のセル、぀たり川によっお䜜られた湖にも草を䜿甚したしょう。負の高さのセルは深海域であるため、石を䜿甚したす。他のすべおのセルは接地されたたたです。

  void SetTerrainType () { 
 if (!cell.IsUnderwater) { 
 } else { int terrain; if (cell.Elevation == waterLevel - 1) { terrain = 1; } else if (cell.Elevation >= waterLevel) { terrain = 1; } else if (cell.Elevation < 0) { terrain = 3; } else { terrain = 2; } cell.TerrainTypeIndex = terrain; } } } 


氎䞭倉動。

海岞沿いの氎䞭セルの詳现を远加したしょう。これらは、氎䞊に少なくずも1぀の隣接セルを持぀セルです。そのようなセルが浅い堎合は、ビヌチを䜜成したす。厖の隣にある堎合は、芖芚的なディテヌルが支配的になり、石を䜿甚したす。

これを刀断するために、氎䜍の1぀䞋のセルに隣接するセルをチェックしたす。隣接する陞のセルずの厖や斜面による接続の数を数えたしょう。

  if (cell.Elevation == waterLevel - 1) { int cliffs = 0, slopes = 0; for ( HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++ ) { HexCell neighbor = cell.GetNeighbor(d); if (!neighbor) { continue; } int delta = neighbor.Elevation - cell.WaterLevel; if (delta == 0) { slopes += 1; } else if (delta > 0) { cliffs += 1; } } terrain = 1; } 

これで、この情報を䜿甚しおセルを分類できたす。たず、隣人の半分以䞊が土地である堎合、湖たたは湟を扱っおいたす。これらのセルには、草のテクスチャを䜿甚したす。それ以倖の堎合、厖がある堎合は、石を䜿甚したす。それ以倖の堎合、斜面がある堎合は、砂を䜿甚しおビヌチを䜜成したす。残っおいる唯䞀のオプションは、海岞から離れた浅い゚リアで、これにはただ草を䜿甚しおいたす。

  if (cell.Elevation == waterLevel - 1) { int cliffs = 0, slopes = 0; for ( HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++ ) { 
 } if (cliffs + slopes > 3) { terrain = 1; } else if (cliffs > 0) { terrain = 3; } else if (slopes > 0) { terrain = 0; } else { terrain = 1; } } 



海岞の倉動。

最埌に、最も寒い枩床範囲に緑色の氎䞭セルがないこずを確認したしょう。そのような现胞には、地球を䜿甚したす。

  if (terrain == 1 && temperature < temperatureBands[0]) { terrain = 2; } cell.TerrainTypeIndex = terrain; 

倚くの蚭定オプションを備えた、非垞に興味深く自然に芋えるランダムカヌドを生成する機䌚を埗たした。

ナニティパッケヌゞ

パヌト27カヌドの折りたたみ



この最埌の郚分では、地図を最小化し、東端ず西端を接続するためのサポヌトを远加したす。

チュヌトリアルはUnity 2017.3.0p3を䜿甚しお䜜成されたした。


折り畳むこずで、䞖界が䞀呚できたす。

折りたたみカヌド


マップを䜿甚しお、さたざたなサむズの゚リアをモデル化できたすが、それらは垞に長方圢に制限されたす。惑星党䜓ではなく、1぀の島たたは倧陞党䜓の地図を䜜成できたす。惑星は球圢で、衚面の動​​きを劚げる剛䜓の境界はありたせん。䞀方向に移動し続けるず、遅かれ早かれ開始点に戻りたす。

球の呚りに六角圢のグリッドをラップするこずはできたせん;そのようなオヌバヌラップは䞍可胜です。最良の近䌌では、12個のセルが五角圢でなければならない正二十面䜓トポロゞヌが䜿甚されたす。ただし、歪みや䟋倖なしで、メッシュを円柱に巻き付けるこずができたす。これを行うには、マップの東端ず西端を接続するだけです。ラッピングロゞックを陀き、他のすべおは同じたたです。

円柱は球の貧匱な近䌌です。極をモデル化できないためです。しかし、これは倚くのゲヌムの開発者が東から西ぞの折りたたみを䜿甚しお惑星地図をモデル化するこずを止めたせんでした。極地は単にゲヌムゟヌンの䞀郚ではありたせん。

北ず南に曲がっおみおはいかがですか
, . , , . -, -. .

円筒圢の折りたたみを実装するには、2぀の方法がありたす。最初の方法は、実際にその衚面ずその䞊のすべおを曲げお地図を円筒圢にし、東ず西の゚ッゞが接觊するようにするこずです。今、あなたは平らな衚面ではなく、実際のシリンダヌでプレヌしたす。2番目のアプロヌチは、フラットマップを保存し、テレポヌテヌションたたは耇補を䜿甚しお折りたたむこずです。ほずんどのゲヌムは2番目のアプロヌチを䜿甚するため、それを採甚したす。

オプションの折りたたみ


マップを折りたたむ必芁があるかどうかは、そのスケヌルロヌカルたたは惑星によっお異なりたす。折りたたみをオプションにするこずで、䞡方のサポヌトを䜿甚できたす。これを行うには、デフォルトで折りたたみがオンになった状態で[ 新しいマップの䜜成 ]メニュヌに新しいスむッチを远加したす。


折りたたみオプションを備えた新しいマップのメニュヌ。 遞択を远跡するため

のNewMapMenuフィヌルドず、倉曎方法を远加したす。スむッチの状態が倉化したずきにこのメ゜ッドが呌び出されるようにしたす。

  bool wrapping = true; 
 public void ToggleWrapping (bool toggle) { wrapping = toggle; } 

新しいマップが芁求されるず、最小化オプションの倀を枡したす。

  void CreateMap (int x, int z) { if (generateMaps) { mapGenerator.GenerateMap(x, z, wrapping); } else { hexGrid.CreateMap(x, z, wrapping); } HexMapCamera.ValidatePosition(); Close(); } 

倉曎しHexMapGenerator.GenerateMap、圌はこの新しい匕数を取り、その埌にそれを転送されたこずの道をHexGrid.CreateMap。

  public void GenerateMap (int x, int z, bool wrapping) { 
 grid.CreateMap(x, z, wrapping); 
 } 

code> HexGridは折りたたたれおいるかどうかを知る必芁があるため、フィヌルドを远加しおCreateMap蚭定したす。他のクラスは、グリッドが最小化されおいるかどうかに応じおロゞックを倉曎する必芁があるため、フィヌルドを䞀般化したす。さらに、むンスペクタヌを䜿甚しおデフォルト倀を蚭定できたす。

  public int cellCountX = 20, cellCountZ = 15; public bool wrapping; 
 public bool CreateMap (int x, int z, bool wrapping) { 
 cellCountX = x; cellCountZ = z; this.wrapping = wrapping; 
 } 

HexGridCreateMap2぀の堎所で自分自身を呌び出したす。collapse匕数に独自のフィヌルドを䜿甚するだけです。

  void Awake () { 
 CreateMap(cellCountX, cellCountZ, wrapping); } 
 public void Load (BinaryReader reader, int header) { 
 if (x != cellCountX || z != cellCountZ) { if (!CreateMap(x, z, wrapping)) { return; } } 
 } 


グリッド折りたたみスむッチはデフォルトでオンになっおいたす。

保存ず読み蟌み


折りたたみはカヌドごずに蚭定されるため、保存しおロヌドする必芁がありたす。これは、ファむルの保存圢匏を倉曎する必芁があるため、のバヌゞョン定数を倧きくするこずを意味したすSaveLoadMenu。

  const int mapFileVersion = 5; 

保存するずきHexGridは、マップサむズの埌にブヌル倀の折りたたみ倀を曞き蟌むだけにしたす。

  public void Save (BinaryWriter writer) { writer.Write(cellCountX); writer.Write(cellCountZ); writer.Write(wrapping); 
 } 

ダりンロヌドするずきは、正しいバヌゞョンのファむルでのみ読み取りたす。異なる堎合、これは叀いカヌドであり、最小化しないでください。この情報をロヌカル倉数に保存し、珟圚の折りたたみ状態ず比范したす。異なる堎合、他のサむズのマップをロヌドする堎合ず同じ方法で既存のマップトポロゞを再利甚するこずはできたせん。

  public void Load (BinaryReader reader, int header) { ClearPath(); ClearUnits(); int x = 20, z = 15; if (header >= 1) { x = reader.ReadInt32(); z = reader.ReadInt32(); } bool wrapping = header >= 5 ? reader.ReadBoolean() : false; if (x != cellCountX || z != cellCountZ || this.wrapping != wrapping) { if (!CreateMap(x, z, wrapping)) { return; } } 
 } 

折りたたみメトリック


マップを折りたたむには、たずえば距離を蚈算するずきなど、ロゞックを倧幅に倉曎する必芁がありたす。したがっお、グリッドぞの盎接リンクを持たないコヌドに觊れるこずができたす。この情報を匕数ずしお枡す代わりに、に远加したしょうHexMetrics。マップの幅に䞀臎する折りたたみサむズを含む静的敎数を远加したす。れロより倧きい堎合、折りたたみ可胜なカヌドを扱っおいたす。これを確認するには、プロパティを远加したす。

  public static int wrapSize; public static bool Wrapping { get { return wrapSize > 0; } } 

各呌び出しの折りたたみサむズを蚭定する必芁がありたすHexGrid.CreateMap。

  public bool CreateMap (int x, int z, bool wrapping) { 
 this.wrapping = wrapping; HexMetrics.wrapSize = wrapping ? cellCountX : 0; 
 } 

このデヌタはPlayモヌドでの再コンパむルには耐えられないため、に蚭定しおみたしょうOnEnable。

  void OnEnable () { if (!HexMetrics.noiseSource) { HexMetrics.noiseSource = noiseSource; HexMetrics.InitializeHashGrid(seed); HexUnit.unitPrefab = unitPrefab; HexMetrics.wrapSize = wrapping ? cellCountX : 0; ResetVisibility(); } } 

セル幅


折りたたみ可胜なカヌドを䜿甚する堎合、セルの幅で枬定されるX軞に沿った䜍眮を凊理する必芁がありたす。このために䜿甚できたすがHexMetrics.innerRadius * 2f、毎回乗算を远加しない方が䟿利です。定数を远加したしょうHexMetrics.innerDiameter。

  public const float innerRadius = outerRadius * outerToInner; public const float innerDiameter = innerRadius * 2f; 

すでに3箇所で盎埄を䜿甚できたす。たず、HexGrid.CreateCell新しいセルを配眮するずき。

  void CreateCell (int x, int z, int i) { Vector3 position; position.x = (x + z * 0.5f - z / 2) * HexMetrics.innerDiameter; 
 } 

第二HexMapCameraに、カメラの䜍眮を制限したす。

  Vector3 ClampPosition (Vector3 position) { float xMax = (grid.cellCountX - 0.5f) * HexMetrics.innerDiameter; position.x = Mathf.Clamp(position.x, 0f, xMax); 
 } 

たたHexCoordinates、䜍眮から座暙ぞの倉換でも。

  public static HexCoordinates FromPosition (Vector3 position) { float x = position.x / HexMetrics.innerDiameter; 
 } 

ナニティパッケヌゞ

カヌドのセンタリング


マップが折りたたたれおいない堎合、東端ず西端が明確に定矩されおいるため、氎平方向の䞭心が明確になりたす。しかし、折りたたみ可胜なカヌドの堎合、すべおが異なりたす。東端も西端も䞭倮もありたせん。たたは、䞭心がカメラのある堎所であるず想定できたす。これは、マップを垞に芖点の䞭心に配眮する必芁があるため䟿利です。その埌、どこにいおも、マップの東端たたは西端が芋えなくなりたす。

フラグメント列のマップ


マップの芖芚化がカメラに察しお䞭倮に配眮されるように、カメラの動きに応じお芁玠の配眮を倉曎する必芁がありたす。西に移動する堎合は、珟圚東郚の端にあるものを取埗し、西郚の端に移動する必芁がありたす。同じこずが反察方向にも圓おはたりたす。

理想的には、カメラが隣接するセルの列に移動したらすぐに、セルの最も遠い列をすぐに反察偎に移動する必芁がありたす。ただし、それほど正確である必芁はありたせん。代わりに、マップフラグメント党䜓を転送できたす。これにより、メッシュを倉曎せずにマップの䞀郚を移動できたす。

フラグメントの列党䜓を同時に移動するため、各グルヌプの芪列オブゞェクトを䜜成しお、それらをグルヌプ化したす。これらのオブゞェクトの配列をに远加し、でHexGrid初期化しCreateChunksたす。コンテナずしおのみ䜿甚するため、コンポヌネントぞのリンクを远跡するだけですTransform。フラグメントの堎合ず同様に、それらの初期䜍眮はグリッド座暙のロヌカル原点にありたす。

  Transform[] columns; 
 void CreateChunks () { columns = new Transform[chunkCountX]; for (int x = 0; x < chunkCountX; x++) { columns[x] = new GameObject("Column").transform; columns[x].SetParent(transform, false); } 
 } 

これで、フラグメントはグリッドではなく、察応する列の子になりたす。

  void CreateChunks () { 
 chunks = new HexGridChunk[chunkCountX * chunkCountZ]; for (int z = 0, i = 0; z < chunkCountZ; z++) { for (int x = 0; x < chunkCountX; x++) { HexGridChunk chunk = chunks[i++] = Instantiate(chunkPrefab); chunk.transform.SetParent(columns[x], false); } } } 


列にグルヌプ化されたフラグメント。

すべおのフラグメントが列の子になったため、フラグメントではCreateMapなく、すべおの列を盎接砎棄するだけで十分です。したがっお、嚘の断片を取り陀きたす。

  public bool CreateMap (int x, int z, bool wrapping) { 
 if (columns != null) { for (int i = 0; i < columns.Length; i++) { Destroy(columns[i].gameObject); } } 
 } 

テレポヌト列


䜍眮XをパラメヌタヌずしおHexGrid新しいメ゜ッドに远加しCenterMapたす。䜍眮を列むンデックスに倉換し、Unity単䜍のフラグメント幅で陀算したす。これは、カメラが珟圚配眮されおいる列のむンデックスになりたす。぀たり、マップの䞭倮の列になりたす。

  public void CenterMap (float xPosition) { int centerColumnIndex = (int) (xPosition / (HexMetrics.innerDiameter * HexMetrics.chunkSizeX)); } 

䞭倮の列のむンデックスが倉曎された堎合にのみ、マップの芖芚化を倉曎するだけで十分です。それで、フィヌルドでそれを远跡したしょう。マップを䜜成するずきにデフォルト倀-1を䜿甚しお、新しいマップが垞に䞭倮に配眮されるようにしたす。

  int currentCenterColumnIndex = -1; 
 public bool CreateMap (int x, int z, bool wrapping) { 
 this.wrapping = wrapping; currentCenterColumnIndex = -1; 
 } 
 public void CenterMap (float xPosition) { int centerColumnIndex = (int) (xPosition / (HexMetrics.innerDiameter * HexMetrics.chunkSizeX)); if (centerColumnIndex == currentCenterColumnIndex) { return; } currentCenterColumnIndex = centerColumnIndex; } 

䞭倮の列のむンデックスがわかったので、列の半分の数を単玔に枛算しお加算するこずにより、最小および最倧のむンデックスを決定できたす。奇数列の敎数倀を䜿甚するため、これは完党に機胜したす。偶数の堎合、列を完党に䞭倮に配眮するこずはできないため、むンデックスの1぀は必芁以䞊に1ステップ進みたす。これにより、マップの最も遠い゚ッゞの方向に1列のオフセットが䜜成されたすが、これは問題ではありたせん。

  currentCenterColumnIndex = centerColumnIndex; int minColumnIndex = centerColumnIndex - chunkCountX / 2; int maxColumnIndex = centerColumnIndex + chunkCountX / 2; 

これらのむンデックスは、負たたは自然最倧列むンデックスより倧きい堎合がありたす。カメラがマップの自然䞭心に近い堎合にのみ、最小倀はれロです。私たちのタスクは、これらの盞察むンデックスに察応するように列を移動するこずです。これは、ルヌプ内の各列のロヌカルX座暙を倉曎するこずで実行できたす。

  int minColumnIndex = centerColumnIndex - chunkCountX / 2; int maxColumnIndex = centerColumnIndex + chunkCountX / 2; Vector3 position; position.y = position.z = 0f; for (int i = 0; i < columns.Length; i++) { position.x = 0f; columns[i].localPosition = position; } 

各列に぀いお、むンデックスが最小むンデックスよりも䜎いかどうかを確認したす。もしそうなら、それは䞭心の巊に遠すぎたす。圌はマップの反察偎にテレポヌトしなければなりたせん。これは、X座暙をマップの幅に等しくするこずで実行できたす。同様に、列のむンデックスが最倧のむンデックスよりも倧きい堎合は、䞭心から右に離れすぎおいるため、反察偎にテレポヌトする必芁がありたす。

  for (int i = 0; i < columns.Length; i++) { if (i < minColumnIndex) { position.x = chunkCountX * (HexMetrics.innerDiameter * HexMetrics.chunkSizeX); } else if (i > maxColumnIndex) { position.x = chunkCountX * -(HexMetrics.innerDiameter * HexMetrics.chunkSizeX); } else { position.x = 0f; } columns[i].localPosition = position; } 

移動カメラ


これを倉曎しHexMapCamera.AdjustPositionお、折りたたみ可胜なカヌドを操䜜するずきに、代わりにをClampPosition呌び出すようにしたすWrapPosition。最初に、新しいメ゜ッドをWrapPosition耇補ClampPositionにしたすが、唯䞀の違いがありたすCenterMap。最終的に、を呌び出したす。

  void AdjustPosition (float xDelta, float zDelta) { 
 transform.localPosition = grid.wrapping ? WrapPosition(position) : ClampPosition(position); } 
 Vector3 WrapPosition (Vector3 position) { float xMax = (grid.cellCountX - 0.5f) * HexMetrics.innerDiameter; position.x = Mathf.Clamp(position.x, 0f, xMax); float zMax = (grid.cellCountZ - 1) * (1.5f * HexMetrics.outerRadius); position.z = Mathf.Clamp(position.z, 0f, zMax); grid.CenterMap(position.x); return position; } 

カヌドがすぐに䞭倮にくるように、OnEnableメ゜ッドを呌び出したすValidatePosition。

  void OnEnable () { instance = this; ValidatePosition(); } 


カメラの䞭心にあるずきに巊右に移動したす。

カメラの移動は匕き続き制限されたすが、マップはカメラに察しお䞭心に配眮され、必芁に応じおマップフラグメントの列をテレポヌトしたす。小さな地図ずリモヌトカメラでは、これがはっきりず芋えたすが、倧きな地図では、テレポヌトされた断片がカメラの衚瀺範囲倖にありたす。明らかに、それらの間にただ䞉角圢分割がないため、マップの最初の東ず西の゚ッゞのみが目立ちたす。

カメラを折りたたむには、そのX座暙の制限を削陀しWrapPositionたす。代わりに、X座暙はれロよりも小さい間はマップの幅だけ増加し続け、マップの幅よりも倧きい堎合は枛少したす。

  Vector3 WrapPosition (Vector3 position) { // float xMax = (grid.cellCountX - 0.5f) * HexMetrics.innerDiameter; // position.x = Mathf.Clamp(position.x, 0f, xMax); float width = grid.cellCountX * HexMetrics.innerDiameter; while (position.x < 0f) { position.x += width; } while (position.x > width) { position.x -= width; } float zMax = (grid.cellCountZ - 1) * (1.5f * HexMetrics.outerRadius); position.z = Mathf.Clamp(position.z, 0f, zMax); grid.CenterMap(position.x); return position; } 


ロヌルアップカメラはマップに沿っお移動したす。

折りたたみ可胜なシェヌダヌテクスチャ


䞉角枬量空間を陀き、ゲヌムモヌドでカメラを最小化するこずは感知できないはずです。ただし、これが発生するず、地圢ず氎の半分が芖芚的に倉化したす。これは、䞖界の䜍眮を䜿甚しおこれらのテクスチャをサンプリングするために発生したす。フラグメントの鋭いテレポヌテヌションは、テクスチャの䜍眮を倉曎したす。

この問題を解決するには、フラグメントサむズの倍数のタむルにテクスチャを衚瀺したす。フラグメントサむズはの定数から蚈算されるHexMetricsため、HexMetrics.cgincシェヌダヌむンクルヌドファむルを䜜成し、それに察応する定矩を貌り付けたしょう。基本的なタむルスケヌルは、フラグメントサむズずセルの倖半埄から蚈算されたす。他のメトリックを䜿甚する堎合、それに応じおファむルを倉曎する必芁がありたす。

 #define OUTER_TO_INNER 0.866025404 #define OUTER_RADIUS 10 #define CHUNK_SIZE_X 5 #define TILING_SCALE (1 / (CHUNK_SIZE_X * 2 * OUTER_RADIUS / OUTER_TO_INNER)) 

これにより、タむルスケヌルが0.00866025404になりたす。この倀の敎数倍を䜿甚する堎合、テクスチャリングはフラグメントのテレポヌテヌションの圱響を受けたせん。さらに、マップの東ず西の゚ッゞのテクスチャは、接続を正しく䞉角圢分割した埌、シヌムレスに結合したす。テレむン

シェヌダヌのUVスケヌルずしお0.02を䜿甚したした。代わりに、0.01732050808の2倍のタむルスケヌルを䜿甚できたす。スケヌルは以前よりも少し小さくなり、テクスチャのスケヌルはわずかに増加したしたが、芖芚的には芋えたせん。

  #include "../HexMetrics.cginc" #include "../HexCellData.cginc" 
 float4 GetTerrainColor (Input IN, int index) { float3 uvw = float3( IN.worldPos.xz * (2 * TILING_SCALE), IN.terrain[index] ); 
 } 

UVノむズのRoadsシェヌダヌでは、0.025のスケヌルを䜿甚したした。代わりに、トリプルタむルスケヌルを䜿甚できたす。これにより0.02598076212が埗られたすが、これはかなり近い倀です。

  #include "HexMetrics.cginc" #include "HexCellData.cginc" 
 void surf (Input IN, inout SurfaceOutputStandardSpecular o) { float4 noise = tex2D(_MainTex, IN.worldPos.xz * (3 * TILING_SCALE)); 
 } 

最埌に、Water.cgincでは、泡に0.015、波に0.025を䜿甚したした。ここでも、これらの倀を2倍および3倍のタむルスケヌルに眮き換えるこずができたす。

 #include "HexMetrics.cginc" float Foam (float shore, float2 worldXZ, sampler2D noiseTex) { shore = sqrt(shore) * 0.9; float2 noiseUV = worldXZ + _Time.y * 0.25; float4 noise = tex2D(noiseTex, noiseUV * (2 * TILING_SCALE)); 
 } 
 float Waves (float2 worldXZ, sampler2D noiseTex) { float2 uv1 = worldXZ; uv1.y += _Time.y; float4 noise1 = tex2D(noiseTex, uv1 * (3 * TILING_SCALE)); float2 uv2 = worldXZ; uv2.x += _Time.y; float4 noise2 = tex2D(noiseTex, uv2 * (3 * TILING_SCALE)); 
 } 

ナニティパッケヌゞ

東ず西の連合


この段階では、マップを折り畳むこずの唯䞀の芖芚的蚌拠は、最東列ず最西列の間の小さなギャップです。このギャップは、折りたたむこずなくマップの反察偎のセル間の゚ッゞず角床の接続をただ䞉角圢分割しおいないために発生したす。


端のスペヌスバヌ。

折りたたみ隣人


東西接続を䞉角枬量するために、反察偎のセルを互いに隣接させる必芁がありたす。これたではHexGrid.CreateCell、Xのむンデックスがれロより倧きい堎合にのみ、前のセルずのE-W接続が確立されるため、これを行っおいたせん。この接続を折りたたむには、マップの折り畳みがオンになっおいるずきに、行の最埌のセルを同じ行の最初のセルに接続する必芁がありたす。

  void CreateCell (int x, int z, int i) { 
 if (x > 0) { cell.SetNeighbor(HexDirection.W, cells[i - 1]); if (wrapping && x == cellCountX - 1) { cell.SetNeighbor(HexDirection.E, cells[i - x]); } } 
 } 

隣人E – Wの接続を確立したら、ギャップの郚分的な䞉角圢分割を取埗したす。歪みが誀っお隠されおいるため、゚ッゞの接続は理想的ではありたせん。これに぀いおは埌で察凊したす。


化合物E – W

NE-SWリンクも折りたたむ必芁がありたす。これは、各偶数行の最初のセルを前の行の最埌のセルに接続するこずで実行できたす。前のセルになりたす。

  if (z > 0) { if ((z & 1) == 0) { cell.SetNeighbor(HexDirection.SE, cells[i - cellCountX]); if (x > 0) { cell.SetNeighbor(HexDirection.SW, cells[i - cellCountX - 1]); } else if (wrapping) { cell.SetNeighbor(HexDirection.SW, cells[i - 1]); } } else { 
 } } 


NE – SW接続。

最埌に、SE – NW接続は、最初の䞋の各奇数行の終わりに確立されたす。これらのセルは、前の行の最初のセルに接続する必芁がありたす。

  if (z > 0) { if ((z & 1) == 0) { 
 } else { cell.SetNeighbor(HexDirection.SW, cells[i - cellCountX]); if (x < cellCountX - 1) { cell.SetNeighbor(HexDirection.SE, cells[i - cellCountX + 1]); } else if (wrapping) { cell.SetNeighbor( HexDirection.SE, cells[i - cellCountX * 2 + 1] ); } } } 


コンパりンドSE – NW。

ノむズフォヌルディング


ギャップを完党に隠すには、頂点の䜍眮を歪めるために䜿甚されるノむズが、マップの東端ず西端で完党に揃うようにする必芁がありたす。シェヌダヌに䜿甚したのず同じトリックを䜿甚できたすが、ノむズスケヌルは歪みに察しお0.003でした。タむルを確実に䜜成するには、スケヌルを倧幅に倧きくする必芁がありたす。これにより、頂点がより混distortionずした歪みになりたす。

別の解決策は、ノむズをテヌリングするこずではなく、マップの端でノむズを滑らかに枛衰させるこずです。1぀のセルの幅に沿っお滑らかな枛衰を実行するず、歪みによりギャップのない滑らかな遷移が䜜成されたす。この領域のノむズはわずかに滑らかになり、長距離からは倉化がシャヌプに芋えたすが、頂点のわずかな歪みを䜿甚する堎合、これはそれほど明癜ではありたせん。

枩床倉動はどうですか
. , . , . , .

カヌドを折りたたたない堎合は、HexMetrics.SampleNoise1぀のサンプルで察応できたす。しかし、折り畳むずきは枛衰を远加する必芁がありたす。したがっお、サンプルを返す前に、倉数に保存しおください。

  public static Vector4 SampleNoise (Vector3 position) { Vector4 sample = noiseSource.GetPixelBilinear( position.x * noiseScale, position.z * noiseScale ); return sample; } 

最小化する堎合、2番目のサンプルず混合する必芁がありたす。マップの東郚でトランゞションを実行するため、2番目のサンプルを西に移動する必芁がありたす。

  Vector4 sample = noiseSource.GetPixelBilinear( position.x * noiseScale, position.z * noiseScale ); if (Wrapping && position.x < innerDiameter) { Vector4 sample2 = noiseSource.GetPixelBilinear( (position.x + wrapSize * innerDiameter) * noiseScale, position.z * noiseScale ); } 

枛衰は、1぀のセルの幅にわたっお、西郚から東郚ぞの単玔な線圢補間を䜿甚しお実行されたす。

  if (Wrapping && position.x < innerDiameter) { Vector4 sample2 = noiseSource.GetPixelBilinear( (position.x + wrapSize * innerDiameter) * noiseScale, position.z * noiseScale ); sample = Vector4.Lerp( sample2, sample, position.x * (1f / innerDiameter) ); } 


ノむズミキシング、䞍完党な゜リュヌション。

その結果、東偎のセルの䞀郚が負のX座暙を持぀ため、完党に䞀臎したせん。この領域に近づかないように、遷移領域をセル幅の西半分に移動したしょう。

  if (Wrapping && position.x < innerDiameter * 1.5f) { Vector4 sample2 = noiseSource.GetPixelBilinear( (position.x + wrapSize * innerDiameter) * noiseScale, position.z * noiseScale ); sample = Vector4.Lerp( sample2, sample, position.x * (1f / innerDiameter) - 0.5f ); } 


正しい枛衰。

セル線集


䞉角圢分割が正しいようになったので、地図ず折り畳みの継ぎ目ですべおを線集できるこずを確認したしょう。結局のずころ、テレポヌトされたフラグメントでは、座暙が誀っおおり、倧きなブラシが瞫い目で切れおいたす。


ブラシがトリミングされたす。

これを修正するには、HexCoordinates折りたたみを報告する必芁がありたす。これを行うには、コンストラクタヌメ゜ッドでX座暙を䞀臎させたす。軞座暙Xは、オフセットのX座暙からZ座暙の半分を枛算するこずで取埗されるこずがわかっおいるため、この情報を䜿甚しお逆倉換を実行し、れロ座暙が小さいかどうかを確認できたす。その堎合、展開されたマップの東偎を超えた座暙がありたす。各方向でマップの半分以䞋をテレポヌトするため、折り畳みサむズをXに1回远加するだけで十分です。そしお、オフセット座暙が折りたたみサむズよりも倧きい堎合、枛算を実行する必芁がありたす。

  public HexCoordinates (int x, int z) { if (HexMetrics.Wrapping) { int oX = x + z / 2; if (oX < 0) { x += HexMetrics.wrapSize; } else if (oX >= HexMetrics.wrapSize) { x -= HexMetrics.wrapSize; } } this.x = x; this.z = z; } 

マップの䞋郚たたは䞊郚を線集するずきに゚ラヌ
が発生するこずがありたす。これは、頂点のゆがみにより、マップの倖偎のセルの行にカヌ゜ルが衚瀺される堎合に発生したす。これはHexGrid.GetCell、ベクトルパラメヌタず座暙を䞀臎させないために発生するバグです。これを修正GetCellするには、必芁なチェックを実行するパラメヌタヌずしお座暙を持぀メ゜ッドを適甚したす。

  public HexCell GetCell (Vector3 position) { position = transform.InverseTransformPoint(position); HexCoordinates coordinates = HexCoordinates.FromPosition(position); // int index = // coordinates.X + coordinates.Z * cellCountX + coordinates.Z / 2; // return cells[index]; return GetCell(coordinates); } 

沿岞折りたたみ


䞉角枬量は地圢に適しおいたすが、東西の継ぎ目に沿っお、氎の海岞の端はありたせん。実際、圌らはただ、厩壊したせん。それらは反転され、マップの反察偎に匕き䌞ばされたす。


氎の端がありたせん。

これは、海岞の氎を䞉角枬量するずきに、隣人の䜍眮を䜿甚するためです。これを修正するには、カヌドの反察偎を扱っおいるず刀断する必芁がありたす。タスクを簡玠化するHexCellために、むンデックスのプロパティにセル列を远加したす。

  public int ColumnIndex { get; set; } 

このむンデックスをに割り圓おたすHexGrid.CreateCell。これは、オフセット座暙Xをフラグメントサむズで割ったものに単玔に等しくなりたす。

  void CreateCell (int x, int z, int i) { 
 cell.Index = i; cell.ColumnIndex = x / HexMetrics.chunkSizeX; 
 } 

HexGridChunk.TriangulateWaterShore珟圚のセルずその隣のセルの列むンデックスを比范するこずで、最小化されおいるものを刀断できたす。隣人の列のむンデックスが1段階䞋の堎合、西偎にいたす。隣人は東偎にいたす。したがっお、隣人を西に向ける必芁がありたす。同様に、反察方向に。

  Vector3 center2 = neighbor.Position; if (neighbor.ColumnIndex < cell.ColumnIndex - 1) { center2.x += HexMetrics.wrapSize * HexMetrics.innerDiameter; } else if (neighbor.ColumnIndex > cell.ColumnIndex + 1) { center2.x -= HexMetrics.wrapSize * HexMetrics.innerDiameter; } 


海岞のRi骚、しかし角はありたせん。

そのため、私たちは海岞のrib骚の䞖話をしたしたが、これたでのずころコヌナヌを扱っおいたせんでした。次の隣人にも同じこずをする必芁がありたす。

  if (nextNeighbor != null) { Vector3 center3 = nextNeighbor.Position; if (nextNeighbor.ColumnIndex < cell.ColumnIndex - 1) { center3.x += HexMetrics.wrapSize * HexMetrics.innerDiameter; } else if (nextNeighbor.ColumnIndex > cell.ColumnIndex + 1) { center3.x -= HexMetrics.wrapSize * HexMetrics.innerDiameter; } Vector3 v3 = center3 + (nextNeighbor.IsUnderwater ? HexMetrics.GetFirstWaterCorner(direction.Previous()) : HexMetrics.GetFirstSolidCorner(direction.Previous())); 
 } 


適切に瞮小された海岞。

カヌド生成


東ず西を接続するオプションは、マップの生成に圱響したす。マップを最小化する堎合、生成アルゎリズムも最小化する必芁がありたす。これにより、別のマップが䜜成されたすが、れロ以倖のマップボヌダヌXを䜿甚する堎合、折り畳みは明らかではありたせん。



デフォルト蚭定の倧きなマップ1208905299。折り畳みありずなし。

最小化を䜿甚しおも意味がありたせん堎合は地図ボヌダヌにXを。しかし、同時にリヌゞョンがマヌゞされるため、単にそれを取り陀くこずはできたせん。代わりに折りたたむ堎合は、単にRegionBorderを䜿甚できたす。すべおの堎合で

倉曎しおください。この新しい倉数は、collapseオプションの倀に応じお、たたは、たたはに等しくなりたす。以䞋に、最初のケヌスのみの倉曎を瀺したした。HexMapGenerator.CreateRegionsmapBorderXborderXregionBordermapBorderX

  int borderX = grid.wrapping ? regionBorder : mapBorderX; MapRegion region; switch (regionCount) { default: region.xMin = borderX; region.xMax = grid.cellCountX - borderX; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); break; 
 } 

同時に、地域は分離されたたたですが、これはマップの東偎ず西偎に異なる地域がある堎合にのみ必芁です。これが尊重されない堎合が2぀ありたす。1぀は、リヌゞョンが1぀しかない堎合です。2぀目は、マップを氎平に分割する2぀の領域がある堎合です。これらの堎合、borderXれロの倀を割り圓おるこずができたす。これにより、陞地が東西の継ぎ目を暪切るこずができたす。

  switch (regionCount) { default: if (grid.wrapping) { borderX = 0; } region.xMin = borderX; region.xMax = grid.cellCountX - borderX; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); break; case 2: if (Random.value < 0.5f) { 
 } else { if (grid.wrapping) { borderX = 0; } region.xMin = borderX; region.xMax = grid.cellCountX - borderX; region.zMin = mapBorderZ; region.zMax = grid.cellCountZ / 2 - regionBorder; regions.Add(region); region.zMin = grid.cellCountZ / 2 + regionBorder; region.zMax = grid.cellCountZ - mapBorderZ; regions.Add(region); } break; 
 } 


1぀の地域が厩壊しおいたす。

䞀芋、すべおが正しく機胜しおいるように芋えたすが、実際には継ぎ目に沿っおギャップがありたす。これは、䟵食率をれロに蚭定するず、より顕著になりたす。



䟵食が無効になるず、レリヌフの継ぎ目が目立぀ようになりたす。

継ぎ目がレリヌフ砎片の成長を劚げるため、ギャップが発生したす。最初に远加されるものを決定するために、セルからフラグメントの䞭心たでの距離が䜿甚され、マップの反察偎のセルは非垞に遠くなる可胜性があるため、ほずんど点灯したせん。もちろん、これは間違っおいたす。HexCoordinates.DistanceTo最小化されたマップに぀いお知っおいるこずを確認する必芁がありたす。

間の距離を蚈算しHexCoordinates、3぀の軞のそれぞれに沿った絶察距離を合蚈し、結果を半分にしたす。 Zに沿った距離は垞に真ですが、それに沿っお折りたたむずXずYの距離に圱響する堎合がありたす。それでは、X + Yの個別の蚈算から始めたしょう。

  public int DistanceTo (HexCoordinates other) { // return // ((x < other.x ? other.x - x : x - other.x) + // (Y < other.Y ? other.Y - Y : Y - other.Y) + // (z < other.z ? other.z - z : z - other.z)) / 2; int xy = (x < other.x ? other.x - x : x - other.x) + (Y < other.Y ? other.Y - Y : Y - other.Y); return (xy + (z < other.z ? other.z - z : z - other.z)) / 2; } 

折り畳むこずで任意のセルの距離が短くなるかどうかを刀断するのは簡単な䜜業ではないため、別の座暙を西偎に折り畳む堎合のX + Yを蚈算しおみたしょう。倀が元のX + Yより小さい堎合は、それを䜿甚したす。

  int xy = (x < other.x ? other.x - x : x - other.x) + (Y < other.Y ? other.Y - Y : Y - other.Y); if (HexMetrics.Wrapping) { other.x += HexMetrics.wrapSize; int xyWrapped = (x < other.x ? other.x - x : x - other.x) + (Y < other.Y ? other.Y - Y : Y - other.Y); if (xyWrapped < xy) { xy = xyWrapped; } } 

これにより距離が短くならない堎合は、他の方向に短く回すこずができるため、確認したす。

  if (HexMetrics.Wrapping) { other.x += HexMetrics.wrapSize; int xyWrapped = (x < other.x ? other.x - x : x - other.x) + (Y < other.Y ? other.Y - Y : Y - other.Y); if (xyWrapped < xy) { xy = xyWrapped; } else { other.x -= 2 * HexMetrics.wrapSize; xyWrapped = (x < other.x ? other.x - x : x - other.x) + (Y < other.Y ? other.Y - Y : Y - other.Y); if (xyWrapped < xy) { xy = xyWrapped; } } } 

これで、折りたたみ可胜なマップで垞に最短距離を取埗できたす。地圢の砎片は継ぎ目によっおブロックされなくなり、陞地が䞞たるこずができたす。



䟵食ず䟵食のないレリヌフを正しく折りたたみたす。

ナニティパッケヌゞ

䞖界を旅する


マップの生成ず䞉角枬量を怜蚎したので、次に分隊、調査、および可芖性のチェックに移りたしょう。

テストシヌム


チヌムを䞖界䞭に移動するずきに最初に遭遇する障害は、探玢できないマップの端です。


カヌドの継ぎ目を調べるこずはできたせん。

マップの端に沿ったセルは、マップの突然の完了を隠すために未探玢にされたす。ただし、マップを最小化するず、北ず南のセルのみがマヌクされ、東ず西のセルはマヌクされたせん。HexGrid.CreateCellこれを考慮しお倉曎しおください。

  if (wrapping) { cell.Explorable = z > 0 && z < cellCountZ - 1; } else { cell.Explorable = x > 0 && z > 0 && x < cellCountX - 1 && z < cellCountZ - 1; } 

レリヌフ機胜の可芖性


次に、継ぎ目に沿っお可芖性が機胜するかどうかを確認したしょう。地圢に察しおは機胜したすが、地圢機胜に察しおは機胜したせん。折りたたたれおいるオブゞェクトは、折りたたたれおいない最埌のセルの可芖性を取埗しおいるように芋えたす。


オブゞェクトの䞍正確な可芖性。

これは、䜿甚するテクスチャフォヌルディングモヌドにHexCellShaderDataクランプモヌドが蚭定されおいるために発生したす。この問題を解決するには、クランプモヌドを倉曎しお繰り返したす。ただし、これInitializeはUの座暙に察しおのみ行う必芁があるため、個別に蚭定wrapModeUしwrapModeVたす。

  public void Initialize (int x, int z) { if (cellTexture) { cellTexture.Resize(x, z); } else { cellTexture = new Texture2D( x, z, TextureFormat.RGBA32, false, true ); cellTexture.filterMode = FilterMode.Point; // cellTexture.wrapMode = TextureWrapMode.Clamp; cellTexture.wrapModeU = TextureWrapMode.Repeat; cellTexture.wrapModeV = TextureWrapMode.Clamp; Shader.SetGlobalTexture("_HexCellData", cellTexture); } 
 } 

分隊ず列


別の問題は、ナニットがただ折り畳たれおいないこずです。ナニットが配眮されおいる列を移動した埌、ナニットは同じ堎所に残りたす。


ナニットは転送されず、反察偎にありたす。

この問題は、フラグメントで行ったように、分隊の子芁玠を列にするこずで解決できたす。たず、それらをグリッドの盎接の子にしたせんHexGrid.AddUnit。

  public void AddUnit (HexUnit unit, HexCell location, float orientation) { units.Add(unit); unit.Grid = this; // unit.transform.SetParent(transform, false); unit.Location = location; unit.Orientation = orientation; } 

ナニットが移動するず、別の列に衚瀺される堎合がありたす。぀たり、芪を倉曎する必芁がありたす。これを可胜にするために、HexGrid䞀般メ゜ッドに远加し、MakeChildOfColumnパラメヌタヌずしおTransform子芁玠のコンポヌネントず列むンデックスを枡したす。

  public void MakeChildOfColumn (Transform child, int columnIndex) { child.SetParent(columns[columnIndex], false); } 

プロパティが蚭定されたずきにこのメ゜ッドを呌び出したすHexUnit.Location。

  public HexCell Location { 
 set { 
 Grid.MakeChildOfColumn(transform, value.ColumnIndex); } } 

これにより、ナニット䜜成の問題が解決されたす。ただし、移動するずきに目的の列に移動する必芁もありたす。これを行うには、HexUnit.TravelPathむンデックスの珟圚の列を远跡する必芁がありたす。このメ゜ッドの最初では、これはパスの最初のセル列のむンデックス、たたは再コンパむルによっお移動が䞭断された堎合は珟圚のむンデックスです。

  IEnumerator TravelPath () { Vector3 a, b, c = pathToTravel[0].Position; yield return LookAt(pathToTravel[1].Position); // Grid.DecreaseVisibility( // currentTravelLocation ? currentTravelLocation : pathToTravel[0], // VisionRange // ); if (!currentTravelLocation) { currentTravelLocation = pathToTravel[0]; } Grid.DecreaseVisibility(currentTravelLocation, VisionRange); int currentColumn = currentTravelLocation.ColumnIndex; 
 } 

移動の各反埩䞭に、次の列のむンデックスが異なるかどうかを確認し、そうであれば、順序の芪を倉曎したす。

  int currentColumn = currentTravelLocation.ColumnIndex; float t = Time.deltaTime * travelSpeed; for (int i = 1; i < pathToTravel.Count; i++) { 
 Grid.IncreaseVisibility(pathToTravel[i], VisionRange); int nextColumn = currentTravelLocation.ColumnIndex; if (currentColumn != nextColumn) { Grid.MakeChildOfColumn(transform, nextColumn); currentColumn = nextColumn; } 
 } 

これにより、ナニットはフラグメントず同様に移動できたす。ただし、カヌドの継ぎ目を移動するずき、ナニットはただ厩壊しおいたせん。代わりに、圌らは突然間違った方向に動き始めたす。これは、継ぎ目の䜍眮に関係なく発生したすが、最も顕著なのは、マップ党䜓を飛び越えたずきです。


マップ党䜓で競銬。

ここでは、海岞で䜿甚されたのず同じアプロヌチを䜿甚できたすが、今回は、デタッチメントが移動するカヌブをオフにしたす。次の列が東に向いおいる堎合、他の方向に぀いおも同様に、曲線を東にテレポヌトしたす。曲線の制埡点を倉曎する必芁があるaずb、それはたた、コントロヌルポむントに圱響を䞎えたすc。

  for (int i = 1; i < pathToTravel.Count; i++) { currentTravelLocation = pathToTravel[i]; a = c; b = pathToTravel[i - 1].Position; // c = (b + currentTravelLocation.Position) * 0.5f; // Grid.IncreaseVisibility(pathToTravel[i], VisionRange); int nextColumn = currentTravelLocation.ColumnIndex; if (currentColumn != nextColumn) { if (nextColumn < currentColumn - 1) { ax -= HexMetrics.innerDiameter * HexMetrics.wrapSize; bx -= HexMetrics.innerDiameter * HexMetrics.wrapSize; } else if (nextColumn > currentColumn + 1) { ax += HexMetrics.innerDiameter * HexMetrics.wrapSize; bx += HexMetrics.innerDiameter * HexMetrics.wrapSize; } Grid.MakeChildOfColumn(transform, nextColumn); currentColumn = nextColumn; } c = (b + currentTravelLocation.Position) * 0.5f; Grid.IncreaseVisibility(pathToTravel[i], VisionRange); 
 } 


折りたたみ匏の動き。

最埌に行うこずは、チヌムが移動する最初のセルを芋たずきにチヌムの最初のタヌンを倉曎するこずです。このセルが東西の継ぎ目の反察偎にある堎合、ナニットは間違った方向を向いおいたす。

地図を最小化するずき、正確に北たたは南にないポむントを芋るには2぀の方法がありたす。あなたは東たたは西を芋るこずができたす。それは移動の方向でもあるため、ポむントに最も近い距離に察応する方向を芋るのが論理的ですので、で䜿甚したしょうLookAt。

最小化するずき、X軞に沿った盞察距離をチェックしたす。マップの幅の負の半分よりも小さい堎合は、西に目を向ける必芁がありたす。それ以倖の堎合、距離がマップの幅の半分よりも倧きい堎合は、東に折りたたむ必芁がありたす。

  IEnumerator LookAt (Vector3 point) { if (HexMetrics.Wrapping) { float xDistance = point.x - transform.localPosition.x; if (xDistance < -HexMetrics.innerRadius * HexMetrics.wrapSize) { point.x += HexMetrics.innerDiameter * HexMetrics.wrapSize; } else if (xDistance > HexMetrics.innerRadius * HexMetrics.wrapSize) { point.x -= HexMetrics.innerDiameter * HexMetrics.wrapSize; } } 
 } 

したがっお、折りたたみ機胜を備えた完党に機胜するマップがありたす。これで、六角圢マップに関する䞀連のチュヌトリアルが終了したした。前のセクションで述べたように、他のトピックも怜蚎できたすが、六角圢マップに固有のものではありたせん。おそらく、今埌の䞀連のチュヌトリアルでそれらを怜蚎したす。

最埌のパッケヌゞをダりンロヌドし、プレむモヌドでタヌン゚ラヌを取埗したした
, Rotation . . . 5.

最埌のパッケヌゞをダりンロヌドしたしたが、スクリヌンショットのようにグラフィックが矎しくありたせん
. - .

最埌のパッケヌゞをダりンロヌドしたしたが、同じカヌドが垞に生成されたす
seed (1208905299), . , Use Fixed Seed .

ナニティパッケヌゞ

Source: https://habr.com/ru/post/J427567/


All Articles