public void Update() { // check if chunk is not null GameObject chunkObject = Engine.PositionToChunk (transform.position); if (chunkObject == null) return; // get the voxelInfo from the transform's position Chunk chunk = chunkObject.GetComponent<Chunk>(); Index voxelIndex = chunk.PositionToVoxelIndex (transform.position); VoxelInfo voxelInfo = new VoxelInfo (voxelIndex, chunk); // create a local copy of the collision voxel so we can call functions on it GameObject voxelObject = Instantiate ( Engine.GetVoxelGameObject (voxelInfo.GetVoxel()) ) as GameObject; VoxelEvents events = voxelObject.GetComponent<VoxelEvents>(); if (events != null ) { // OnEnter if ( chunk != LastChunk || voxelIndex.IsEqual(LastIndex) == false) { events.OnBlockEnter (this.gameObject, voxelInfo); } // OnStay else { events.OnBlockStay(this.gameObject, voxelInfo); } } LastChunk = chunk; LastIndex = voxelIndex; Destroy(voxelObject); }
public void InitializeGenerator() { // load seed if it's not loaded yet while (Engine.WorldSeed == 0) { Engine.GetSeed(); } seed = Engine.WorldSeed; // get chunk component chunk = GetComponent<Chunk>(); // generate data GenerateVoxelData (); // set empty chunk.Empty = true; foreach (ushort voxel in chunk.VoxelData) { if (voxel != 0) { chunk.Empty = false; break; } } // flag as done chunk.VoxelsDone = true; }
public VoxelInfo( Index setIndex, Index setAdjacentIndex, Chunk setChunk ) { this.index = setIndex; this.adjacentIndex = setAdjacentIndex; this.chunk = setChunk; }
public VoxelInfo( int setX, int setY, int setZ, Chunk setChunk ) { this.index.x = setX; this.index.y = setY; this.index.z = setZ; this.chunk = setChunk; }
public VoxelInfo( int setX, int setY, int setZ, int setXa, int setYa, int setZa, Chunk setChunk ) { this.index.x = setX; this.index.y = setY; this.index.z = setZ; this.adjacentIndex.x = setXa; this.adjacentIndex.y = setYa; this.adjacentIndex.z = setZa; this.chunk = setChunk; }
public void Initialize() { // set variables chunk = GetComponent<Chunk>(); SideLength = chunk.SideLength; // make a list for each material (each material is a submesh) for (int i=0; i<GetComponent<Renderer>().materials.Length; i++) { Faces.Add(new List<int>()); } initialized = true; }
public static Dictionary<string, string> TempChunkData; // stores chunk's data to write into a region file later #endregion Fields #region Methods public static string CompressData( Chunk chunk ) { // returns the data of chunk in compressed string format StringWriter writer = new StringWriter(); int i = 0; int length = chunk.GetDataLength(); // length of VoxelData array ushort currentCount = 0; // count of consecutive voxels of the same type ushort currentData = 0; // data of the current voxel for (i=0; i<length; i++) { // for each voxel ushort thisData = chunk.GetVoxelSimple(i); // read raw data at i if (thisData != currentData) { // if the data is different from the previous data, write the last block and start a new one // write previous block if (i != 0) { // (don't write in the first loop iteration, because count would be 0 (no previous blocks)) writer.Write ((char)currentCount); writer.Write ((char)currentData); } // start new block currentCount = 1; currentData = thisData; } else { // if the data is the same as the last data, simply add to the count currentCount ++; } if (i == length-1) { // if this is the last iteration of the loop, close and write the current block writer.Write ((char)currentCount); writer.Write ((char)currentData); } } string compressedData = writer.ToString(); writer.Flush (); writer.Close (); return compressedData; }
public static void DecompressData( Chunk chunk, string data ) { // decompresses voxel data and loads it into the VoxelData array // check if chunk is empty if (data.Length == 2 && data[1] == (char)0) { chunk.Empty = true; } StringReader reader = new StringReader (data); int i = 0; int length = chunk.GetDataLength(); // length of VoxelData array try { while ( i < length ) { // this loop will stop once the VoxelData array has been populated completely. Iterates once per count-data block. ushort currentCount = (ushort) reader.Read(); // read the count ushort currentData = (ushort) reader.Read(); // read the data int ii = 0; while ( ii < currentCount ) { chunk.SetVoxelSimple (i, (ushort)currentData);// write a single voxel for every currentCount ii ++; i ++; } } } catch (System.Exception) { Debug.LogError ("Uniblocks: Corrupt chunk data for chunk: " + chunk.ChunkIndex.ToString() + ". Has the data been saved using a different chunk size?"); reader.Close(); return; } reader.Close(); }
public static void RegisterChunk( Chunk chunk ) { // adds a reference to the chunk to the global chunk list ChunkManager.Chunks.Add (chunk.ChunkIndex.ToString(), chunk); }
public static void AddChunkToUpdateQueue( Chunk chunk ) { if (ChunkUpdateQueue.Contains(chunk) == false) { ChunkUpdateQueue.Add (chunk); } }
public static void UnregisterChunk( Chunk chunk ) { ChunkManager.Chunks.Remove(chunk.ChunkIndex.ToString()); }
// ==== Voxel updates ===================================================================================== public void RebuildMesh() { chunk = GetComponent<Chunk>(); // destroy additional mesh containers foreach (Transform child in transform) { Destroy(child.gameObject); } int x=0,y=0,z=0; // Refresh neighbor chunks chunk.GetNeighbors(); // for each voxel in Voxels, check if any of the voxel's faces are exposed, and if so, add their faces to the main mesh arrays (named Vertices and Faces) while (x < SideLength) { while (y < SideLength) { while (z < SideLength) { ushort voxel = chunk.GetVoxel(x,y,z); // the current voxel data if ( voxel != 0 ) { // don't render empty blocks. Voxel voxelType = Engine.GetVoxelType(voxel); if ( voxelType.VCustomMesh == false ) { // if cube //Transparency transparency = Engine.GetVoxelType (chunk.GetVoxel(x,y,z)).VTransparency; Transparency transparency = voxelType.VTransparency; ColliderType colliderType = voxelType.VColliderType; if (CheckAdjacent(x,y,z, Direction.forward, transparency) == true) CreateFace(voxel, Facing.forward, colliderType, x,y,z); if (CheckAdjacent(x,y,z, Direction.back, transparency) == true) CreateFace(voxel, Facing.back, colliderType, x,y,z); if (CheckAdjacent(x,y,z, Direction.up, transparency) == true) CreateFace(voxel, Facing.up, colliderType, x,y,z); if (CheckAdjacent(x,y,z, Direction.down, transparency) == true) CreateFace(voxel, Facing.down, colliderType, x,y,z); if (CheckAdjacent(x,y,z, Direction.right, transparency) == true) CreateFace(voxel, Facing.right, colliderType, x,y,z); if (CheckAdjacent(x,y,z, Direction.left, transparency) == true) CreateFace(voxel, Facing.left, colliderType, x,y,z); // if no collider, create a trigger cube collider if (colliderType == ColliderType.none && Engine.GenerateColliders) { AddCubeMesh (x,y,z, false); } } else { // if not cube if (CheckAllAdjacent (x,y,z) == false) { // if any adjacent voxel isn't opaque, we render the mesh CreateCustomMesh(voxel, x,y,z, voxelType.VMesh); } } } z += 1; } z = 0; y += 1; } y = 0; x += 1; } // update mesh using the values from the arrays UpdateMesh ( GetComponent<MeshFilter>().mesh ); }
//添加块 public static void RegisterChunk(Chunk chunk) { // adds a reference to the chunk to the global chunk list ChunkManager.Chunks.Add(chunk.ChunkIndex.ToString(), chunk); }
private IEnumerator SpawnMissingChunks(int originX, int originY, int originZ, int range) { int heightRange = Engine.HeightRange; ChunkUpdateQueue = new List <Chunk>(); // clear update queue - it will be repopulated again in the correct order in the following loop // flag chunks not in range for removal ChunksToDestroy = new List <Chunk>(); foreach (Chunk chunk in Chunks.Values) { if (Vector2.Distance(new Vector2(chunk.ChunkIndex.x, chunk.ChunkIndex.z), new Vector2(originX, originZ)) > range + Engine.ChunkDespawnDistance) {//块和人物的水平距离超过销毁范围,将此块加入销毁队列 ChunksToDestroy.Add(chunk); } else if (Mathf.Abs(chunk.ChunkIndex.y - originY) > range + Engine.ChunkDespawnDistance) { // destroy chunks outside of vertical range // 块和人物的垂直距离超过销毁范围,将此块加入销毁队列 ChunksToDestroy.Add(chunk); } } // main loop for (int currentLoop = 0; currentLoop <= range; currentLoop++) { for (var x = originX - currentLoop; x <= originX + currentLoop; x++) { // iterate through all potential chunk indexes within range for (var y = originY - currentLoop; y <= originY + currentLoop; y++) { for (var z = originZ - currentLoop; z <= originZ + currentLoop; z++) { if (Mathf.Abs(y) <= heightRange) { // skip chunks outside of height range//垂直范围之内 if (Mathf.Abs(originX - x) + Mathf.Abs(originZ - z) < range * 2f) /*if (Mathf.Pow(Mathf.Abs(originX-x),2)+ Mathf.Pow(Mathf.Abs(originZ-z),2)< Mathf.Pow(range,2))*/ { //1.3f skip corners // pause loop while the queue is not empty while (ChunkUpdateQueue.Count > 0) { ProcessChunkQueue(); if (frameStopwatch.Elapsed.TotalSeconds >= targetFrameDuration) { yield return(new WaitForEndOfFrame()); } } Chunk currentChunk = ChunkManager.GetChunkComponent(x, y, z); // chunks that already exist but haven't had their mesh built yet should be added to the update queue if (currentChunk != null) { // chunks without meshes spawned by server should be changed to regular chunks if (currentChunk.DisableMesh || currentChunk.EnableTimeout) { currentChunk.DisableMesh = false; currentChunk.EnableTimeout = false; currentChunk.Fresh = true; } if (currentChunk.Fresh) { // spawn neighbor chunks for (int d = 0; d < 6; d++) { Index neighborIndex = currentChunk.ChunkIndex.GetAdjacentIndex((Direction)d); GameObject neighborChunk = GetChunk(neighborIndex); if (neighborChunk == null) { neighborChunk = Instantiate(ChunkObject, neighborIndex.ToVector3(), transform.rotation) as GameObject; } currentChunk.NeighborChunks[d] = neighborChunk.GetComponent <Chunk>(); // always add the neighbor to NeighborChunks, in case it's not there already // continue loop in next frame if the current frame time is exceeded if (frameStopwatch.Elapsed.TotalSeconds >= targetFrameDuration) { yield return(new WaitForEndOfFrame()); } if (StopSpawning) { EndSequence(); yield break; } } if (currentChunk != null) { currentChunk.AddToQueueWhenReady(); } } } else { // if chunk doesn't exist, create new chunk (it adds itself to the update queue when its data is ready) // spawn chunk GameObject newChunk = Instantiate(ChunkObject, new Vector3(x, y, z), transform.rotation) as GameObject; // Spawn a new chunk. currentChunk = newChunk.GetComponent <Chunk>(); // spawn neighbor chunks if they're not spawned yet for (int d = 0; d < 6; d++) { Index neighborIndex = currentChunk.ChunkIndex.GetAdjacentIndex((Direction)d); GameObject neighborChunk = GetChunk(neighborIndex); if (neighborChunk == null) { neighborChunk = Instantiate(ChunkObject, neighborIndex.ToVector3(), transform.rotation) as GameObject; } currentChunk.NeighborChunks[d] = neighborChunk.GetComponent <Chunk>(); // always add the neighbor to NeighborChunks, in case it's not there already // continue loop in next frame if the current frame time is exceeded if (frameStopwatch.Elapsed.TotalSeconds >= targetFrameDuration) { yield return(new WaitForEndOfFrame()); } if (StopSpawning) { EndSequence(); yield break; } } if (currentChunk != null) { currentChunk.AddToQueueWhenReady(); } } } } // continue loop in next frame if the current frame time is exceeded if (frameStopwatch.Elapsed.TotalSeconds >= targetFrameDuration) { yield return(new WaitForEndOfFrame()); } if (StopSpawning) { EndSequence(); yield break; } } } } } yield return(new WaitForEndOfFrame()); EndSequence(); }
//删除块 public static void UnregisterChunk(Chunk chunk) { ChunkManager.Chunks.Remove(chunk.ChunkIndex.ToString()); }
public VoxelInfo(Index setIndex, Chunk setChunk) { this.index = setIndex; this.chunk = setChunk; }
public VoxelInfo(int setX, int setY, int setZ, int setXa, int setYa, int setZa, Chunk setChunk) { this.index.x = setX; this.index.y = setY; this.index.z = setZ; this.adjacentIndex.x = setXa; this.adjacentIndex.y = setYa; this.adjacentIndex.z = setZa; this.chunk = setChunk; }