Last active
June 7, 2016 23:33
-
-
Save tsaodown/afcb082a213bbf8eb0b16ab1f7a34021 to your computer and use it in GitHub Desktop.
DerpCraft - Building a MineCraft Clone in Unity - ChunkManager | Full code available at https://git.io/vok6S
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
public Texture2D textureAtlas; | |
float[,] heightMap; | |
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 Awake() { | |
heightMap = Noise2DGenerator.Instance.GenerateNoise( | |
Vector3Utilities.XZPlane(transform.position), Vector2Int.one * Size); | |
var rend = GetComponent<MeshRenderer>(); | |
rend.material.mainTexture = textureAtlas; | |
rend.material.shader = Shader.Find("Mobile/Diffuse"); | |
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] = y > heightMap[x, z] * Height ? | |
AirBlock.Instance : new GrassBlock(); | |
} | |
} | |
} | |
} | |
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++) { | |
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); | |
} | |
// Convenience function to get a world position in chunk space. | |
public static Vector2Int WorldSpaceToChunkSpace(Vector2 position) { | |
return new Vector2Int(Mathf.RoundToInt(position.x / Size), | |
Mathf.RoundToInt(position.y / Size)); | |
} | |
public static Vector2Int WorldSpaceToChunkSpace(Vector3 position) { | |
var v2 = new Vector2(position.x, position.z); | |
return WorldSpaceToChunkSpace(v2); | |
} | |
public static Vector3 ChunkSpaceToWorldSpace(Vector2Int position) { | |
return Vector2Utilities.XZPlane((position * Size) - | |
(Vector2Int.one * Size / 2) + (Vector2.one * 0.5f)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
public Texture2D textureAtlas; | |
float[,] heightMap; | |
Block[,,] blocks = new Block[Size, Height, Size]; | |
public enum ChunkDirection { | |
North, | |
South, | |
East, | |
West | |
} | |
public Block this[int x, int y, int z] { | |
get { | |
if (x < 0) { | |
var adjacentChunk = GetAdjacentChunk(this, ChunkDirection.West); | |
if (adjacentChunk == null) { | |
return AirBlock.Instance; | |
} | |
return adjacentChunk[Size + x, y, z]; | |
} else if (x >= Size) { | |
var adjacentChunk = GetAdjacentChunk(this, ChunkDirection.East); | |
if (adjacentChunk == null) { | |
return AirBlock.Instance; | |
} | |
return adjacentChunk[Size - x, y, z]; | |
} else if (z < 0) { | |
var adjacentChunk = GetAdjacentChunk(this, ChunkDirection.South); | |
if (adjacentChunk == null) { | |
return AirBlock.Instance; | |
} | |
return adjacentChunk[x, y, Size + z]; | |
} else if (z >= Size) { | |
var adjacentChunk = GetAdjacentChunk(this, ChunkDirection.North); | |
if (adjacentChunk == null) { | |
return AirBlock.Instance; | |
} | |
return adjacentChunk[x, y, Size - z]; | |
} else if (y < 0 || y >= Height) { | |
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 Awake() { | |
heightMap = Noise2DGenerator.Instance.GenerateNoise( | |
Vector3Utilities.XZPlane(transform.position), Vector2Int.one * Size); | |
var rend = GetComponent<MeshRenderer>(); | |
rend.material.mainTexture = textureAtlas; | |
rend.material.shader = Shader.Find("Mobile/Diffuse"); | |
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] = y > heightMap[x, z] * Height ? | |
AirBlock.Instance : new GrassBlock(); | |
} | |
} | |
} | |
} | |
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++) { | |
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); | |
} | |
public static Chunk GetAdjacentChunk(Chunk chunk, ChunkDirection direction) { | |
Vector2Int chunkPosition = WorldSpaceToChunkSpace(chunk.transform.position); | |
switch (direction) { | |
case ChunkDirection.North: | |
return ChunkManager.Instance[chunkPosition + Vector2Int.up]; | |
case ChunkDirection.South: | |
return ChunkManager.Instance[chunkPosition + Vector2Int.down]; | |
case ChunkDirection.East: | |
return ChunkManager.Instance[chunkPosition + Vector2Int.right]; | |
case ChunkDirection.West: | |
return ChunkManager.Instance[chunkPosition + Vector2Int.left]; | |
default: | |
return chunk; | |
} | |
} | |
// Convenience function to get a world position in chunk space. | |
public static Vector2Int WorldSpaceToChunkSpace(Vector2 position) { | |
return new Vector2Int(Mathf.RoundToInt(position.x / Size), | |
Mathf.RoundToInt(position.y / Size)); | |
} | |
public static Vector2Int WorldSpaceToChunkSpace(Vector3 position) { | |
var v2 = new Vector2(position.x, position.z); | |
return WorldSpaceToChunkSpace(v2); | |
} | |
public static Vector3 ChunkSpaceToWorldSpace(Vector2Int position) { | |
return Vector2Utilities.XZPlane((position * Size) - | |
(Vector2Int.one * Size / 2) + (Vector2.one * 0.5f)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using UnityEditor; | |
using UnityEngine; | |
using Utilities; | |
public class ChunkManager : MonoBehaviourSingleton<ChunkManager> { | |
public GameObject chunkPrefab; | |
public int seed; | |
public float noiseScale = 100; | |
[Range(1, 10)] | |
public int octaves = 3; | |
public float lacunarity = 2.5f; | |
[Range(0, 1)] | |
public float persistence = 0.5f; | |
public bool autoUpdate = true; | |
Dictionary<Vector2Int, Chunk> chunks = new Dictionary<Vector2Int, Chunk>(); | |
public Chunk this[int x, int y] { | |
get { | |
return this[new Vector2Int(x, y)]; | |
} | |
} | |
public Chunk this[Vector2Int v] { | |
get { | |
try { | |
return chunks[v]; | |
} catch (KeyNotFoundException) { | |
return null; | |
} | |
} | |
} | |
void Start() { | |
Noise2DGenerator.Noise2DGeneratorFactory.CreatePerlinNoise2DGenerator( | |
seed, noiseScale, octaves, lacunarity, persistence); | |
var viewer = ChunkViewer.Instance; | |
var viewerPosition = | |
Chunk.WorldSpaceToChunkSpace(viewer.transform.position); | |
var viewDistanceInChunks = viewer.viewDistance / Chunk.Size; | |
for (int x = -viewDistanceInChunks; x <= viewDistanceInChunks; x++) { | |
for (int z = -viewDistanceInChunks; z <= viewDistanceInChunks; z++) { | |
var chunkOffset = new Vector2Int(x, z); | |
if (chunkOffset.magnitude > viewDistanceInChunks) | |
continue; | |
var chunkPosition = viewerPosition + chunkOffset; | |
if (!chunks.ContainsKey(chunkPosition)) { | |
var chunkGameObject = Instantiate(chunkPrefab, | |
Chunk.ChunkSpaceToWorldSpace(chunkPosition), | |
Quaternion.identity) as GameObject; | |
chunks.Add(chunkPosition, chunkGameObject.GetComponent<Chunk>()); | |
} | |
} | |
} | |
} | |
public void OnValidate() { | |
if (noiseScale < 1) | |
noiseScale = 1; | |
if (octaves < 1) | |
octaves = 1; | |
if (lacunarity < 1) | |
lacunarity = 1; | |
if (!EditorApplication.isPlayingOrWillChangePlaymode && autoUpdate) { | |
if (gameObject.GetComponent<MeshFilter>() == null) | |
gameObject.AddComponent<MeshFilter>(); | |
if (gameObject.GetComponent<MeshRenderer>() == null) | |
gameObject.AddComponent<MeshRenderer>(); | |
Noise2DGenerator.Noise2DGeneratorFactory.CreatePerlinNoise2DGenerator( | |
seed, noiseScale, octaves, lacunarity, persistence); | |
GenerateNoiseMap(); | |
transform.position = ChunkViewer.Instance.transform.position; | |
} else if (EditorApplication.isPlaying) { | |
Destroy(gameObject.GetComponent<MeshFilter>()); | |
Destroy(gameObject.GetComponent<MeshRenderer>()); | |
} | |
} | |
void GenerateNoiseMap() { | |
var viewerPosition = ChunkViewer.Instance.transform.position; | |
var viewerSize = ChunkViewer.Instance.viewDistance; | |
var meshData = new MeshData(false); | |
meshData.AddVertex(new Vector3(-viewerSize, 0, viewerSize)); | |
meshData.AddVertex(new Vector3(viewerSize, 0, viewerSize)); | |
meshData.AddVertex(new Vector3(viewerSize, 0, -viewerSize)); | |
meshData.AddVertex(new Vector3(-viewerSize, 0, -viewerSize)); | |
meshData.AddQuadTriangles(); | |
meshData.uvs.Add(Vector2Int.up); | |
meshData.uvs.Add(Vector2Int.one); | |
meshData.uvs.Add(Vector2Int.right); | |
meshData.uvs.Add(Vector2Int.zero); | |
var filter = GetComponent<MeshFilter>(); | |
GetComponent<MeshFilter>().sharedMesh = new Mesh(); | |
filter.sharedMesh.vertices = meshData.verts.ToArray(); | |
filter.sharedMesh.triangles = meshData.tris.ToArray(); | |
filter.sharedMesh.uv = meshData.uvs.ToArray(); | |
var heightMap = Noise2DGenerator.Instance.GenerateNoise( | |
new Vector2(viewerPosition.x / 2, viewerPosition.z / 2), | |
Vector2Int.one * viewerSize); | |
var pixels = new Color[viewerSize * viewerSize]; | |
for (int y = 0; y < viewerSize; y++) { | |
for (int x = 0; x < viewerSize; x++) { | |
pixels[y * viewerSize + x] = | |
Color.Lerp(Color.black, Color.white, heightMap[x, y]); | |
} | |
} | |
var tex = new Texture2D(viewerSize, viewerSize); | |
tex.wrapMode = TextureWrapMode.Clamp; | |
tex.filterMode = FilterMode.Point; | |
tex.SetPixels(pixels); | |
tex.Apply(); | |
GetComponent<MeshRenderer>().sharedMaterial = | |
new Material(Shader.Find("Mobile/Diffuse")); | |
GetComponent<MeshRenderer>().sharedMaterial.mainTexture = tex; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using UnityEditor; | |
using UnityEngine; | |
using Utilities; | |
public class ChunkManager : MonoBehaviourSingleton<ChunkManager> { | |
public GameObject chunkPrefab; | |
public int seed; | |
public float noiseScale = 100; | |
[Range(1, 10)] | |
public int octaves = 3; | |
public float lacunarity = 2.5f; | |
[Range(0, 1)] | |
public float persistence = 0.5f; | |
public bool autoUpdate = true; | |
Dictionary<Vector2Int, Chunk> chunks = new Dictionary<Vector2Int, Chunk>(); | |
void Start() { | |
Noise2DGenerator.Noise2DGeneratorFactory.CreatePerlinNoise2DGenerator( | |
seed, noiseScale, octaves, lacunarity, persistence); | |
var viewer = ChunkViewer.Instance; | |
var viewerPosition = | |
Chunk.WorldSpaceToChunkSpace(viewer.transform.position); | |
var viewDistanceInChunks = viewer.viewDistance / Chunk.Size; | |
for (int x = -viewDistanceInChunks; x <= viewDistanceInChunks; x++) { | |
for (int z = -viewDistanceInChunks; z <= viewDistanceInChunks; z++) { | |
var chunkOffset = new Vector2Int(x, z); | |
if (chunkOffset.magnitude > viewDistanceInChunks) | |
continue; | |
var chunkPosition = viewerPosition + chunkOffset; | |
if (!chunks.ContainsKey(chunkPosition)) { | |
var chunkGameObject = Instantiate(chunkPrefab, | |
Chunk.ChunkSpaceToWorldSpace(chunkPosition), | |
Quaternion.identity) as GameObject; | |
chunks.Add(chunkPosition, chunkGameObject.GetComponent<Chunk>()); | |
} | |
} | |
} | |
} | |
public void OnValidate() { | |
if (noiseScale < 1) | |
noiseScale = 1; | |
if (octaves < 1) | |
octaves = 1; | |
if (lacunarity < 1) | |
lacunarity = 1; | |
if (!EditorApplication.isPlayingOrWillChangePlaymode && autoUpdate) { | |
if (gameObject.GetComponent<MeshFilter>() == null) | |
gameObject.AddComponent<MeshFilter>(); | |
if (gameObject.GetComponent<MeshRenderer>() == null) | |
gameObject.AddComponent<MeshRenderer>(); | |
Noise2DGenerator.Noise2DGeneratorFactory.CreatePerlinNoise2DGenerator( | |
seed, noiseScale, octaves, lacunarity, persistence); | |
GenerateNoiseMap(); | |
transform.position = ChunkViewer.Instance.transform.position; | |
} else if (EditorApplication.isPlaying) { | |
Destroy(gameObject.GetComponent<MeshFilter>()); | |
Destroy(gameObject.GetComponent<MeshRenderer>()); | |
} | |
} | |
void GenerateNoiseMap() { | |
var viewerPosition = ChunkViewer.Instance.transform.position; | |
var viewerSize = ChunkViewer.Instance.viewDistance; | |
var meshData = new MeshData(false); | |
meshData.AddVertex(new Vector3(-viewerSize, 0, viewerSize)); | |
meshData.AddVertex(new Vector3(viewerSize, 0, viewerSize)); | |
meshData.AddVertex(new Vector3(viewerSize, 0, -viewerSize)); | |
meshData.AddVertex(new Vector3(-viewerSize, 0, -viewerSize)); | |
meshData.AddQuadTriangles(); | |
meshData.uvs.Add(Vector2Int.up); | |
meshData.uvs.Add(Vector2Int.one); | |
meshData.uvs.Add(Vector2Int.right); | |
meshData.uvs.Add(Vector2Int.zero); | |
var filter = GetComponent<MeshFilter>(); | |
GetComponent<MeshFilter>().sharedMesh = new Mesh(); | |
filter.sharedMesh.vertices = meshData.verts.ToArray(); | |
filter.sharedMesh.triangles = meshData.tris.ToArray(); | |
filter.sharedMesh.uv = meshData.uvs.ToArray(); | |
var heightMap = Noise2DGenerator.Instance.GenerateNoise( | |
new Vector2(viewerPosition.x / 2, viewerPosition.z / 2), | |
Vector2Int.one * viewerSize); | |
var pixels = new Color[viewerSize * viewerSize]; | |
for (int y = 0; y < viewerSize; y++) { | |
for (int x = 0; x < viewerSize; x++) { | |
pixels[y * viewerSize + x] = | |
Color.Lerp(Color.black, Color.white, heightMap[x, y]); | |
} | |
} | |
var tex = new Texture2D(viewerSize, viewerSize); | |
tex.wrapMode = TextureWrapMode.Clamp; | |
tex.filterMode = FilterMode.Point; | |
tex.SetPixels(pixels); | |
tex.Apply(); | |
GetComponent<MeshRenderer>().sharedMaterial = | |
new Material(Shader.Find("Mobile/Diffuse")); | |
GetComponent<MeshRenderer>().sharedMaterial.mainTexture = tex; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using UnityEditor; | |
using UnityEngine; | |
using Utilities; | |
public class ChunkManager : MonoBehaviourSingleton<ChunkManager> { | |
public GameObject chunkPrefab; | |
public int seed; | |
public float noiseScale = 100; | |
[Range(1, 10)] | |
public int octaves = 3; | |
public float lacunarity = 2.5f; | |
[Range(0, 1)] | |
public float persistence = 0.5f; | |
public bool autoUpdate = true; | |
Dictionary<Vector2Int, Chunk> chunks = new Dictionary<Vector2Int, Chunk>(); | |
void Start() { | |
Noise2DGenerator.Noise2DGeneratorFactory.CreatePerlinNoise2DGenerator( | |
seed, noiseScale, octaves, lacunarity, persistence); | |
var viewDistanceInChunks = 100 / Chunk.Size; | |
for (int x = -viewDistanceInChunks; x <= viewDistanceInChunks; x++) { | |
for (int z = -viewDistanceInChunks; z <= viewDistanceInChunks; z++) { | |
var chunkOffset = new Vector2Int(x, z); | |
if (chunkOffset.magnitude > viewDistanceInChunks) | |
continue; | |
var chunkPosition = Vector2Int.zero + chunkOffset; | |
if (!chunks.ContainsKey(chunkPosition)) { | |
var chunkGameObject = Instantiate(chunkPrefab, | |
Chunk.ChunkSpaceToWorldSpace(chunkPosition), | |
Quaternion.identity) as GameObject; | |
chunks.Add(chunkPosition, chunkGameObject.GetComponent<Chunk>()); | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using UnityEngine; | |
using Utilities; | |
public class ChunkManager : MonoBehaviourSingleton<ChunkManager> { | |
public GameObject chunkPrefab; | |
public int seed; | |
public float noiseScale = 100; | |
[Range(1, 10)] | |
public int octaves = 3; | |
public float lacunarity = 2.5f; | |
[Range(0, 1)] | |
public float persistence = 0.5f; | |
public bool autoUpdate = true; | |
Dictionary<Vector2Int, Chunk> chunks = new Dictionary<Vector2Int, Chunk>(); | |
void Start() { | |
Noise2DGenerator.Noise2DGeneratorFactory.CreatePerlinNoise2DGenerator( | |
seed, noiseScale, octaves, lacunarity, persistence); | |
var viewer = ChunkViewer.Instance; | |
var viewerPosition = | |
Chunk.WorldSpaceToChunkSpace(viewer.transform.position); | |
var viewDistanceInChunks = viewer.viewDistance / Chunk.Size; | |
for (int x = -viewDistanceInChunks; x <= viewDistanceInChunks; x++) { | |
for (int z = -viewDistanceInChunks; z <= viewDistanceInChunks; z++) { | |
var chunkOffset = new Vector2Int(x, z); | |
if (chunkOffset.magnitude > viewDistanceInChunks) | |
continue; | |
var chunkPosition = viewerPosition + chunkOffset; | |
if (!chunks.ContainsKey(chunkPosition)) { | |
var chunkGameObject = Instantiate(chunkPrefab, | |
Chunk.ChunkSpaceToWorldSpace(chunkPosition), | |
Quaternion.identity) as GameObject; | |
chunks.Add(chunkPosition, chunkGameObject.GetComponent<Chunk>()); | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using Utilities; | |
[ExecuteInEditMode] | |
public class ChunkViewer : MonoBehaviourSingleton<ChunkViewer> { | |
public int viewDistance = 200; | |
void Update() { | |
if (transform.hasChanged) { | |
ChunkManager.Instance.OnValidate(); | |
transform.hasChanged = false; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Utilities; | |
public class ChunkViewer : MonoBehaviourSingleton<ChunkViewer> { | |
public int viewDistance = 200; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using UnityEditor; | |
using UnityEngine; | |
namespace Utilities { | |
// Convenience struct for integer based Vector2s. | |
[System.Serializable] | |
public struct Vector2Int { | |
public static Vector2Int zero { | |
get { | |
return new Vector2Int(0, 0); | |
} | |
} | |
public static Vector2Int one { | |
get { | |
return new Vector2Int(1, 1); | |
} | |
} | |
public static Vector2Int up { | |
get { | |
return new Vector2Int(0, 1); | |
} | |
} | |
public static Vector2Int down { | |
get { | |
return new Vector2Int(0, -1); | |
} | |
} | |
public static Vector2Int right { | |
get { | |
return new Vector2Int(1, 0); | |
} | |
} | |
public static Vector2Int left { | |
get { | |
return new Vector2Int(-1, 0); | |
} | |
} | |
public static Vector2Int operator +(Vector2Int a, Vector2Int b) { | |
Vector2 r = a.v2 + b.v2; | |
return new Vector2Int(Mathf.RoundToInt(r.x), Mathf.RoundToInt(r.y)); | |
} | |
public static Vector2 operator +(Vector2Int a, Vector2 b) { | |
return new Vector2(a.x + b.x, a.y + b.y); | |
} | |
public static Vector2Int operator -(Vector2Int a, Vector2Int b) { | |
Vector2 r = a.v2 - b.v2; | |
return new Vector2Int(Mathf.RoundToInt(r.x), Mathf.RoundToInt(r.y)); | |
} | |
public static Vector2Int operator *(Vector2Int v, int i) { | |
return new Vector2Int(v.x * i, v.y * i); | |
} | |
public static Vector2 operator *(Vector2Int v, float f) { | |
return new Vector2(v.x * f, v.y * f); | |
} | |
public static Vector2Int operator /(Vector2Int v, int i) { | |
return new Vector2Int(v.x / i, v.y / i); | |
} | |
public static Vector2Int operator /(Vector2Int v, float f) { | |
int i = Mathf.RoundToInt(f); | |
return new Vector2Int(v.x / i, v.y / i); | |
} | |
public static bool operator ==(Vector2Int a, Vector2Int b) { | |
return a.x == b.x && a.y == b.y; | |
} | |
public static bool operator !=(Vector2Int a, Vector2Int b) { | |
return !(a == b); | |
} | |
public static implicit operator Vector2Int(Vector2 v) { | |
return new Vector2Int(v); | |
} | |
public static implicit operator Vector2(Vector2Int v) { | |
return new Vector2(v.x, v.y); | |
} | |
[SerializeField] | |
Vector2 v2; | |
public float magnitude { | |
get { | |
return v2.magnitude; | |
} | |
} | |
public int x { | |
get { | |
return Mathf.RoundToInt(v2.x); | |
} | |
set { | |
v2.x = value; | |
} | |
} | |
public int y { | |
get { | |
return Mathf.RoundToInt(v2.y); | |
} | |
set { | |
v2.y = value; | |
} | |
} | |
public Vector3Int XYPlane { | |
get { | |
return new Vector3Int(x, y, 0); | |
} | |
} | |
public Vector3Int XZPlane { | |
get { | |
return new Vector3Int(x, 0, y); | |
} | |
} | |
public Vector3Int YZPlane { | |
get { | |
return new Vector3Int(0, x, y); | |
} | |
} | |
public Vector2Int(int x, int y) { | |
v2 = new Vector2(x, y); | |
} | |
public Vector2Int(Vector2 v) { | |
v2 = new Vector2(Mathf.RoundToInt(v.x), Mathf.RoundToInt(v.y)); | |
} | |
public override bool Equals(object obj) { | |
return base.Equals(obj); | |
} | |
public override int GetHashCode() { | |
return base.GetHashCode(); | |
} | |
public override string ToString() { | |
return string.Format("({0}, {1})", x, y); | |
} | |
} | |
public static class Vector2Utilities { | |
public static Vector3 XYPlane(Vector2 v) { | |
return new Vector3(v.x, v.y, 0); | |
} | |
public static Vector3 XZPlane(Vector2 v) { | |
return new Vector3(v.x, 0, v.y); | |
} | |
public static Vector3 YZPlane(Vector2 v) { | |
return new Vector3(0, v.x, v.y); | |
} | |
} | |
[CustomPropertyDrawer(typeof(Vector2Int))] | |
public class Vector2IntDrawer : PropertyDrawer { | |
public override void OnGUI(Rect position, SerializedProperty property, | |
GUIContent label) { | |
EditorGUI.BeginProperty(position, label, property); | |
Vector2Int result = EditorGUI.Vector2Field(position, label, | |
property.FindPropertyRelative("v2").vector2Value); | |
property.FindPropertyRelative("v2").vector2Value = result; | |
EditorGUI.EndProperty(); | |
} | |
} | |
// Convenience struct for integer based Vector3s. | |
[System.Serializable] | |
public struct Vector3Int { | |
public static Vector3Int zero { | |
get { | |
return new Vector3Int(0, 0, 0); | |
} | |
} | |
public static Vector3Int one { | |
get { | |
return new Vector3Int(1, 1, 1); | |
} | |
} | |
public static Vector3Int up { | |
get { | |
return new Vector3Int(0, 1, 0); | |
} | |
} | |
public static Vector3Int down { | |
get { | |
return new Vector3Int(0, -1, 0); | |
} | |
} | |
public static Vector3Int north { | |
get { | |
return new Vector3Int(0, 0, 1); | |
} | |
} | |
public static Vector3Int south { | |
get { | |
return new Vector3Int(0, 0, -1); | |
} | |
} | |
public static Vector3Int east { | |
get { | |
return new Vector3Int(1, 0, 0); | |
} | |
} | |
public static Vector3Int west { | |
get { | |
return new Vector3Int(-1, 0, 0); | |
} | |
} | |
public static Vector3Int operator +(Vector3Int a, Vector3Int b) { | |
Vector3 r = a.v3 + b.v3; | |
return new Vector3Int( | |
Mathf.RoundToInt(r.x), Mathf.RoundToInt(r.y), Mathf.RoundToInt(r.z)); | |
} | |
public static Vector3 operator +(Vector3Int a, Vector3 b) { | |
return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z); | |
} | |
public static Vector3 operator +(Vector3 a, Vector3Int b) { | |
return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z); | |
} | |
public static Vector3Int operator -(Vector3Int a, Vector3Int b) { | |
Vector3 r = a.v3 - b.v3; | |
return new Vector3Int( | |
Mathf.RoundToInt(r.x), Mathf.RoundToInt(r.y), Mathf.RoundToInt(r.z)); | |
} | |
public static Vector3Int operator *(Vector3Int v, int i) { | |
return new Vector3Int(v.x * i, v.y * i, v.z * i); | |
} | |
public static Vector3 operator *(Vector3Int v, float f) { | |
return new Vector3(v.x * f, v.y * f, v.z * f); | |
} | |
public static Vector3Int operator /(Vector3Int v, int i) { | |
return new Vector3Int(v.x / i, v.y / i, v.z / i); | |
} | |
public static Vector3Int operator /(Vector3Int v, float f) { | |
int i = Mathf.RoundToInt(f); | |
return new Vector3Int(v.x / i, v.y / i, v.z / i); | |
} | |
public static implicit operator Vector3Int(Vector3 v) { | |
return new Vector3Int(v); | |
} | |
public static implicit operator Vector3(Vector3Int v) { | |
return new Vector3(v.x, v.y, v.z); | |
} | |
[SerializeField] | |
Vector3 v3; | |
public float magnitude { | |
get { | |
return v3.magnitude; | |
} | |
} | |
public int x { | |
get { | |
return Mathf.RoundToInt(v3.x); | |
} | |
set { | |
v3.x = value; | |
} | |
} | |
public int y { | |
get { | |
return Mathf.RoundToInt(v3.y); | |
} | |
set { | |
v3.y = value; | |
} | |
} | |
public int z { | |
get { | |
return Mathf.RoundToInt(v3.z); | |
} | |
set { | |
v3.z = value; | |
} | |
} | |
public Vector3Int(int x, int y, int z) { | |
v3 = new Vector3(x, y, z); | |
} | |
public Vector3Int(Vector3 v) { | |
v3 = new Vector3( | |
Mathf.RoundToInt(v.x), Mathf.RoundToInt(v.y), Mathf.RoundToInt(v.z)); | |
} | |
public override string ToString() { | |
return string.Format("({0}, {1}, {2})", x, y, z); | |
} | |
} | |
public static class Vector3Utilities { | |
public static Vector2 XYPlane(Vector3 v) { | |
return new Vector2(v.x, v.y); | |
} | |
public static Vector2 XZPlane(Vector3 v) { | |
return new Vector2(v.x, v.z); | |
} | |
public static Vector2 YZPlane(Vector3 v) { | |
return new Vector2(v.y, v.z); | |
} | |
} | |
[CustomPropertyDrawer(typeof(Vector3Int))] | |
public class Vector3IntDrawer : PropertyDrawer { | |
public override void OnGUI(Rect position, SerializedProperty property, | |
GUIContent label) { | |
EditorGUI.BeginProperty(position, label, property); | |
Vector3Int result = EditorGUI.Vector3Field(position, label, | |
property.FindPropertyRelative("v3").vector3Value); | |
property.FindPropertyRelative("v3").vector3Value = result; | |
EditorGUI.EndProperty(); | |
} | |
} | |
public class MonoBehaviourSingleton<T> | |
: MonoBehaviour | |
where T : MonoBehaviour { | |
public class TooManyInstancesException : Exception { | |
public TooManyInstancesException() | |
: base("Too many instances of " + typeof(T)) { | |
} | |
} | |
protected static T instance; | |
public static T Instance { | |
get { | |
if (instance == null) { | |
var find = FindObjectsOfType<T>(); | |
if (find.Length > 1) { | |
throw new TooManyInstancesException(); | |
} else if (find.Length == 0) { | |
var go = new GameObject(typeof(T).ToString()); | |
instance = go.AddComponent<T>(); | |
} else { | |
instance = find[0]; | |
} | |
} | |
return instance; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment