public Voxel GetVoxelAtHeight(int height, int y) { // Top layer should be grass var id = VoxelDictionary.IdByName("grass"); if (y < height) { id = VoxelDictionary.IdByName("dirt"); } if (y < height - 2) { id = VoxelDictionary.IdByName("stone"); } if (y > height && y <= Chunk.SEA_LEVEL) { id = VoxelDictionary.IdByName("water"); } if (y == height && y <= Chunk.SEA_LEVEL) { id = VoxelDictionary.IdByName("sand"); } if (y > height && y > Chunk.SEA_LEVEL) { id = 0; } return(new Voxel(id)); }
// Initialization private void Initialize() { VoxelWorld = new VoxelWorld(4582); UpdateJobs = new BlockingCollection <ChunkUpdateJob>(new ConcurrentStack <ChunkUpdateJob>()); _meshResults = new ConcurrentStack <ChunkMeshResult>(); _lightResults = new ConcurrentStack <ChunkLightResult>(); // Initialize the voxel dictionary VoxelDictionary.InitializeVoxelDictionary(); // Instantiate a new runtime texture atlas AtlasGenerator = new RuntimeTextureAtlas(); // Instantiate mesh workers proportional to system thread count var workerCount = Environment.ProcessorCount > 4 ? Environment.ProcessorCount - 2 : 2; _meshExtractors = new ChunkUpdateWorker[workerCount]; for (var i = 0; i < _meshExtractors.Length; i++) { _meshExtractors[i] = new ChunkUpdateWorker(UpdateJobs, _meshResults); } // Start the chunk generation routine StartCoroutine(nameof(GenerateChunks)); }
/// <summary> /// Handles stone, sea-level water, and eventually caves. /// Maybe Grass, dirt, etc /// </summary> private void GenerationFirstPass() { for (var z = 0; z < CHUNK_LENGTH; z++) { for (var y = 0; y < CHUNK_HEIGHT; y++) { for (var x = 0; x < CHUNK_LENGTH; x++) { var seq = x + CHUNK_LENGTH * (y + CHUNK_HEIGHT * z); // Fill according to height map var height = _heightMap[x + z * CHUNK_LENGTH]; HeightMapMax = Mathf.Max(HeightMapMax, height); // Skip voxels above the height map and sea level if (y > height && y > SEA_LEVEL) { continue; } var voxel = _world.GetBiomeAtPosition(WorldPosition.x + x, WorldPosition.y + z).GetVoxelAtHeight(height, y); if (voxel.Id == VoxelDictionary.IdByName("water")) { _heightMap[x + z * CHUNK_LENGTH] = Mathf.Max(height, y); } _voxels[seq] = voxel; } } } }
private void Update() { if (Input.GetKeyDown(KeyCode.Mouse0)) { RaycastHit hit; var rayHit = Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hit, 12f, Mask); if (rayHit) { var hitPoint = hit.point + (Camera.main.transform.forward * 0.25f); var voxelPos = new Vector3Int(Mathf.RoundToInt(hitPoint.x), Mathf.RoundToInt(hitPoint.y), Mathf.RoundToInt(hitPoint.z)); WorldSystem.Instance.VoxelWorld.TrySetVoxel(voxelPos, new Voxel(0)); } } if (Input.GetKeyDown(KeyCode.Mouse1)) { RaycastHit hit; var rayHit = Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hit, 12f, Mask); if (rayHit) { var hitPoint = hit.point; var voxelPos = new Vector3Int(Mathf.RoundToInt(hitPoint.x + hit.normal.x * 0.6f), Mathf.RoundToInt(hitPoint.y + hit.normal.y * 0.5f), Mathf.RoundToInt(hitPoint.z + hit.normal.z * 0.5f)); WorldSystem.Instance.VoxelWorld.TrySetVoxel(voxelPos, new Voxel(VoxelDictionary.IdByName("light_stone_lamp"))); } } }
/// <summary> /// Sets a voxel at the specified position. /// Will throw an exception if the position is out of range. /// Chunk update event is invoked by default and should only be changed /// under special circumstances. /// </summary> private void SetVoxel(Vector3Int pos, Voxel voxel) { // Disallow editing of bedrock voxels if (_voxels[pos.x + CHUNK_LENGTH * (pos.y + CHUNK_HEIGHT * pos.z)].Id == VoxelDictionary.IdByName("bedrock")) { return; } // Set the voxel _voxels[pos.x + CHUNK_LENGTH * (pos.y + CHUNK_HEIGHT * pos.z)] = voxel; // Determine if this was a placement or removal (set to air) if (voxel.Id == 0) { // Update light sources lock (LightSources) { if (LightSources.ContainsKey(pos)) { LightSources.Remove(pos); } } // Update height map HeightMapMax = Mathf.Max(HeightMapMax, pos.y); if (_heightMap[pos.x + pos.z * CHUNK_LENGTH] == pos.y) { _heightMap[pos.x + pos.z * CHUNK_LENGTH] = pos.y - 1; } } else { // Update height map HeightMapMax = Mathf.Max(HeightMapMax, pos.y); if (_heightMap[pos.x + pos.z * CHUNK_LENGTH] < pos.y) { _heightMap[pos.x + pos.z * CHUNK_LENGTH] = pos.y; } } // Update light sources if necessary var voxelData = VoxelDictionary.VoxelData[voxel.Id]; if (voxelData.LightValue > 0) { SetBlockLight(pos, voxelData.LightValue); lock (LightSources) { if (!LightSources.ContainsKey(pos)) { LightSources.Add(pos, voxelData.LightValue); } else { LightSources[pos] = voxelData.LightValue; } } } }