kamihi のブログ

作成したゲームの情報や作り方を掲載します

UnityでMinecraft風ゲームを作る その4「無限マップの作成」

今回は無限マップの作成に取り掛かろうと思います。 (実験的公開版より読み込みの仕方を改善しました)


ソースや設定方法は長くなるので、Googleドライブに保存しておきました。 そこからダウンロードしてみてください。

UnityでMinecraft風ゲームを作る - Google ドライブ


f:id:zekutasiki:20190102161432p:plain
実行結果

ASDWキー、SPACEキーで移動してみてください Shiftキーでダッシュができます


スクリプトは5つです。

  • Chunk.cs ソースを分離、クラスとゲームオブジェクトを紐付けるフィールドを追加
  • ChunkManager.cs 主な変更場所
  • EnumData.cs 方向の列挙型を格納、前回のを分離しただけ
  • PlayerControl.cs プレイヤーの移動のコントロールを行う、説明は割愛
  • TargetControl.cs プレイヤーのカメラのコントロールを行う、説明は割愛

ChunkManager.csの説明を行います。主にUpdateの中を変更しました。

            int newPlayerChunkX = (int)(Math.Floor((player.position.x + 0.5f) / chunkWidth));
            int newPlayerChunkZ = (int)(Math.Floor((player.position.z + 0.5f) / chunkWidth));

上記のソースコード でプレイヤーのチャンクの位置を計算し、変更があったらプレイヤーの周りchunkDrawDistance分のチャンクを表示しています。

                chunkPosList = new List<Pos>();
                chunkPosListCount = 0;
                for (int x = playerChunkX - chunkDrawDistance; x <= playerChunkX + chunkDrawDistance; x++)
                {
                    for (int z = playerChunkZ - chunkDrawDistance; z <= playerChunkZ + chunkDrawDistance; z++)
                    {
                        chunkPosList.Add(new Pos(Math.Abs(x - playerChunkX) + Math.Abs(z - playerChunkZ), x, z));
                    }
                }
                chunkPosList.Sort((a, b) => a.distance - b.distance);

チャンクを表示する順番のリストの作成箇所です。作成したリストに存在するチャンクが表示されていなかったら、以降の処理で表示します。

            while(chunkPosListCount < chunkPosList.Count)
            {
                int x = chunkPosList[chunkPosListCount].indexX;
                int z = chunkPosList[chunkPosListCount].indexZ;
                chunkPosListCount++;

                string tmpstr = x + "_" + z;
                if (allChunkData.ContainsKey(tmpstr))
                {
                    Chunk chunk = allChunkData[x + "_" + z];
                    if (chunk.gameObject == null)
                    {
                        CreateChunkBase(x + 1, z);
                        CreateChunkBase(x - 1, z);
                        CreateChunkBase(x, z + 1);
                        CreateChunkBase(x, z - 1);

                        GameObject obj = new GameObject("Chunk");
                        obj.AddComponent<MeshRenderer>();
                        obj.GetComponent<MeshRenderer>().material = cubeMaterial;
                        obj.AddComponent<MeshFilter>();
                        obj.GetComponent<MeshFilter>().mesh = chunk.BuildVisualMesh();
                        obj.AddComponent<MeshCollider>();

                        obj.transform.position = new Vector3(x * chunkWidth, 0, z * chunkWidth);
                        chunk.gameObject = obj;

                        //一度リターンする(一度に表示すると少し固まる為)
                        return true;
                    }
                }
            }

実際にチャンクのメッシュを表示する箇所です。表示する際、隣のチャンクのブロックが初期化されていなかったら、初期化します(CreateChunkBase)。 初期化する理由は、メッシュ生成時に隣のチャンクを参照するからです。

            //プレーヤーから遠くなったチャンクの削除
            foreach (KeyValuePair<string, Chunk> tmpChunk in allChunkData)
            {
                if (playerChunkX - chunkDrawDistance <= tmpChunk.Value.indexX && tmpChunk.Value.indexX <= playerChunkX + chunkDrawDistance
                    && playerChunkZ - chunkDrawDistance <= tmpChunk.Value.indexZ && tmpChunk.Value.indexZ <= playerChunkZ + chunkDrawDistance)
                {
                    continue;
                }
                else
                {
                    Destroy(tmpChunk.Value.gameObject);
                    tmpChunk.Value.gameObject = null;
                }
            }

プレイヤーから遠くなったチャンクの削除処理も追加しました。


chunkDrawDistanceの値を変えると、表示するチャンクの距離が変わります。値が大きいと重くなります。

次回はキューブにテクスチャを貼ってみます。