kamihi のブログ

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

UnityでMinecraft風ゲームを作る その11「水を流す」

今回は「水を流す」です。


Googleドライブに保存しておきました。 そこからダウンロードしてみてください。

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

実行するにはレイヤーの設定を行ってください

「Clear」レイヤーの追加

f:id:zekutasiki:20190106135434p:plain

「Clear」レイヤーと「Ignore Raycast(player)」レイヤーの衝突をなくす

f:id:zekutasiki:20190106135450p:plain


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

ブロックの配置が水になっています。

水を配置すると流れると思います。

ついでに原木を消すと葉が消える処理も追加しました。


f:id:zekutasiki:20190113080941p:plain

上の画像のように砂の境界が見えやすいと思います。気になる方はEdit->Project Setting->QualityのAnti AliasingをDisabledにしてみてください


chunk.cs

public List<string> activeBlocks = new List<string>();

アクティブブロックのリストを追加しました。これは現在変化する可能性のあるブロックのリストです

EnumData.cs

            //木ブロック
            blockNo = 5;
            blockList.Add(blockNo, new BlockDatabase());
            blockList[blockNo].texture = new int[6] { 5, 5, 6, 6, 6, 6 };
            blockList[blockNo].impact = 3;

インパクトというのが追加になっていますね。ブロックが変更になった時、インパクトの範囲分、アクティブブロックのリストに追加しています

chunk.cs

        public void Active()
        {
            for (int i = activeBlocks.Count - 1; i >= 0; i--)
            {
                string[] tmpsp = activeBlocks[i].Split('_');
                int tmpBlock = GetBlockTypeSimple(int.Parse(tmpsp[0]), int.Parse(tmpsp[1]), int.Parse(tmpsp[2]));
                if (BlockManager.blockList[tmpBlock].activeProcess == null)
                {
                    activeBlocks.RemoveAt(i);
                }
            }

            List<string> tmp = new List<string>(activeBlocks);
            activeBlocks = new List<string>();


            for (int i = tmp.Count - 1; i >= 0; i--)
            {
                string[] tmpsp = tmp[i].Split('_');
                int tmpBlock = GetBlockTypeSimple(int.Parse(tmpsp[0]), int.Parse(tmpsp[1]), int.Parse(tmpsp[2]));
                if(BlockManager.blockList[tmpBlock].activeProcess != null)
                {
                    if(BlockManager.blockList[tmpBlock].activeProcess(int.Parse(tmpsp[0]), int.Parse(tmpsp[1]), int.Parse(tmpsp[2]), this))
                    {
                        activeBlocks.Add(tmp[i]);
                    }
                }
            }
        }

この辺りでブロックのactiveProcessを呼んでいます。

簡単な説明ですが、以上になります。

次回は未定です。

UnityでMinecraft風ゲームを作る その10「草を生やす」

今回は「草を生やす」です。


Googleドライブに保存しておきました。 そこからダウンロードしてみてください。

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

実行するにはレイヤーの設定を行ってください

「Clear」レイヤーの追加

f:id:zekutasiki:20190106135434p:plain

「Clear」レイヤーと「Ignore Raycast(player)」レイヤーの衝突をなくす

f:id:zekutasiki:20190106135450p:plain


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

草が生えてますね(・v・)


スクリプトの主な変更は以下の通りです

  • Chunk.cs 草のメッシュを表示できるよう追加
  • ChunkManager.cs CustomMesh、ClearMeshの追加
  • EnumData.cs 草を追加
  • PlayerControl.cs 変更なし
  • TargetControl.cs レイヤーで当たる当たらないの設定を追加

f:id:zekutasiki:20190106135705p:plain

草を生やすためにChunkの配下にCustomMesh(草の表示を行うゲームオブジェクト)、ClearMesh(草の当たり判定を行うゲームオブジェクト)を追加しました。


Chunk.cs

        //草の表示を行うリスト
        List<List<Vector3>> customVerticeList = new List<List<Vector3>>();
        List<List<int>> customFaceList = new List<List<int>>();
        List<List<Vector2>> customUvList = new List<List<Vector2>>();
        int customFaceCount;
        int customListCount;
        //草のあたり判定を行うリスト、表示はしないのでUVリストはない
        List<List<Vector3>> clearVerticeList = new List<List<Vector3>>();
        List<List<int>> clearFaceList = new List<List<int>>();
        int clearFaceCount;
        int clearListCount;

CustomMesh、ClearMeshを追加したので頂点情報などが追加になっています。

ブロックと同じよう、草のメッシュはプログラムでちまちま書いてます。

今回は以上になります。

次回は水です。

UnityでMinecraft風ゲームを作る その9「木を生やす」

今回は「木を生やす」です。


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

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


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

木が生えてますね(・v・)

注意:葉はまだすぐに壊れません。


スクリプトの主な変更は以下の通りです

  • Chunk.cs 木を生やすよう変更
  • ChunkManager.cs チャンクの初期化→木を生やす(追加)→メッシュの生成
  • EnumData.cs 変更なし
  • PlayerControl.cs 変更なし
  • TargetControl.cs 変更なし

チャンク表示のタイミングで木を生やしています(ブロックを更新している)。

        //まだ木を生やしていない状態の時呼ばれる、Seed値を決めたRandom関数とパーリンノイズで木を生やす位置を決める
        public void Decoration()
        {
            int randomCount = indexX * 100000 + indexZ * ChunkManager.worldSeed;
            for (int x = 0; x < ChunkManager.chunkWidth; x++)
            {
                for (int z = 0; z < ChunkManager.chunkWidth; z++)
                {

                    float tmpx = (x + indexX * ChunkManager.chunkWidth) + ChunkManager.worldSeed;
                    float tmpz = (z + indexZ * ChunkManager.chunkWidth) + ChunkManager.worldSeed;
                    float noise = Mathf.PerlinNoise(tmpx / 32, tmpz / 32) * 12;
                    int y = (int)(noise) + 6;

                    System.Random rnd = new System.Random(randomCount);
                    if (rnd.Next(0,300) == 0)
                    {
                        ChangeBlock(x, y, z, 5);
                        ChangeBlock(x, y + 1, z, 5);
                        ChangeBlock(x, y + 2, z, 5);
                        ChangeBlock(x, y + 3, z, 5);
                        ChangeBlock(x + 1, y + 3, z + 1, 6);
                        ChangeBlock(x + 1, y + 3, z - 1, 6);
                        ChangeBlock(x - 1, y + 3, z + 1, 6);
                        ChangeBlock(x - 1, y + 3, z - 1, 6);
                        ChangeBlock(x + 1, y + 3, z + 0, 6);
                        ChangeBlock(x + 0, y + 3, z + 1, 6);
                        ChangeBlock(x - 1, y + 3, z + 0, 6);
                        ChangeBlock(x - 0, y + 3, z - 1, 6);
                        ChangeBlock(x, y + 4, z, 5);
                        ChangeBlock(x + 1, y + 4, z + 1, 6);
                        ChangeBlock(x + 1, y + 4, z - 1, 6);
                        ChangeBlock(x - 1, y + 4, z + 1, 6);
                        ChangeBlock(x - 1, y + 4, z - 1, 6);
                        ChangeBlock(x + 1, y + 4, z + 0, 6);
                        ChangeBlock(x + 0, y + 4, z + 1, 6);
                        ChangeBlock(x - 1, y + 4, z + 0, 6);
                        ChangeBlock(x - 0, y + 4, z - 1, 6);

                        ChangeBlock(x + 2, y + 4, z + 0, 6);
                        ChangeBlock(x + 2, y + 4, z + 1, 6);
                        ChangeBlock(x + 2, y + 4, z - 1, 6);

                        ChangeBlock(x - 2, y + 4, z + 0, 6);
                        ChangeBlock(x - 2, y + 4, z + 1, 6);
                        ChangeBlock(x - 2, y + 4, z - 1, 6);

                        ChangeBlock(x + 0, y + 4, z + 2, 6);
                        ChangeBlock(x + 1, y + 4, z + 2, 6);
                        ChangeBlock(x - 1, y + 4, z + 2, 6);

                        ChangeBlock(x + 0, y + 4, z - 2, 6);
                        ChangeBlock(x + 1, y + 4, z - 2, 6);
                        ChangeBlock(x - 1, y + 4, z - 2, 6);

                        ChangeBlock(x, y + 5, z, 5);
                        ChangeBlock(x + 1, y + 5, z + 1, 6);
                        ChangeBlock(x + 1, y + 5, z - 1, 6);
                        ChangeBlock(x - 1, y + 5, z + 1, 6);
                        ChangeBlock(x - 1, y + 5, z - 1, 6);
                        ChangeBlock(x + 1, y + 5, z + 0, 6);
                        ChangeBlock(x + 0, y + 5, z + 1, 6);
                        ChangeBlock(x - 1, y + 5, z + 0, 6);
                        ChangeBlock(x - 0, y + 5, z - 1, 6);

                        ChangeBlock(x + 2, y + 5, z + 0, 6);
                        ChangeBlock(x + 2, y + 5, z + 1, 6);
                        ChangeBlock(x + 2, y + 5, z - 1, 6);

                        ChangeBlock(x - 2, y + 5, z + 0, 6);
                        ChangeBlock(x - 2, y + 5, z + 1, 6);
                        ChangeBlock(x - 2, y + 5, z - 1, 6);

                        ChangeBlock(x + 0, y + 5, z + 2, 6);
                        ChangeBlock(x + 1, y + 5, z + 2, 6);
                        ChangeBlock(x - 1, y + 5, z + 2, 6);

                        ChangeBlock(x + 0, y + 5, z - 2, 6);
                        ChangeBlock(x + 1, y + 5, z - 2, 6);
                        ChangeBlock(x - 1, y + 5, z - 2, 6);

                        ChangeBlock(x, y + 6, z, 5);
                        ChangeBlock(x + 1, y + 6, z + 1, 6);
                        ChangeBlock(x + 1, y + 6, z - 1, 6);
                        ChangeBlock(x - 1, y + 6, z + 1, 6);
                        ChangeBlock(x - 1, y + 6, z - 1, 6);
                        ChangeBlock(x + 1, y + 6, z + 0, 6);
                        ChangeBlock(x + 0, y + 6, z + 1, 6);
                        ChangeBlock(x - 1, y + 6, z + 0, 6);
                        ChangeBlock(x - 0, y + 6, z - 1, 6);
                        ChangeBlock(x, y + 7, z, 6);
                        ChangeBlock(x + 1, y + 7, z + 0, 6);
                        ChangeBlock(x + 0, y + 7, z + 1, 6);
                        ChangeBlock(x - 1, y + 7, z + 0, 6);
                        ChangeBlock(x - 0, y + 7, z - 1, 6);
                        ChangeBlock(x, y + 8, z, 6);

                    }
                    randomCount += y;
                }
            }
            decoration = true;
        }

木を生やす位置は、シード値を決めたRandom関数とパーリンノイズで決めています。長々とChangeBlockしています。

ブロック更新時、毎回メッシュを生成するのをやめ、 refreshフラグを追加し、後でメッシュを更新するようしました。 (木を生やす際、ブロックの更新をたくさんするため)

今回は以上になります。

次回は草を生やします。

UnityでMinecraft風ゲームを作る その8「ブロック破壊のアニメーションを追加」

今回は「ブロック破壊のアニメーションを追加」です。


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

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


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

ブロック破壊時のアニメーションが追加されています。


原理は、ほんの少し大きい亀裂が入っている透明なキューブのプレハブを用意し、選択位置に生成しているだけです。

アニメーションはマテリアルを変更しています。


スクリプトの主な変更は以下の通りです

  • Chunk.cs 変更なし
  • ChunkManager.cs 変更なし
  • EnumData.cs 変更なし
  • PlayerControl.cs 変更なし
  • TargetControl.cs ブロック破壊時のアニメーションを追加

TargetControl.csを修正して実装しました。

おまけで手、音も追加しました。

効果音は初めて作りました(机を叩いて録音) 違和感があるかもしれませんが・・・

次回は木を生やすです。

UnityでMinecraft風ゲームを作る その7「チャンクのメッシュを分割し、制限を無くしていく」

今回は「チャンクのメッシュを分割し、制限を無くしていく」です。

今現在、Unityのゲームオブジェクトの頂点数は65535という制限があります。

頂点の多い3Dデータをインポートすると制限を超えないよう分割されます。

作成中Minecraft風ゲームのチャンクの大きさは幅8、高さ32でした。この控えめの数値はゲームオブジェクトの頂点数の制限を超えないようするための配慮でした(SetVerticesで制限以上は無視されて作られてしまう)

今回は頂点数が60000くらいになったらメッシュを分割し、チャンクの大きさの制限を無くしていこうと思います(もちろんマシンスペックの制限はありますが・・・)


※2019.01.16 追記

mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;

上記をSetVertices前に記入することで制限を上げることができるので、ゲームオブジェクトを分ける必要がないことが判明しました。


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

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


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

ぱっと見は変わりませんが、高さ制限が128になっていて、生成されるゲームオブジェクトChunkの配下にMeshが存在するのがわかります。 複雑な地形を生成するとMeshが増えていきます。


スクリプトの主な変更は以下の通りです

  • Chunk.cs 複数のメッシュを作成できるよう変更
  • ChunkManager.cs ゲームオブジェクトChunkの配下にMechオブジェクトを作成するよう修正
  • EnumData.cs 変更なし
  • PlayerControl.cs 変更なし
  • TargetControl.cs 変更なし

Chunk.cs

        //リストのリストに変更、複数のメッシュを作成することを可能にする
        List<List<Vector3>> verticeList = new List<List<Vector3>>();
        List<List<int>> faceList = new List<List<int>>();
        List<List<Vector2>> uvList = new List<List<Vector2>>();
        int faceCount;
        int listCount;

データの持ち方を修正しました。これに対応するよう修正が入ってます。

            //頂点数が限界値に近ずいた時、新たなメッシュを作成するために、初期化する
            if (60000 < faceCount)
            {
                faceCount = 0;
                listCount++;
                verticeList.Add(new List<Vector3>());
                faceList.Add(new List<int>());
                uvList.Add(new List<Vector2>());
            }

この辺りは、頂点数の制限が近づいた時の処理です

今回は以上です。

次回はブロック破壊アニメーションです。

UnityでMinecraft風ゲームを作る その6「ブロックを置いたり消したりする」

今回はブロックを置いたり消したりできるようにしたいと思います。

原理はレイを飛ばして当たった位置のチャンクのブロック情報を変更したらチャンクのMeshを毎回再生成しています。


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

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


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

左クリックでブロックを消す、右クリックでブロックを置けます。 置くブロックは土ブロック固定です。


スクリプトの主な変更は以下の通りです

  • Chunk.cs ブロックの変更処理とメッシュの更新処理を追加
  • ChunkManager.cs 座標計算系を追加しました。
  • EnumData.cs 変更なし
  • PlayerControl.cs 変更なし
  • TargetControl.cs カメラからレイを放ち、当たった箇所にブロック置くor消すの処理を追加

TargetControl.cs

        //画面の中心からレイを放ち、当たった位置から、選択されたブロックの座標、隣のブロックの座標を計算
        void ChangeRayHitBlock()
        {

            RaycastHit cameraHit;
            Vector3 center = new Vector3(Screen.width / 2, Screen.height / 2);
            Ray ray = Camera.main.ScreenPointToRay(center);

            if (Physics.Raycast(ray , out cameraHit, 6))
            {
                //レイの当たった方向を取得
                Direction hitDirection = CalculateFaceDirectionHit(cameraHit);
                //選択されたブロックの座標を計算
                Vector3 hitPoint = new Vector3(0, 0, 0);
                hitPoint.x = (int)Math.Round(cameraHit.point.x, MidpointRounding.AwayFromZero);
                hitPoint.y = (int)Math.Round(cameraHit.point.y, MidpointRounding.AwayFromZero);
                hitPoint.z = (int)Math.Round(cameraHit.point.z, MidpointRounding.AwayFromZero);
                switch (hitDirection)
                {
                    case Direction.Right:
                        //この計算は、中途半端な位置でもちゃんと座標を計算できるようにしている。今はあまり関係ない。
                        hitPoint.x = (int)Math.Round(cameraHit.point.x + 0.99f, MidpointRounding.AwayFromZero);
                        hitPoint.x--;
                        break;
                    case Direction.Front:
                        hitPoint.z = (int)Math.Round(cameraHit.point.z + 0.99f, MidpointRounding.AwayFromZero);
                        hitPoint.z--;
                        break;
                    case Direction.Top:
                        hitPoint.y = (int)Math.Round(cameraHit.point.y + 0.99f, MidpointRounding.AwayFromZero);
                        hitPoint.y--;
                        break;
                    case Direction.Left:
                        hitPoint.x = (int)Math.Round(cameraHit.point.x - 0.99f, MidpointRounding.AwayFromZero);
                        hitPoint.x++;
                        break;
                    case Direction.Back:
                        hitPoint.z = (int)Math.Round(cameraHit.point.z - 0.99f, MidpointRounding.AwayFromZero);
                        hitPoint.z++;
                        break;
                    case Direction.Bottom:
                        hitPoint.y = (int)Math.Round(cameraHit.point.y - 0.99f, MidpointRounding.AwayFromZero);
                        hitPoint.y++;
                        break;
                }
                //選択したブロックの位置からそのブロックが所属するチャンクを取得
                Chunk selectChunk = ChunkManager.GetChunk_World(hitPoint.x, hitPoint.z);
                //ヒットポイント(ワールド座標)からチャンクのローカルな座標に変換
                Vector3 selectIndex = ChunkManager.RestrictIndex(hitPoint);

                //隣接するブロック位置を取得
                Vector3 ajactWorldIndex = ChunkManager.GetAdjacentIndex(hitPoint, hitDirection);
                //隣接するブロックが所属するチャンクを取得
                Chunk ajactChunk = ChunkManager.GetChunk_World(ajactWorldIndex.x, ajactWorldIndex.z);
                //隣のブロック位置(ワールド座標)からチャンクのローカルな座標に変換
                Vector3 ajactIndex = ChunkManager.RestrictIndex(ajactWorldIndex);

                if (Input.GetMouseButtonDown(0))
                {
                    //選択した位置を1(空)にする、ブロックを消す
                    selectChunk.ChangeBlock((int)selectIndex.x, (int)selectIndex.y, (int)selectIndex.z, 1);
                }

                if (Input.GetMouseButtonDown(1))
                {
                    //プレイヤーから近い時、ブロックを置けない
                    if(1f < Vector3.Distance(transform.position, ajactWorldIndex))
                    {
                        //3(土ブロック)を隣接した位置に置く
                        ajactChunk.ChangeBlock((int)ajactIndex.x, (int)ajactIndex.y, (int)ajactIndex.z, 3);
                    }
                }
            }
        }

        //レイの当たった方向を計算
        Direction CalculateFaceDirectionHit(RaycastHit data)
        {
            float threshhold = 0.25f;

            if (data.normal.x > threshhold)
                return Direction.Right;
            else if (data.normal.x < -threshhold)
                return Direction.Left;
            else if (data.normal.z > threshhold)
                return Direction.Front;
            else if (data.normal.z < -threshhold)
                return Direction.Back;
            else if (data.normal.y > threshhold)
                return Direction.Top;
            else if (data.normal.y < -threshhold)
                return Direction.Bottom;

            return Direction.Last;
        }

レイから位置を計算する箇所です。


ChunkManager.cs

        //ワールド座標からチャンクを取得
        static public Chunk GetChunk_World(float worldX, float worldZ)
        {

            int cx = (int)(Math.Floor(worldX / chunkWidth));
            int cz = (int)(Math.Floor(worldZ / chunkWidth));

            return GetChunk(cx, cz);
        }
        //ワールド座標からチャンクのローカル座標に変換
        static public Vector3 RestrictIndex(Vector3 oldIndex)
        {
            int tmpX = (int)oldIndex.x % chunkWidth;
            if (tmpX < 0)
            {
                tmpX += chunkWidth;
            }
            int tmpZ = (int)oldIndex.z % chunkWidth;
            if (tmpZ < 0)
            {
                tmpZ += chunkWidth;
            }
            return new Vector3(tmpX, oldIndex.y, tmpZ);
        }
        //方向に対する座標の計算
        static public Vector3 GetAdjacentIndex(Vector3 index, Direction direction)
        {

            switch (direction)
            {
                case Direction.Bottom:
                    index.y--;
                    break;
                case Direction.Top:
                    index.y++;
                    break;
                case Direction.Left:
                    index.x--;
                    break;
                case Direction.Right:
                    index.x++;
                    break;
                case Direction.Back:
                    index.z--;
                    break;
                case Direction.Front:
                    index.z++;
                    break;
            }
            return index;
        }

座標計算系あたりの修正です。


Chunk.cs

        //指定の座標のブロックを変える
        public void ChangeBlock(int x, int y, int z, int blockIndex)
        {
            //ブロックリストのインデックスに変換
            int tmpint = ConvertBlockIndex(x, y, z);
            //ブロックを変更する
            blocks[tmpint] = blockIndex;
            //メッシュの更新
            RefreshMesh();

            //チャンクの隅の時、隣のチャンクもリフレッシュする
            if (x == ChunkManager.chunkWidth - 1)
            {
                Chunk tmp = ChunkManager.GetChunk(indexX + 1, indexZ);
                if (tmp != null)
                {
                    ChunkManager.GetChunk(indexX + 1, indexZ).RefreshMesh();
                }
            }
            if (x == 0)
            {
                Chunk tmp = ChunkManager.GetChunk(indexX - 1, indexZ);
                if (tmp != null)
                {
                    ChunkManager.GetChunk(indexX - 1, indexZ).RefreshMesh();
                }
            }
            if (z == ChunkManager.chunkWidth - 1)
            {
                Chunk tmp = ChunkManager.GetChunk(indexX, indexZ + 1);
                if (tmp != null)
                {
                    ChunkManager.GetChunk(indexX, indexZ + 1).RefreshMesh();
                }
            }
            if (z == 0)
            {
                Chunk tmp = ChunkManager.GetChunk(indexX, indexZ - 1);
                if (tmp != null)
                {
                    ChunkManager.GetChunk(indexX, indexZ - 1).RefreshMesh();
                }
            }
        }
        //メッシュの更新
        public void RefreshMesh()
        {
            Mesh tmpmesh = BuildVisualMesh();
            gameObject.GetComponent<MeshFilter>().mesh = tmpmesh;
            gameObject.GetComponent<MeshCollider>().sharedMesh = tmpmesh;
        }

ブロックの更新処理とメッシュの更新処理の箇所です。

次回は高さ制限を無くしていこうと思います。

UnityでMinecraft風ゲームを作る その5「テクスチャを貼る」

今回はテクスチャを貼っていこうと思います。(実験的公開版よりテクスチャの読み込み方を改善しています)


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

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


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

さらにマイクラっぽくなりましたね。


スクリプトの主な変更は以下の通りです

  • Chunk.cs uvListを追加、BlockDatabaseのtextureの番号から座標を計算し面に貼り付ける処理を追加
  • ChunkManager.cs マテリアルの名前をblockMaterialに変更
  • EnumData.cs BlockManager、BlockDatabaseを追加
  • PlayerControl.cs 変更なし
  • TargetControl.cs 変更なし

Chunk.csの変更箇所

        List<Vector2> uvList = new List<Vector2>();

uvの情報を格納するリストを追加しました

            mesh.SetUVs(0, uvList);

Meshにuvをセットする処理を追加

void AddFaceList(int block, Direction direction)
        {
            //テクスチャの座標を計算
            float px = BlockManager.blockList[block].texture[(int)direction] % 32;
            float py = 0;
            uvList.Add(new Vector2((0 + px) / 32F, py / 32F));
            uvList.Add(new Vector2((1 + px) / 32F, py / 32F));
            uvList.Add(new Vector2((1 + px) / 32F, (1 + py) / 32F));
            uvList.Add(new Vector2((0 + px) / 32F, (1 + py) / 32F));

            faceList.Add(faceCount + 0);
            faceList.Add(faceCount + 1);
            faceList.Add(faceCount + 3);
            faceList.Add(faceCount + 1);
            faceList.Add(faceCount + 2);
            faceList.Add(faceCount + 3);

            faceCount += 4;
        }

AddFaceListに渡すのもが増えました。テクスチャの座標を計算してuvListに追加しています。画像に対するtexture番号は左下から始まります。今回は一番下の列しか使わないためpyは0にしました。


EnumData.csの変更箇所

    public class BlockDatabase
    {
        //Top, Bottom, Right, Left, Front, Backの順で格納
        public int[] texture;
    }

    static public class BlockManager
    {
        static public Dictionary<int, BlockDatabase> blockList = new Dictionary<int, BlockDatabase>();

        static public void Init()
        {
            //ブロックエリア
            //未定義
            int blockNo = 0;
            blockList.Add(blockNo, new BlockDatabase());
            blockList[blockNo].texture = new int[6] { 0, 0, 0, 0, 0, 0 };
            //空気
            blockNo = 1;
            blockList.Add(blockNo, new BlockDatabase());
            blockList[blockNo].texture = new int[6] { 0, 0, 0, 0, 0, 0 };
            //草ブロック
            blockNo = 2;
            blockList.Add(blockNo, new BlockDatabase());
            blockList[blockNo].texture = new int[6] { 1, 3, 2, 2, 2, 2 };
            //土ブロック
            blockNo = 3;
            blockList.Add(blockNo, new BlockDatabase());
            blockList[blockNo].texture = new int[6] { 3, 3, 3, 3, 3, 3 };
            //石ブロック
            blockNo = 4;
            blockList.Add(blockNo, new BlockDatabase());
            blockList[blockNo].texture = new int[6] { 4, 4, 4, 4, 4, 4 };
        }
    }

Init()はChunkManager.csのはじめに呼んでいます。呼ばれたらblockListを生成しています。BlockDatabaseのtextureは画像の位置になります。土ブロック、石ブロックは追加してありますが、今回使用しません。


次回はブロックを置くところを作成したいと思います。