using System.Collections.Generic; using UnityEngine; namespace Assets.Scripts { public class Chunk { public ChunkCoord coord; private GameObject _chunkObject; private MeshRenderer _meshRenderer; private MeshFilter _meshFilter; private int _vertexIndex = 0; private readonly List _vertices = new List(); private readonly List _triangles = new List(); private readonly List _uvs = new List(); private readonly byte[,,] _voxelMap = new byte[VoxelData.ChunkWidth, VoxelData.ChunkHeight, VoxelData.ChunkWidth]; private World _world; public Chunk(ChunkCoord _coord, World world) { coord = _coord; _world = world; _chunkObject = new GameObject(); _meshFilter = _chunkObject.AddComponent(); _meshRenderer = _chunkObject.AddComponent(); _meshRenderer.material = _world.material; _chunkObject.transform.SetParent(_world.transform); _chunkObject.transform.position = new Vector3(coord.x * VoxelData.ChunkWidth, 0, coord.z * VoxelData.ChunkWidth); _chunkObject.name = "Chunk [" + coord.x + ":" + coord.z + "]"; PopulateVoxelMap(); CreateMeshData(); CreateMesh(); } private void PopulateVoxelMap() { for (int y = 0; y < VoxelData.ChunkHeight; y++) { for (int x = 0; x < VoxelData.ChunkWidth; x++) { for (int z = 0; z < VoxelData.ChunkWidth; z++) { _voxelMap[x, y, z] = _world.GenerateBlock(new Vector3(x, y, z) + Position); } } } } private void CreateMeshData() { for (int y = 0; y < VoxelData.ChunkHeight; y++) { for (int x = 0; x < VoxelData.ChunkWidth; x++) { for (int z = 0; z < VoxelData.ChunkWidth; z++) { if (!_world.blockTypes[_voxelMap[x, y, z]].isSolid) continue; AddVoxelDataToChunk(new Vector3(x, y, z)); } } } } public bool IsActive { get { return _chunkObject.activeSelf; } set { _chunkObject.SetActive(value); } } public Vector3 Position { get { return _chunkObject.transform.position; } } private bool CheckVoxel(Vector3 pos) { int x = Mathf.FloorToInt(pos.x); int y = Mathf.FloorToInt(pos.y); int z = Mathf.FloorToInt(pos.z); if (!IsVoxelInChunk(x, y, z)) return _world.blockTypes[_world.GenerateBlock(pos + Position)].isSolid; return _world.blockTypes[_voxelMap[x, y, z]].isSolid; } private void AddVoxelDataToChunk(Vector3 pos) { for (int p = 0; p < 6; p++) { if (CheckVoxel(pos + VoxelData.FaceChecks[p])) continue; byte blockID = _voxelMap[(int)pos.x, (int)pos.y, (int)pos.z]; _vertices.Add(pos + VoxelData.VoxelVerts[VoxelData.VoxelTris[p, 0]]); _vertices.Add(pos + VoxelData.VoxelVerts[VoxelData.VoxelTris[p, 1]]); _vertices.Add(pos + VoxelData.VoxelVerts[VoxelData.VoxelTris[p, 2]]); _vertices.Add(pos + VoxelData.VoxelVerts[VoxelData.VoxelTris[p, 3]]); AddTexture(_world.blockTypes[blockID].GetTextureID(p)); _triangles.Add(_vertexIndex); _triangles.Add(_vertexIndex + 1); _triangles.Add(_vertexIndex + 2); _triangles.Add(_vertexIndex + 2); _triangles.Add(_vertexIndex + 1); _triangles.Add(_vertexIndex + 3); _vertexIndex += 4; } } private void CreateMesh() { Mesh mesh = new Mesh(); mesh.vertices = _vertices.ToArray(); mesh.triangles = _triangles.ToArray(); mesh.uv = _uvs.ToArray(); mesh.RecalculateNormals(); _meshFilter.mesh = mesh; } private void AddTexture(int textureID) { float y = textureID / VoxelData.TextureAtlasSizeInBlocks; float x = textureID - (y * VoxelData.TextureAtlasSizeInBlocks); x *= VoxelData.NormalizedBlockTextureSize; y *= VoxelData.NormalizedBlockTextureSize; y = 1f - y - VoxelData.NormalizedBlockTextureSize; _uvs.Add(new Vector2(x, y)); _uvs.Add(new Vector2(x, y + VoxelData.NormalizedBlockTextureSize)); _uvs.Add(new Vector2(x + VoxelData.NormalizedBlockTextureSize, y)); _uvs.Add(new Vector2(x + VoxelData.NormalizedBlockTextureSize, y + VoxelData.NormalizedBlockTextureSize)); } private bool IsVoxelInChunk(int x, int y, int z) { return !(x < 0 || x > VoxelData.ChunkWidth - 1 || y < 0 || y > VoxelData.ChunkHeight - 1 || z < 0 || z > VoxelData.ChunkWidth - 1); } } public class ChunkCoord { public int x; public int z; public ChunkCoord(int _x, int _z) { this.x = _x; this.z = _z; } public override bool Equals(object obj) { if (!(obj is ChunkCoord)) return false; ChunkCoord other = (ChunkCoord) obj; return (other.x == x && other.z == z); } public override int GetHashCode() => base.GetHashCode(); } }