public void RequestMapData(System.Action <ChunkColumn.MapDataInfo> callback, ColumnCoord colCoord) { ThreadMapObject threadTask = new ThreadMapObject(callback, colCoord); ThreadPool.QueueUserWorkItem(new WaitCallback(MapDataThread), threadTask); amountOfWorkerThreads++; }
private void OrderList(ColumnCoord playerCoord) { columnsToBuild.Sort(delegate(ColumnCoord colCoord, ColumnCoord colCoord2) { return(colCoord.GetSqrDistance(playerCoord).CompareTo(colCoord2.GetSqrDistance(playerCoord))); }); }
public static void SetBlock(int x, int y, int z, byte blockID) { ColumnCoord colCoord = GetColumnCoord(x, z); try { ChunkColumn chunkCol = null; if (columns.TryGetValue(colCoord, out chunkCol)) { if (chunkCol.hasMapData) { chunkCol.SetBlock(x - colCoord.x * ChunkColumn.chunkSize, y, z - colCoord.z * ChunkColumn.chunkSize, blockID); } else { Debug.LogError("Block set on chunk without data"); } } else { Debug.LogError("Block set on non existing chunk"); } } catch (Exception e) { Debug.Log("Set Block chunk error " + e); } }
/// <summary> /// Translate the noisevalue into a blockId at a position /// </summary> /// <param name="x">Local x position</param> /// <param name="y">Local y position</param> /// <param name="z">Local z position</param> /// <param name="noiseVal">Sampled value</param> /// <param name="colCoord">Column coordinate</param> /// <returns>The blockId</returns> private byte GetBlockIdFromNoise(int x, int y, int z, float noiseVal, ColumnCoord colCoord) { // Treshold needed if (noiseVal > SOLID_TRESHOLD) { // Spawn block if (y < waterHeight + 5) { if (y < waterHeight + 1 || y < waterHeight + 3 + (Mathf.PerlinNoise((x + colCoord.x * ChunkColumn.chunkSize) / 13f, (z + colCoord.z * ChunkColumn.chunkSize) / 17f) * 2 - 1) * 2) { // Sand return(6); } } // Stone return(2); } else if (y < waterHeight) { // Water return(1); } else { // Air return(0); } }
public static ChunkColumn GetColumn(ColumnCoord colCoord) { if (columns.ContainsKey(colCoord)) { // Chunk exists return(columns[colCoord]); } return(null); }
public static bool ColumnHasMapdata(ColumnCoord colCoord) { ChunkColumn chunkCol = GetColumn(colCoord); if (chunkCol != null) { return(chunkCol.hasMapData); } return(false); }
public void BuildNextColumn() { ColumnCoord currentViewedColumnCoord = columnsToBuild[0]; columnsToBuild.RemoveAt(0); GameObject newColumn = Instantiate(columnPrefab, new Vector3(currentViewedColumnCoord.x * ChunkColumn.chunkSize * ChunkColumn.blockSize, 0, currentViewedColumnCoord.z * ChunkColumn.chunkSize * ChunkColumn.blockSize), Quaternion.identity); newColumn.transform.parent = transform; newColumn.name = "aChunkColumn " + currentViewedColumnCoord.x + " " + currentViewedColumnCoord.z; ChunkColumn chunkColScript = newColumn.GetComponent <ChunkColumn>(); columns.Add(currentViewedColumnCoord, chunkColScript); chunkColScript.Init(currentViewedColumnCoord); chunkColScript.StartGenerating(); }
private void UpdateVisibleChunks() { int currentChunkCoordX = Mathf.RoundToInt(viewer.transform.position.x / (ChunkColumn.chunkSize * ChunkColumn.blockSize)); int currentChunkCoordZ = Mathf.RoundToInt(viewer.transform.position.z / (ChunkColumn.chunkSize * ChunkColumn.blockSize)); ColumnCoord playerCoord = new ColumnCoord(currentChunkCoordX, currentChunkCoordZ); for (int i = chunksVisibleLastUpdate.Count - 1; i >= 0; i--) { if (chunksVisibleLastUpdate[i].colCoord.GetSqrDistance(playerCoord) > sqrViewTreshold) { // Chunk is out of view distance chunksVisibleLastUpdate[i].SetInVisible(); } } //chunksVisibleLastUpdate.Clear(); columnsToBuild.Clear(); for (int zOffset = -viewDistance; zOffset <= viewDistance; zOffset++) { for (int xOffset = -viewDistance; xOffset <= viewDistance; xOffset++) { ColumnCoord currentViewedColumnCoord = new ColumnCoord(currentChunkCoordX + xOffset, currentChunkCoordZ + zOffset); if (currentViewedColumnCoord.GetSqrDistance(playerCoord) < sqrViewTreshold) { ChunkColumn currentColumn; if (columns.TryGetValue(currentViewedColumnCoord, out currentColumn)) { currentColumn.SetVisible(); } else { GenerateColumn(currentViewedColumnCoord); } } } } OrderList(playerCoord); }
public static byte GetBlock(int x, int y, int z) { ColumnCoord colCoord = GetColumnCoord(x, z); try { ChunkColumn chunkCol = null; if (columns.TryGetValue(colCoord, out chunkCol)) { if (chunkCol.hasMapData) { return(chunkCol.GetBlock(x - colCoord.x * ChunkColumn.chunkSize, y, z - colCoord.z * ChunkColumn.chunkSize)); } } } catch (Exception e) { Debug.Log("Chunk error!! " + e); } return(0); }
/// <summary> /// Samples all points in a chunk column using perlin noise /// </summary> /// <param name="colCoord">The coordinate of the chunk</param> /// <returns>The filled noisemap</returns> private float[,,] SamplePoints(ColumnCoord colCoord) { int size = ChunkColumn.chunkSize; int amountOfVerticalChunks = ChunkColumn.worldHeight; float halfSize = size * 0.5f; float[,,] sampleNoiseMap = new float[size / horizontalNoiseScale + 1, size *amountOfVerticalChunks / verticalNoiseScale + 1, size / horizontalNoiseScale + 1]; float sampleX, sampleY, sampleZ, adjustmentVal; // Sampling points for (int x = 0; x < sampleNoiseMap.GetLength(0); x++) { for (int y = 0; y < sampleNoiseMap.GetLength(1); y++) { for (int z = 0; z < sampleNoiseMap.GetLength(2); z++) { Vector3 chunkOffset = new Vector3(colCoord.x, 0, colCoord.z) * size; sampleX = ((float)x * horizontalNoiseScale - halfSize + chunkOffset.x) * ChunkColumn.blockSize / zoomScale; sampleY = ((float)y * verticalNoiseScale + chunkOffset.y) * ChunkColumn.blockSize / zoomScale; sampleZ = ((float)z * horizontalNoiseScale - halfSize + chunkOffset.z) * ChunkColumn.blockSize / zoomScale; sampleNoiseMap[x, y, z] = CustomPerlinNoise.PerlinNoise(sampleX, sampleY, sampleZ); adjustmentVal = (1 - Mathf.InverseLerp(solidHeight, airHeight, y * verticalNoiseScale) * (1 - Mathf.PerlinNoise(sampleX, sampleZ) * 0.2f)) * 2 - 1; adjustmentVal *= adjustScalar; sampleNoiseMap[x, y, z] += adjustmentVal; } } } return(sampleNoiseMap); }
public void Init(ColumnCoord colCoord) { this.colCoord = colCoord; }
/// <summary> /// Interpolate points within a sampling block and translate them to blockId's to fill the array with /// </summary> /// <param name="sampleNoiseMap">Noise map to interpolate from</param> /// <param name="blockMap">BlockId array to fill</param> /// <param name="x">Local x coordinate</param> /// <param name="y">Local y coordinate</param> /// <param name="z">Local z coordinate</param> /// <param name="colCoord">Column coordinate</param> private void InterpolatePoints(ref float[,,] sampleNoiseMap, ref byte[,,] blockMap, int x, int y, int z, ColumnCoord colCoord) { float xStep1, xStep2, xStep3, xStep4, xLerped1, xLerped2, xLerped3, xLerped4, yPercentage, zPercentage, interpolatedY1, interpolatedY2; int blockX, blockY, blockZ; // Accurate interpolation xStep1 = (sampleNoiseMap[x + 1, y, z] - sampleNoiseMap[x, y, z]) / horizontalNoiseScale; xStep2 = (sampleNoiseMap[x + 1, y + 1, z] - sampleNoiseMap[x, y + 1, z]) / horizontalNoiseScale; xStep3 = (sampleNoiseMap[x + 1, y, z + 1] - sampleNoiseMap[x, y, z + 1]) / horizontalNoiseScale; xStep4 = (sampleNoiseMap[x + 1, y + 1, z + 1] - sampleNoiseMap[x, y + 1, z + 1]) / horizontalNoiseScale; for (int k = 0; k < horizontalNoiseScale; k++) { xLerped1 = sampleNoiseMap[x, y, z] + xStep1 * k; xLerped2 = sampleNoiseMap[x, y + 1, z] + xStep2 * k; xLerped3 = sampleNoiseMap[x, y, z + 1] + xStep3 * k; xLerped4 = sampleNoiseMap[x, y + 1, z + 1] + xStep4 * k; for (int j = 0; j < verticalNoiseScale; j++) { yPercentage = (float)j / verticalNoiseScale; interpolatedY1 = Mathf.Lerp(xLerped1, xLerped2, yPercentage); interpolatedY2 = Mathf.Lerp(xLerped3, xLerped4, yPercentage); for (int i = 0; i < horizontalNoiseScale; i++) { zPercentage = (float)i / horizontalNoiseScale; blockX = x * horizontalNoiseScale + k; blockY = y * verticalNoiseScale + j; blockZ = z * horizontalNoiseScale + i; byte blockId = GetBlockIdFromNoise(blockX, blockY, blockZ, Mathf.Lerp(interpolatedY1, interpolatedY2, zPercentage), colCoord); blockMap[blockX, blockY, blockZ] = blockId; // Change top layer to grass if (y == 0) { continue; } if (blockId == 0 && blockMap[blockX, blockY - 1, blockZ] == 2) { // Spawn grass blockMap[blockX, blockY - 1, blockZ] = 3; } } } } }
/// <summary> /// Generate chunk map data based on perlin noise and interpolation /// </summary> /// <param name="colCoord">Column coordinate to sample</param> /// <returns>Chunk block data</returns> public ChunkColumn.MapDataInfo GenerateNoiseMap(ColumnCoord colCoord) { int size = ChunkColumn.chunkSize; int amountOfVerticalChunks = ChunkColumn.worldHeight; ChunkColumn.MapDataInfo mapData = new ChunkColumn.MapDataInfo(); mapData.SetAllEmpty(); byte[,,] chunkBlockData = new byte[size, size *amountOfVerticalChunks, size]; // Sampling all points using perlin noise within chunk float[,,] sampleNoiseMap = SamplePoints(colCoord); // 0 = differences, 1 = all non-solid, 2 = all solid int allSolidIndex; for (int x = 0; x < sampleNoiseMap.GetLength(0) - 1; x++) { for (int y = 0; y < sampleNoiseMap.GetLength(1) - 1; y++) { for (int z = 0; z < sampleNoiseMap.GetLength(2) - 1; z++) { allSolidIndex = GetAllSolidIndex(ref sampleNoiseMap, x, y, z); if (allSolidIndex == 0) { InterpolatePoints(ref sampleNoiseMap, ref chunkBlockData, x, y, z, colCoord); // Any interpolation means the is atleast 1 solid block mapData.isEmpty[(y * verticalNoiseScale + verticalNoiseScale / 2) / ChunkColumn.chunkSize] = false; } else { float noiseVal; int blockX, blockY, blockZ; if (allSolidIndex == 2) { mapData.isEmpty[(y * verticalNoiseScale + verticalNoiseScale / 2) / ChunkColumn.chunkSize] = false; } // All points the same, skip interpolation for (int k = 0; k < horizontalNoiseScale; k++) { for (int j = 0; j < verticalNoiseScale; j++) { for (int i = 0; i < horizontalNoiseScale; i++) { blockX = x * horizontalNoiseScale + k; blockY = y * verticalNoiseScale + j; blockZ = z * horizontalNoiseScale + i; noiseVal = allSolidIndex == 1 ? 0 : 1; byte blockId = GetBlockIdFromNoise(blockX, blockY, blockZ, noiseVal, colCoord); chunkBlockData[blockX, blockY, blockZ] = blockId; // Add grass to the top layer if (y == 0) { continue; } if (blockId == 0 && chunkBlockData[blockX, blockY - 1, blockZ] == 2) { // Spawn grass chunkBlockData[blockX, blockY - 1, blockZ] = 3; } } } } } } } } mapData.voxelData = chunkBlockData; return(mapData); }
public float GetSqrDistance(ColumnCoord colCoord) { return((x - colCoord.x) * (x - colCoord.x) + (z - colCoord.z) * (z - colCoord.z)); }
public static ColumnCoord GetColumnCoord(int x, int z) { ColumnCoord colCoord = new ColumnCoord(Mathf.FloorToInt((float)x / ChunkColumn.chunkSize), Mathf.FloorToInt((float)z / ChunkColumn.chunkSize)); return(colCoord); }
public ThreadMapObject(System.Action <ChunkColumn.MapDataInfo> callback, ColumnCoord colCoord) { this.callback = callback; this.colCoord = colCoord; }
public void GenerateColumn(ColumnCoord colCoord) { columnsToBuild.Add(colCoord); }