Unity3D创建可编辑体素环境的最佳方式

时间:2015-06-17 04:19:43

标签: java c# unity3d sandbox voxel

我希望为类似于Minecraft的游戏创建动态体素环境。我的主要语言是Java,但是因为我不想从头开始编写游戏,所以我决定选择Unity3D。我在这里按照本教程了解主题:http://alexstv.com/index.php/category/voxels

我的环境正常运行,并且已经整合了我自己的FPS控制器预制件。但是现在我的下一个目标是缩小块。基本上,我想将每个立方体拆分为另一个8x8x8可编辑表面。这将为世界带来更大的灵活性。在Block类中,我可以使用Block.blockSize让各个块看起来更小。但是,当我这样做时,块之间和块之间有空格。显然我错过了一些东西,但我不确定是什么。我想我会在这个代码中寻找决定块和块间距的因素。

此外,我想到的可能只是将角色升级为巨人......再次不确定这是否是最好的路线。

这是我的Block类:

using UnityEngine;
using System.Collections;
using System;

[Serializable]
public class Block
{
    public enum Direction { north, east, south, west, up, down };


    public struct Tile { public int x; public int y;}



    const float tileSize = 0.25f;
    const float blockSize = 0.5f;
    const int blockSpace = 1;

    public bool changed = true;

    //Base block constructor
    public Block()
    {

    }

    public virtual MeshData Blockdata
        (Chunk chunk, int x, int y, int z, MeshData meshData)
    {


        meshData.useRenderDataForCol = true;

        if (!chunk.GetBlock(x, y + blockSpace, z).IsSolid(Direction.down))
        {
            meshData = FaceDataUp(chunk, x, y, z, meshData);
        }

        if (!chunk.GetBlock(x, y - blockSpace, z).IsSolid(Direction.up))
        {
            meshData = FaceDataDown(chunk, x, y, z, meshData);
        }

        if (!chunk.GetBlock(x, y, z +blockSpace).IsSolid(Direction.south))
        {
            meshData = FaceDataNorth(chunk, x, y, z, meshData);
        }

        if (!chunk.GetBlock(x, y, z - blockSpace).IsSolid(Direction.north))
        {
            meshData = FaceDataSouth(chunk, x, y, z, meshData);
        }

        if (!chunk.GetBlock(x + blockSpace, y, z).IsSolid(Direction.west))
        {
            meshData = FaceDataEast(chunk, x, y, z, meshData);
        }

        if (!chunk.GetBlock(x - blockSpace, y, z).IsSolid(Direction.east))
        {
            meshData = FaceDataWest(chunk, x, y, z, meshData);
        }

        return meshData;

    }





    protected virtual MeshData FaceDataUp
        (Chunk chunk, int x, int y, int z, MeshData meshData)
    {

        meshData.AddVertex(new Vector3(x - blockSize, y + blockSize, z + blockSize));
        meshData.AddVertex(new Vector3(x + blockSize, y + blockSize, z + blockSize));
        meshData.AddVertex(new Vector3(x + blockSize, y + blockSize, z - blockSize));
        meshData.AddVertex(new Vector3(x - blockSize, y + blockSize, z - blockSize));

        meshData.AddQuadTriangles();
        meshData.uv.AddRange(FaceUVs(Direction.up));
        return meshData;
    }

    protected virtual MeshData FaceDataDown
        (Chunk chunk, int x, int y, int z, MeshData meshData)
    {
        meshData.AddVertex(new Vector3(x - blockSize, y - blockSize, z - blockSize));
        meshData.AddVertex(new Vector3(x + blockSize, y - blockSize, z - blockSize));
        meshData.AddVertex(new Vector3(x + blockSize, y - blockSize, z + blockSize));
        meshData.AddVertex(new Vector3(x - blockSize, y - blockSize, z + blockSize));

        meshData.AddQuadTriangles();
        meshData.uv.AddRange(FaceUVs(Direction.down));
        return meshData;
    }

    protected virtual MeshData FaceDataNorth
        (Chunk chunk, int x, int y, int z, MeshData meshData)
    {
        meshData.AddVertex(new Vector3(x + blockSize, y - blockSize, z + blockSize));
        meshData.AddVertex(new Vector3(x + blockSize, y + blockSize, z + blockSize));
        meshData.AddVertex(new Vector3(x - blockSize, y + blockSize, z + blockSize));
        meshData.AddVertex(new Vector3(x - blockSize, y - blockSize, z + blockSize));

        meshData.AddQuadTriangles();
        meshData.uv.AddRange(FaceUVs(Direction.north));
        return meshData;
    }

    protected virtual MeshData FaceDataEast
        (Chunk chunk, int x, int y, int z, MeshData meshData)
    {
        meshData.AddVertex(new Vector3(x + blockSize, y - blockSize, z - blockSize));
        meshData.AddVertex(new Vector3(x + blockSize, y + blockSize, z - blockSize));
        meshData.AddVertex(new Vector3(x + blockSize, y + blockSize, z + blockSize));
        meshData.AddVertex(new Vector3(x + blockSize, y - blockSize, z + blockSize));

        meshData.AddQuadTriangles();
        meshData.uv.AddRange(FaceUVs(Direction.east));
        return meshData;
    }

    protected virtual MeshData FaceDataSouth
        (Chunk chunk, int x, int y, int z, MeshData meshData)
    {
        meshData.AddVertex(new Vector3(x - blockSize, y - blockSize, z - blockSize));
        meshData.AddVertex(new Vector3(x - blockSize, y + blockSize, z - blockSize));
        meshData.AddVertex(new Vector3(x + blockSize, y + blockSize, z - blockSize));
        meshData.AddVertex(new Vector3(x + blockSize, y - blockSize, z - blockSize));

        meshData.AddQuadTriangles();
        meshData.uv.AddRange(FaceUVs(Direction.south));
        return meshData;
    }

    protected virtual MeshData FaceDataWest
        (Chunk chunk, int x, int y, int z, MeshData meshData)
    {
        meshData.AddVertex(new Vector3(x - blockSize, y - blockSize, z + blockSize));
        meshData.AddVertex(new Vector3(x - blockSize, y + blockSize, z + blockSize));
        meshData.AddVertex(new Vector3(x - blockSize, y + blockSize, z - blockSize));
        meshData.AddVertex(new Vector3(x - blockSize, y - blockSize, z - blockSize));

        meshData.AddQuadTriangles();
        meshData.uv.AddRange(FaceUVs(Direction.west));
        return meshData;
    }

    public virtual Tile TexturePosition(Direction direction)
    {
        Tile tile = new Tile();
        tile.x = 0;
        tile.y = 0;

        return tile;
    }

    public virtual Vector2[] FaceUVs(Direction direction)
    {
        Vector2[] UVs = new Vector2[4];
        Tile tilePos = TexturePosition(direction);

        UVs[0] = new Vector2(tileSize * tilePos.x + tileSize,
            tileSize * tilePos.y);
        UVs[1] = new Vector2(tileSize * tilePos.x + tileSize,
            tileSize * tilePos.y + tileSize);
        UVs[2] = new Vector2(tileSize * tilePos.x,
            tileSize * tilePos.y + tileSize);
        UVs[3] = new Vector2(tileSize * tilePos.x,
            tileSize * tilePos.y);

        return UVs;
    }

    public virtual bool IsSolid(Direction direction)
    {
        switch (direction)
        {
            case Direction.north:
                return true;
            case Direction.east:
                return true;
            case Direction.south:
                return true;
            case Direction.west:
                return true;
            case Direction.up:
                return true;
            case Direction.down:
                return true;
        }

        return false;
    }

}

世界级:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class World : MonoBehaviour {

    public Dictionary<WorldPos, Chunk> chunks = new Dictionary<WorldPos, Chunk>();
    public GameObject chunkPrefab;

    public string worldName = "world";

    public void CreateChunk(int x, int y, int z)
    {
        WorldPos worldPos = new WorldPos(x, y, z);

        //Instantiate the chunk at the coordinates using the chunk prefab
        GameObject newChunkObject = Instantiate(
                        chunkPrefab, new Vector3(x, y, z),
                        Quaternion.Euler(Vector3.zero)
                    ) as GameObject;

        Chunk newChunk = newChunkObject.GetComponent<Chunk>();

        newChunk.pos = worldPos;
        newChunk.world = this;

        //Add it to the chunks dictionary with the position as the key
        chunks.Add(worldPos, newChunk);

        var terrainGen = new TerrainGen();
        newChunk = terrainGen.ChunkGen(newChunk);

        newChunk.SetBlocksUnmodified();

        Serialization.Load(newChunk);
    }

    public void DestroyChunk(int x, int y, int z)
    {
        Chunk chunk = null;
        if (chunks.TryGetValue(new WorldPos(x, y, z), out chunk))
        {
            Serialization.SaveChunk(chunk);
            Object.Destroy(chunk.gameObject);
            chunks.Remove(new WorldPos(x, y, z));
        }
    }

    public Chunk GetChunk(int x, int y, int z)
    {
        WorldPos pos = new WorldPos();
        float multiple = Chunk.chunkSize;
        pos.x = Mathf.FloorToInt(x / multiple) * Chunk.chunkSize;
        pos.y = Mathf.FloorToInt(y / multiple) * Chunk.chunkSize;
        pos.z = Mathf.FloorToInt(z / multiple) * Chunk.chunkSize;

        Chunk containerChunk = null;

        chunks.TryGetValue(pos, out containerChunk);

        return containerChunk;
    }

    public Block GetBlock(int x, int y, int z)
    {
        Chunk containerChunk = GetChunk(x, y, z);

        if (containerChunk != null)
        {
            Block block = containerChunk.GetBlock(
                x - containerChunk.pos.x,
                y - containerChunk.pos.y,
                z - containerChunk.pos.z);

            return block;
        }
        else
        {
            return new BlockAir();
        }

    }

    public void SetBlock(int x, int y, int z, Block block)
    {
        Chunk chunk = GetChunk(x, y, z);

        if (chunk != null)
        {
            chunk.SetBlock(x - chunk.pos.x, y - chunk.pos.y, z - chunk.pos.z, block);
            chunk.update = true;

            UpdateIfEqual(x - chunk.pos.x, 0, new WorldPos(x - 1, y, z));
            UpdateIfEqual(x - chunk.pos.x, Chunk.chunkSize - 1, new WorldPos(x + 1, y, z));
            UpdateIfEqual(y - chunk.pos.y, 0, new WorldPos(x, y - 1, z));
            UpdateIfEqual(y - chunk.pos.y, Chunk.chunkSize - 1, new WorldPos(x, y + 1, z));
            UpdateIfEqual(z - chunk.pos.z, 0, new WorldPos(x, y, z - 1));
            UpdateIfEqual(z - chunk.pos.z, Chunk.chunkSize - 1, new WorldPos(x, y, z + 1));

        }
    }

    void UpdateIfEqual(int value1, int value2, WorldPos pos)
    {
        if (value1 == value2)
        {
            Chunk chunk = GetChunk(pos.x, pos.y, pos.z);
            if (chunk != null)
                chunk.update = true;
        }
    }
}

如果您需要更多代码或信息,请告诉我们!

我也愿意接受有关其他更好的引擎或方法的建议!

1 个答案:

答案 0 :(得分:1)

我认为你需要使用一些体素资产。例如: https://www.assetstore.unity3d.com/en/#!/content/12689