Created
November 12, 2013 14:40
-
-
Save jonbro/7431874 to your computer and use it in GitHub Desktop.
3d tiling system
This file contains hidden or 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 System.Collections; | |
| using System.Collections.Generic; | |
| public class GenerateVoxelLevel : MonoBehaviour { | |
| // not going to do octtrees, just totally straight forward arrays so I can get this done in 25 mins | |
| bool[,,] worldMap; | |
| bool[,,] filled; | |
| int[] digPosition; | |
| int worldSize = 40; | |
| public GameObject worldBit; | |
| public List<GameObject> tile; | |
| public List<GameObject> light; | |
| List<CombineInstance> meshSegments = new List<CombineInstance>(); | |
| public GameObject player; | |
| // Use this for initialization | |
| // 3d neighborhood | |
| int[,] nDir = { | |
| {0, 1, 0}, {0, -1, 0}, | |
| {1, 0, 0}, {-1, 0, 0}, | |
| {0,0,1}, {0,0,-1} | |
| }; | |
| // rotation mappings for 3d neighborhood | |
| Vector3[] rotationMapping = { | |
| new Vector3 (270, 0, 0), new Vector3 (90, 0, 0), | |
| new Vector3 (0, 90, 0), new Vector3 (0, 270, 0), | |
| new Vector3 (0, 0, 0), new Vector3 (0, 180, 0) | |
| }; | |
| void Start () { | |
| digPosition = new int[3]; | |
| worldMap = new bool[worldSize, worldSize, worldSize]; | |
| filled = new bool[worldSize, worldSize, worldSize]; | |
| // fill in the world map | |
| for (int x=0; x<worldSize; x++) { | |
| for (int y=0; y<worldSize; y++) { | |
| for (int z=0; z<worldSize; z++) { | |
| // worldMap [x, y, z] = (Random.value < 0.9f); | |
| worldMap [x, y, z] = true; | |
| // just fill the walls | |
| // if (x == 0 || y == 0 || z == 0 || x == worldSize - 1 || y == worldSize - 1 || z == worldSize - 1) | |
| // worldMap [x, y, z] = true; | |
| } | |
| } | |
| } | |
| for (int i=0; i<4; i++) { | |
| DigTunnel(); | |
| } | |
| // build the world from tiles | |
| int VertCount = 0; | |
| for (int x=0; x<worldSize; x++) { | |
| for (int y=0; y<worldSize; y++) { | |
| for (int z=0; z<worldSize; z++) { | |
| if (worldMap [x, y, z]) { | |
| // check the 3d neighborhood | |
| for (int i = 0; i < 6; i++) { | |
| int _x = x + nDir [i, 0]; | |
| int _y = y + nDir [i, 1]; | |
| int _z = z + nDir [i, 2]; | |
| if (CheckOutsideBuilding(_x, _y, _z) || !worldMap[_x, _y, _z]) { | |
| // add a tile at the location | |
| Vector3 tileOffset = new Vector3 (nDir [i, 0], nDir [i, 1], nDir [i, 2]) * 0.5f; | |
| CombineInstance thisMesh = new CombineInstance(); | |
| thisMesh.mesh = tile[Random.Range(0,tile.Count)].GetComponent<MeshFilter>().sharedMesh; | |
| VertCount += thisMesh.mesh.vertexCount; | |
| transform.position = new Vector3 (x, y, z) + tileOffset; | |
| transform.rotation = Quaternion.Euler (rotationMapping [i]) * Quaternion.Euler(new Vector3(0,0,90)*Random.Range(0,4)); | |
| transform.localScale = Vector3.one * 0.5f; | |
| thisMesh.transform = transform.localToWorldMatrix; | |
| meshSegments.Add(thisMesh); | |
| if (VertCount > 15 * 1000) { | |
| CombineMeshes (); | |
| VertCount = 0; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| CombineMeshes (); | |
| for (int i=0; i<8; i++) { | |
| // find a random empty spot and add a light | |
| int[] empty = FindEmpty(); | |
| if (empty [0] >= 0) { | |
| GameObject g = (GameObject)Instantiate (light[Random.Range(0, light.Count)], new Vector3 (empty [0], empty [1], empty [2]), Quaternion.identity); | |
| g.transform.parent = transform; | |
| } | |
| } | |
| player.transform.position = Vector3.one * worldSize * 0.5f; | |
| } | |
| // necessary because we must combine meshes as we go | |
| void CombineMeshes(){ | |
| transform.position = Vector3.zero; | |
| transform.localRotation = Quaternion.identity; | |
| transform.localScale = Vector3.one; | |
| GameObject subMesh = new GameObject (); | |
| subMesh.AddComponent<MeshFilter> (); | |
| subMesh.AddComponent<MeshCollider> (); | |
| subMesh.AddComponent<MeshRenderer> (); | |
| subMesh.renderer.sharedMaterial = renderer.material; | |
| subMesh.GetComponent<MeshFilter>().mesh = new Mesh(); | |
| subMesh.GetComponent<MeshFilter>().mesh.CombineMeshes(meshSegments.ToArray(), true); | |
| subMesh.GetComponent<MeshCollider> ().sharedMesh = subMesh.GetComponent<MeshFilter> ().sharedMesh; | |
| // subMesh.transform.parent = transform; | |
| meshSegments.Clear (); | |
| } | |
| int[] FindEmpty(){ | |
| int bail = 0; | |
| int[] empty = new int[3]; | |
| while (bail < 3000) { | |
| empty [0] = Random.Range (0, worldSize); | |
| empty [1] = Random.Range (0, worldSize); | |
| empty [2] = Random.Range (0, worldSize); | |
| if (!worldMap[empty [0], empty [1], empty [2]]) { | |
| Debug.Log ("found empty"); | |
| return empty; | |
| } | |
| bail++; | |
| } | |
| empty [0] = -1; | |
| return empty; | |
| } | |
| void DigTunnel(){ | |
| // dig some tunnels | |
| int tunnelDigCount = 0; | |
| digPosition[0] = worldSize/2; | |
| digPosition[2] = worldSize/2; | |
| digPosition[1] = worldSize/2; | |
| while (tunnelDigCount < 40) { | |
| DigInNeighborhood (digPosition [0], digPosition [1], digPosition [2]); | |
| for (int i=0; i<3; i++) { | |
| // add a random value to the dig position | |
| digPosition [i] += Random.value > 0.5 ? -1 : 1;// (-1, 2); | |
| // limit the position to the cube | |
| digPosition [i] = Mathf.Max (0, Mathf.Min (worldSize - 1, digPosition [i])); | |
| } | |
| tunnelDigCount++; | |
| } | |
| } | |
| void DigInNeighborhood(int _x, int _y, int _z){ | |
| for (int x=_x-1; x<_x+1; x++) { | |
| for (int y=_y-1; y<_y+1; y++) { | |
| for (int z=_z-1; z<_z+1; z++) { | |
| if (x > 0 && x < worldSize && y > 0 && y < worldSize && z > 0 && z < worldSize) | |
| worldMap [x, y, z] = false; | |
| } | |
| } | |
| } | |
| } | |
| bool CheckOutsideBuilding(int x, int y, int z){ | |
| return x < 0 || x > worldSize - 1 || y < 0 || y > worldSize - 1 || z < 0 || z > worldSize - 1; | |
| } | |
| // if the area surrounding this has an empty, or is outside of the level, return true | |
| bool checkNeighborhoodContainsEmpty(int _x, int _y, int _z){ | |
| for (int x=_x-1; x<=_x+1; x++) { | |
| for (int y=_y-1; y<=_y+1; y++) { | |
| for (int z=_z-1; z<=_z+1; z++) { | |
| if (x < 0 || x >= worldSize-1 || y < 0 || y >= worldSize-1 || z < 0 || z >= worldSize-1) | |
| return true; | |
| if ((x != _x || y != _y || z != _z) && !worldMap [x, y, z]) | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| // Update is called once per frame | |
| void Update () { | |
| // transform.rotation *= Quaternion.Euler (0, 0, 30 * Time.deltaTime); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You might want to make
int worldSize[line 10] public