Skip to content

Instantly share code, notes, and snippets.

@tsaodown
Last active May 17, 2016 22:46
Show Gist options
  • Save tsaodown/1b51b6bd1936208bfe2076deb3a160a2 to your computer and use it in GitHub Desktop.
Save tsaodown/1b51b6bd1936208bfe2076deb3a160a2 to your computer and use it in GitHub Desktop.
DerpCraft - Building a MineCraft Clone in Unity - Chunks | Full code available at https://git.io/vrlT3
using Utilities;
public class AirBlock : Block {
static Block instance;
public static Block Instance {
get {
if (instance == null) {
instance = new AirBlock();
}
return instance;
}
}
AirBlock() {
}
protected override bool IsSolid() {
return false;
}
public override MeshData GetBlockData(Chunk chunk, Vector3Int position,
MeshData collectedMeshData) {
return collectedMeshData;
}
}
using UnityEngine;
using Utilities;
public class Block {
// Enumerator representing the face of the block.
public enum FaceDirection {
North,
// +z
South,
// -z
East,
// +x
West,
// -x
Top,
// +y
Bottom
// -y
}
// Target texture is 16x16 of 16x16 textures.
static readonly float tileSize = 0.0625f;
protected virtual Vector2Int TextureTilePosition(Chunk chunk,
FaceDirection direction) {
// Default is a hot pink box.
return new Vector2Int(0, 1);
}
protected virtual bool IsSolid() {
return true;
}
// Calculates the UVs for a given direction on the block.
protected virtual Vector2[] FaceUVs(Chunk chunk, FaceDirection direction) {
Vector2Int texTile = TextureTilePosition(chunk, direction);
var uvs = new Vector2[4];
// top-left, top-right, bottom-right, bottom-left
uvs[0] = texTile * tileSize + Vector2.up * tileSize;
uvs[1] = texTile * tileSize + Vector2.one * tileSize;
uvs[2] = texTile * tileSize + Vector2.right * tileSize;
uvs[3] = texTile * tileSize;
return uvs;
}
public virtual MeshData GetBlockData(Chunk chunk, Vector3Int position,
MeshData collectedMeshData) {
// Go through each face and get the vertices, indices, normals, and UVs.
if (!chunk[position + Vector3Int.up].IsSolid())
collectedMeshData = FaceDataTop(chunk, position, collectedMeshData);
if (!chunk[position + Vector3Int.down].IsSolid())
collectedMeshData = FaceDataBottom(chunk, position, collectedMeshData);
if (!chunk[position + Vector3Int.north].IsSolid())
collectedMeshData = FaceDataNorth(chunk, position, collectedMeshData);
if (!chunk[position + Vector3Int.south].IsSolid())
collectedMeshData = FaceDataSouth(chunk, position, collectedMeshData);
if (!chunk[position + Vector3Int.east].IsSolid())
collectedMeshData = FaceDataEast(chunk, position, collectedMeshData);
if (!chunk[position + Vector3Int.west].IsSolid())
collectedMeshData = FaceDataWest(chunk, position, collectedMeshData);
return collectedMeshData;
}
protected virtual MeshData FaceDataTop(Chunk chunk, Vector3Int position,
MeshData collectedMeshData) {
// top-left, top-right, bottom-right, bottom-left
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y + 0.5f, position.z + 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y + 0.5f, position.z + 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y + 0.5f, position.z - 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y + 0.5f, position.z - 0.5f));
// Add tris from verts.
collectedMeshData.AddQuadTriangles();
// Add UVs for face.
collectedMeshData.uvs.AddRange(FaceUVs(chunk, FaceDirection.Top));
return collectedMeshData;
}
protected virtual MeshData FaceDataBottom(Chunk chunk, Vector3Int position,
MeshData collectedMeshData) {
// top-left, top-right, bottom-right, bottom-left
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y - 0.5f, position.z - 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y - 0.5f, position.z - 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y - 0.5f, position.z + 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y - 0.5f, position.z + 0.5f));
// Add tris from verts.
collectedMeshData.AddQuadTriangles();
// Add UVs for face.
collectedMeshData.uvs.AddRange(FaceUVs(chunk, FaceDirection.Bottom));
return collectedMeshData;
}
protected virtual MeshData FaceDataNorth(Chunk chunk, Vector3Int position,
MeshData collectedMeshData) {
// top-left, top-right, bottom-right, bottom-left
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y + 0.5f, position.z + 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y + 0.5f, position.z + 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y - 0.5f, position.z + 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y - 0.5f, position.z + 0.5f));
// Add tris from verts.
collectedMeshData.AddQuadTriangles();
// Add UVs for face.
collectedMeshData.uvs.AddRange(FaceUVs(chunk, FaceDirection.North));
return collectedMeshData;
}
protected virtual MeshData FaceDataSouth(Chunk chunk, Vector3Int position,
MeshData collectedMeshData) {
// top-left, top-right, bottom-right, bottom-left
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y + 0.5f, position.z - 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y + 0.5f, position.z - 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y - 0.5f, position.z - 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y - 0.5f, position.z - 0.5f));
// Add tris from verts.
collectedMeshData.AddQuadTriangles();
// Add UVs for face.
collectedMeshData.uvs.AddRange(FaceUVs(chunk, FaceDirection.South));
return collectedMeshData;
}
protected virtual MeshData FaceDataEast(Chunk chunk, Vector3Int position,
MeshData collectedMeshData) {
// top-left, top-right, bottom-right, bottom-left
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y + 0.5f, position.z - 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y + 0.5f, position.z + 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y - 0.5f, position.z + 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x + 0.5f, position.y - 0.5f, position.z - 0.5f));
// Add tris from verts.
collectedMeshData.AddQuadTriangles();
// Add UVs for face.
collectedMeshData.uvs.AddRange(FaceUVs(chunk, FaceDirection.East));
return collectedMeshData;
}
protected virtual MeshData FaceDataWest(Chunk chunk, Vector3Int position,
MeshData collectedMeshData) {
// top-left, top-right, bottom-right, bottom-left
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y + 0.5f, position.z + 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y + 0.5f, position.z - 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y - 0.5f, position.z - 0.5f));
collectedMeshData.AddVertex(new Vector3(
position.x - 0.5f, position.y - 0.5f, position.z + 0.5f));
// Add tris from verts.
collectedMeshData.AddQuadTriangles();
// Add UVs for face.
collectedMeshData.uvs.AddRange(FaceUVs(chunk, FaceDirection.West));
return collectedMeshData;
}
}
using UnityEngine;
using Utilities;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshCollider))]
public class Chunk : MonoBehaviour {
public static int Size = 16;
public static int Height = 32;
Block[,,] blocks = new Block[Size, Height, Size];
public Block this[int x, int y, int z] {
get {
if (x < 0 || x >= Size || y < 0 || y >= Height || z < 0 || z >= Size) {
return AirBlock.Instance;
}
return blocks[x, y, z];
}
set {
if (x < 0 || x >= Size || y < 0 || y >= Height || z < 0 || z >= Size) {
return;
}
blocks[x, y, z] = value;
}
}
public Block this[Vector3Int v] {
get {
return this[v.x, v.y, v.z];
}
set {
this[v.x, v.y, v.z] = value;
}
}
void Start() {
var meshData = new MeshData();
for (int x = 0; x < Size; x++) {
for (int y = 0; y < Height; y++) {
for (int z = 0; z < Size; z++) {
float rand = Random.value;
blocks[x, y, z] = rand > 0.5 ? AirBlock.Instance : new GrassBlock();
}
}
}
for (int x = 0; x < Size; x++) {
for (int y = 0; y < Height; y++) {
for (int z = 0; z < Size; z++) {
meshData = blocks[x, y, z].GetBlockData(
this, new Vector3Int(x, y, z), meshData);
}
}
}
meshData.RecalculateNormals();
// Set the mesh in the MeshFilter for display.
var filter = GetComponent<MeshFilter>();
filter.mesh.vertices = meshData.verts.ToArray();
filter.mesh.triangles = meshData.tris.ToArray();
filter.mesh.normals = meshData.normals.ToArray();
filter.mesh.uv = meshData.uvs.ToArray();
// Set the mesh in the MeshCollider for collision.
var coll = GetComponent<MeshCollider>();
var collMesh = new Mesh();
collMesh.vertices = meshData.colliderVerts.ToArray();
collMesh.triangles = meshData.colliderTris.ToArray();
collMesh.normals = meshData.colliderNormals.ToArray();
coll.sharedMesh = collMesh;
transform.position = transform.position +
Vector3.one * 0.5f - new Vector3(Size / 2, 0, Size / 2);
}
}
using UnityEngine;
using Utilities;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshCollider))]
public class Chunk : MonoBehaviour {
public static int Size = 16;
public static int Height = 32;
Block[,,] blocks = new Block[Size, Height, Size];
class NullBlock : Block {
static Block instance;
public static Block Instance {
get {
if (instance == null) {
instance = new NullBlock();
}
return instance;
}
}
protected override bool IsSolid() {
return false;
}
}
public Block this[int x, int y, int z] {
get {
if (x < 0 || x >= Size || y < 0 || y >= Height || z < 0 || z >= Size) {
return NullBlock.Instance;
}
return blocks[x, y, z];
}
set {
if (x < 0 || x >= Size || y < 0 || y >= Height || z < 0 || z >= Size) {
return;
}
blocks[x, y, z] = value;
}
}
public Block this[Vector3Int v] {
get {
return this[v.x, v.y, v.z];
}
set {
this[v.x, v.y, v.z] = value;
}
}
void Start() {
var meshData = new MeshData();
for (int x = 0; x < Size; x++) {
for (int y = 0; y < Height; y++) {
for (int z = 0; z < Size; z++) {
blocks[x, y, z] = new GrassBlock();
}
}
}
for (int x = 0; x < Size; x++) {
for (int y = 0; y < Height; y++) {
for (int z = 0; z < Size; z++) {
meshData = blocks[x, y, z].GetBlockData(
this, new Vector3Int(x, y, z), meshData);
}
}
}
meshData.RecalculateNormals();
// Set the mesh in the MeshFilter for display.
var filter = GetComponent<MeshFilter>();
filter.mesh.vertices = meshData.verts.ToArray();
filter.mesh.triangles = meshData.tris.ToArray();
filter.mesh.normals = meshData.normals.ToArray();
filter.mesh.uv = meshData.uvs.ToArray();
// Set the mesh in the MeshCollider for collision.
var coll = GetComponent<MeshCollider>();
var collMesh = new Mesh();
collMesh.vertices = meshData.colliderVerts.ToArray();
collMesh.triangles = meshData.colliderTris.ToArray();
collMesh.normals = meshData.colliderNormals.ToArray();
coll.sharedMesh = collMesh;
transform.position = transform.position +
Vector3.one * 0.5f - new Vector3(Size / 2, 0, Size / 2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment