Skip to content

Instantly share code, notes, and snippets.

@tsaodown
Last active June 7, 2016 23:33
Show Gist options
  • Save tsaodown/afcb082a213bbf8eb0b16ab1f7a34021 to your computer and use it in GitHub Desktop.
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
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));
}
}
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));
}
}
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;
}
}
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;
}
}
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>());
}
}
}
}
}
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>());
}
}
}
}
}
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;
}
}
}
using Utilities;
public class ChunkViewer : MonoBehaviourSingleton<ChunkViewer> {
public int viewDistance = 200;
}
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