super1 发表于 2022-10-25 15:55

Unity实现Minecraft(七)——Chunk脚本

前言:前面一篇文章我们实现了ChunkRenderer脚本,主要是根据MeshData实现渲染。但是我们目前还没有任何一个类去填充MeshData(即MeshData的顶点List,三角形List等还没有数据)。所以我们将会在BlockHelper中进行MeshData的填充(因为BlockHelper是细化到Chunk中每个Block的每个面),而今天要写的Chunk脚本更像是一个辅助类去提供一些便利的方法供BlockHelper调用以便更好在Chunk内遍历时填充数据。
using System;
using UnityEngine;

public static class Chunk
{
    //遍历一个Chunk中的所有Block
    public static void LoopThroughTheBlocks(ChunkData chunkData, Action<int, int, int>
                                                                                                                                                                                        actionToPerform)
    {
      for (int index = 0; index < chunkData.blocks.Length; index++)
      {
            var position = GetPostitionFromIndex(chunkData, index);
            actionToPerform(position.x, position.y, position.z);//对方块进行的改变
      }
    }

    //一个根据block数组的index可以计算出相应block的(x,y,z)位置的算法(来源于StackOverFlow)
                /*      int zDirection=i%zLength;
                        int yDirection=(i/zLength)%yLength;
                        int xDirection=i/(ylength*zLength);
                */
    //根据Block的位置得到在Block数组中的位置
    private static Vector3Int GetPostitionFromIndex(ChunkData chunkData, int index)
    {
      int x = index % chunkData.chunkSize;
      int y = (index / chunkData.chunkSize) % chunkData.chunkHeight;
      int z = index / (chunkData.chunkSize * chunkData.chunkHeight);
      return new Vector3Int(x, y, z);
    }

    //在Chunk坐标系下
    //判断Block是否超出所属Chunk的界限
    private static bool InRange(ChunkData chunkData, int axisCoordinate)
    {
      if (axisCoordinate < 0 || axisCoordinate >= chunkData.chunkSize)
            return false;

      return true;
    }

    //同上
    private static bool InRangeHeight(ChunkData chunkData, int ycoordinate)
    {
      if (ycoordinate < 0 || ycoordinate >= chunkData.chunkHeight)
            return false;

      return true;
    }
    //根据Chunk坐标系的坐标得出该Block的类型
    public static BlockType GetBlockFromChunkCoordinates(ChunkData chunkData, Vector3Int chunkCoordinates)
                                                                                                                                                                                                                                Vector3Int chunkCoordinates)
    {
      return GetBlockFromChunkCoordinates(chunkData, chunkCoordinates.x, chunkCoordinates.y,chunkCoordinates.z);
                                                                                                                                                                                        chunkCoordinates.z);
    }

    public static BlockType GetBlockFromChunkCoordinates(ChunkData chunkData, int x, int y, int z)
    {
      if (InRange(chunkData, x) && InRangeHeight(chunkData, y) && InRange(chunkData, z))
      {
            int index = GetIndexFromPosition(chunkData, x, y, z);
            return chunkData.blocks;
      }

      return chunkData.worldReference.GetBlockFromChunkCoordinates(chunkData, chunkData.worldPosition.x + x, chunkData.worldPosition.y + y, chunkData.worldPosition.z + z);
    }
    //设置Block的类型
    public static void SetBlock(ChunkData chunkData, Vector3Int localPosition, BlockType block)
    {
      if (InRange(chunkData, localPosition.x) && InRangeHeight(chunkData, localPosition.y) && InRange(chunkData, localPosition.z))
      {
            int index = GetIndexFromPosition(chunkData, localPosition.x, localPosition.y, localPosition.z);
            chunkData.blocks = block;
      }
      else
      {
            throw new Exception("Need to ask World for appropiate chunk");
      }
    }
    //从一个Block的坐标得到在数组中的位置
    /*i (x,y,z)
                        0 (0,0,0)
                        1 (0,0,1)
                        2 (0,0,2)
                        3 (0,1,0)
                        4 (0,1,1)
                  5 (0,1,2)
                        6 (0,2,0)
                        ......
                        19 (2,0,1)
                        26 (2,2,2)
                        i=z+y*ZSize+x*ZSize*YSize*/
    private static int GetIndexFromPosition(ChunkData chunkData, int x, int y, int z)
    {
      return x + chunkData.chunkSize * y + chunkData.chunkSize * chunkData.chunkHeight * z;
    }
    //根据Chunk坐标系的坐标得到对应的Block
    public static Vector3Int GetBlockInChunkCoordinates(ChunkData chunkData, Vector3Int pos)
    {
      return new Vector3Int
      {
            x = pos.x - chunkData.worldPosition.x,
            y = pos.y - chunkData.worldPosition.y,
            z = pos.z - chunkData.worldPosition.z
      };
    }
    //获得MeshData的方法
    public static MeshData GetChunkMeshData(ChunkData chunkData)
    {
      MeshData meshData = new MeshData(true);

      LoopThroughTheBlocks(chunkData, (x, y, z) => meshData = BlockHelper.GetMeshData(chunkData, x, y, z, meshData, chunkData.blocks));


      return meshData;
    }
   
    internal static Vector3Int ChunkPositionFromBlockCoords(World world, int x, int y, int z)
    {
      Vector3Int pos = new Vector3Int
      {
            x = Mathf.FloorToInt(x / (float)world.chunkSize) * world.chunkSize,
            y = Mathf.FloorToInt(y / (float)world.chunkHeight) * world.chunkHeight,
            z = Mathf.FloorToInt(z / (float)world.chunkSize) * world.chunkSize
      };
      return pos;
    }
}
页: [1]
查看完整版本: Unity实现Minecraft(七)——Chunk脚本