public void CullChunks() { Vector3 checkPosition; Vector3 checkSize; checkSize.x = Chunk.SIZE; checkSize.y = Chunk.SIZE; checkSize.z = Chunk.SIZE; UpdateCameraFrustrumPlanes(); int numberOfChunks = ChunkRepository.NumberOfChunks(); for (int chunkIndex = 0; chunkIndex < numberOfChunks; chunkIndex++) { Chunk chunk = ChunkRepository.GetChunkAtIndex(chunkIndex); checkPosition.x = chunk.WorldPosition().x *Chunk.SIZE + Chunk.SIZE / 2; checkPosition.y = chunk.WorldPosition().y *Chunk.SIZE + Chunk.SIZE / 2; checkPosition.z = chunk.WorldPosition().z *Chunk.SIZE + Chunk.SIZE / 2; if (CubeIsWithinFrustrum(checkPosition, checkSize)) { chunk.Show(); } else { chunk.Hide(); } } }
// TODO -- This needs to be updated to not directly reference the player public bool PotentialEntityCollision(BlockSpacePosition position) { Block block = ChunkRepository.GetBlockAtPosition(position); if (block.IsSolidToTouch()) { // No use checking for entities if we already know that this spot is taken return(true); } VoxelCharacterController[] characters = UnityEngine.Component.FindObjectsOfType(typeof(VoxelCharacterController)) as VoxelCharacterController[]; int charactersLength = characters.Length; for (int i = 0; i < charactersLength; i++) { VoxelCharacterController character = characters[i]; if (character.transform.position.x - character.radius + 0.5f < position.x + 0.5f && character.transform.position.x + character.radius + 0.5f > position.x - 0.5f && character.transform.position.z - character.radius + 0.5f < position.z + 0.5f && character.transform.position.z + character.radius + 0.5f > position.z - 0.5f && character.transform.position.y - character.height / 2.0f + 0.5f < position.y + 0.5f && character.transform.position.y + character.height / 2.0f + 0.5f > position.y - 0.5f) { return(true); } } return(false); }
public List <BlockLight> GetAllLightsWithinMaxRange(ChunkSpacePosition chunkPosition) { int distance = Configuration.MAX_LIGHT_RADIUS + Chunk.SIZE / 2; BlockSpacePosition checkPosition; checkPosition.x = chunkPosition.x * Chunk.SIZE + Chunk.SIZE / 2; checkPosition.y = chunkPosition.y * Chunk.SIZE + Chunk.SIZE / 2; checkPosition.z = chunkPosition.z * Chunk.SIZE + Chunk.SIZE / 2; List <BlockLight> lights = new List <BlockLight>(); foreach (Chunk chunk in ChunkRepository.IterateChunksWithinRadius(checkPosition, distance)) { // TODO -- This isn't super efficient on memory, but required for thread safety. Try to figure out a // better way of doing this. BlockLight[] chunkLights; lock (chunk) { chunkLights = chunk.LightsArray(); } int chunkLightsLength = chunkLights.Length; for (int chunkLightsIndex = 0; chunkLightsIndex < chunkLightsLength; chunkLightsIndex++) { BlockLight light = chunkLights[chunkLightsIndex]; BlockSpacePosition lightPosition = light.chunkPosition.GetBlockSpacePosition(chunk); if (BlockIsNotHidden(lightPosition)) { lights.Add(light); } } } return(lights); }
private static void MarkChunkAsNeedingMeshUpdate(ChunkSpacePosition position) { Chunk checkChunk = ChunkRepository.GetChunkAtPosition(position); if (checkChunk != null) { checkChunk.MarkForMeshUpdate(); } }
public void MarkChunksWithinMaxLightRadiusForMeshUpdate(BlockSpacePosition position) { int distance = Configuration.MAX_LIGHT_RADIUS + Chunk.SIZE / 2; foreach (Chunk chunk in ChunkRepository.IterateChunksWithinRadius(position, distance)) { chunk.MarkForMeshUpdate(); ChunkRepository.AddToProcessingChunkList(chunk); } }
private Chunk GenerateChunk(ChunkSpacePosition position) { int arrayX = (position.x - worldViewPositionX) + Configuration.CHUNK_VIEW_DISTANCE; int arrayZ = (position.z - worldViewPositionZ) + Configuration.CHUNK_VIEW_DISTANCE; Chunk newChunk = chunkPool.GetChunk(position); ChunkRepository.Add(newChunk); ChunkRepository.SetChunkAtPosition(position, newChunk); loadedChunksCheckArray[arrayX, position.y, arrayZ] = true; newChunk.LoadOrGenerate(); return(newChunk); }
// TODO -- Split up this function to make it shorter and more manageable public void CleanupOldChunks() { // TODO -- This is a weird place to update the worldviewposition worldViewPositionX = (int)(Camera.main.transform.position.x / Chunk.SIZE); worldViewPositionZ = (int)(Camera.main.transform.position.z / Chunk.SIZE); for (int xIttr = 0; xIttr < Configuration.CHUNK_VIEW_DISTANCE * 2 + 1; xIttr++) { for (int yIttr = 0; yIttr < chunkArrayHeight; yIttr++) { for (int zIttr = 0; zIttr < Configuration.CHUNK_VIEW_DISTANCE * 2 + 1; zIttr++) { loadedChunksCheckArray[xIttr, yIttr, zIttr] = false; } } } // Get rid of chunks that are too far from the camera for (int chunkIndex = 0; chunkIndex < ChunkRepository.NumberOfChunks(); chunkIndex++) { Chunk chunk = ChunkRepository.GetChunkAtIndex(chunkIndex); // If the chunk is out of range now, return it int xDiff = Mathf.Abs(chunk.WorldPosition().x - worldViewPositionX); int zDiff = Mathf.Abs(chunk.WorldPosition().z - worldViewPositionZ); if ((xDiff > Configuration.CHUNK_VIEW_DISTANCE) || (zDiff > Configuration.CHUNK_VIEW_DISTANCE)) { ChunkSpacePosition location = chunk.WorldPosition(); ChunkRepository.SetChunkAtPosition(location, null); ChunkRepository.Remove(chunk); chunk.MarkForUnload(); unloadChunksList.Add(chunk); } else { int markX = (chunk.WorldPosition().x - worldViewPositionX) + Configuration.CHUNK_VIEW_DISTANCE; int markZ = (chunk.WorldPosition().z - worldViewPositionZ) + Configuration.CHUNK_VIEW_DISTANCE; loadedChunksCheckArray[markX, chunk.WorldPosition().y, markZ] = true; } } }
public IEnumerable IterateChunksAroundTheWorldPosition(int numberOfSpokes) { ChunkSpacePosition lastPosition; lastPosition.x = 0; lastPosition.y = 0; lastPosition.z = 0; Chunk chunk = null; for (int distance = 0; distance <= Configuration.CHUNK_VIEW_DISTANCE; distance++) { for (int angle = 0; angle < 360 / numberOfSpokes; angle += 1) { for (int worldHeight = chunkArrayHeight - 1; worldHeight >= 0; worldHeight--) { for (int spokeNum = 0; spokeNum < numberOfSpokes; spokeNum++) { float calculateAngle = angle + spokeNum * (360 / numberOfSpokes); int xOffset = (int)(Mathf.Sin(Mathf.Deg2Rad * calculateAngle) * (distance + 0.5f)); int zOffset = (int)(Mathf.Cos(Mathf.Deg2Rad * calculateAngle) * (distance + 0.5f)); //if (frameStopwatch.ElapsedMilliseconds >= partialFrameLength) { break; } ChunkSpacePosition position; position.x = worldViewPositionX + xOffset; position.y = worldHeight; position.z = worldViewPositionZ + zOffset; if (chunk == null || lastPosition.x != position.x || lastPosition.y != position.y || lastPosition.z != position.z) { chunk = ChunkRepository.GetChunkAtPosition(position); if (chunk != null) { yield return(chunk); } lastPosition = position; } } } } } }
// TODO -- Make this func shorter public void GenerateMeshes(Chunk chunk) { if (chunk.NeedsMeshUpdate() && (chunk.GetLoadState() == ChunkLoadState.WaitingForMeshUpdate || chunk.GetLoadState() == ChunkLoadState.Done)) { ChunkSpacePosition position = chunk.WorldPosition(); position.z -= 1; Chunk northChunk = ChunkRepository.GetChunkAtPosition(position); position = chunk.WorldPosition(); position.z += 1; Chunk southChunk = ChunkRepository.GetChunkAtPosition(position); position = chunk.WorldPosition(); position.x -= 1; Chunk westChunk = ChunkRepository.GetChunkAtPosition(position); position = chunk.WorldPosition(); position.x += 1; Chunk eastChunk = ChunkRepository.GetChunkAtPosition(position); position = chunk.WorldPosition(); position.y += 1; Chunk aboveChunk = ChunkRepository.GetChunkAtPosition(position); position = chunk.WorldPosition(); position.y -= 1; Chunk belowChunk = ChunkRepository.GetChunkAtPosition(position); if ((northChunk == null || northChunk.BlocksAreGenerating() == false) && (southChunk == null || southChunk.BlocksAreGenerating() == false) && (westChunk == null || westChunk.BlocksAreGenerating() == false) && (eastChunk == null || eastChunk.BlocksAreGenerating() == false) && (aboveChunk == null || aboveChunk.BlocksAreGenerating() == false) && (belowChunk == null || belowChunk.BlocksAreGenerating() == false)) { chunk.GenerateMesh(northChunk, southChunk, westChunk, eastChunk, aboveChunk, belowChunk); } } }
public bool RegionIsSolid(Vector3 origin, Vector3 size) { Vector3 lowerPoint; Vector3 upperPoint; lowerPoint.x = Mathf.Ceil(origin.x - size.x / 2.0f); lowerPoint.y = Mathf.Ceil(origin.y - size.y / 2.0f); lowerPoint.z = Mathf.Ceil(origin.z - size.z / 2.0f); upperPoint.x = Mathf.Ceil(origin.x + size.x / 2.0f); upperPoint.y = Mathf.Ceil(origin.y + size.y / 2.0f); upperPoint.z = Mathf.Ceil(origin.z + size.z / 2.0f); #if DEBUG DebugUtils.DrawCube(origin, size / 2.0f, Color.yellow, 0, true); #endif Vector3 drawSize; drawSize.x = (upperPoint.x - lowerPoint.x + 1.0f) / 2.0f; drawSize.y = (upperPoint.y - lowerPoint.y + 1.0f) / 2.0f; drawSize.z = (upperPoint.z - lowerPoint.z + 1.0f) / 2.0f; Vector3 drawPoint; drawPoint.x = lowerPoint.x + drawSize.x - 1.0f; drawPoint.y = lowerPoint.y + drawSize.y - 1.0f; drawPoint.z = lowerPoint.z + drawSize.z - 1.0f; #if DEBUG DebugUtils.DrawCube(drawPoint, drawSize, Color.green, 0, true); DebugUtils.DrawMark(lowerPoint, Color.red, 0); DebugUtils.DrawMark(upperPoint, Color.red, 0); #endif bool solid = false; int checkX, checkY, checkZ; for (checkX = (int)lowerPoint.x; checkX <= upperPoint.x; checkX += 1) { for (checkY = (int)lowerPoint.y; checkY <= upperPoint.y; checkY += 1) { for (checkZ = (int)lowerPoint.z; checkZ <= upperPoint.z; checkZ += 1) { BlockSpacePosition checkPosition; checkPosition.x = checkX; checkPosition.y = checkY; checkPosition.z = checkZ; Block checkBlock = ChunkRepository.GetBlockAtPosition(checkPosition); solid = checkBlock.IsSolidToTouch(); if (solid) { Vector3 markPoint; markPoint.x = checkX; markPoint.y = checkY; markPoint.z = checkZ; #if DEBUG DebugUtils.DrawMark(markPoint, Color.blue, 0); #endif } if (solid) { break; } } if (solid) { break; } } if (solid) { break; } } return(solid); }
public bool RaytraceCollision(Vector3 origin, Vector3 direction, float maxDistance, bool ignoreStartAndEnd, bool drawDebug, out Block hitBlock, out Vector3 hitBlockLocation, out Vector3 hitNormal) { hitBlock = Block.EmptyBlock(); hitBlockLocation = Vector3.zero; hitNormal = Vector3.zero; bool hit = false; Vector3 movementAddition = Vector3.Normalize(direction); float movementSpeed = 0.05f; movementAddition.x *= movementSpeed; movementAddition.y *= movementSpeed; movementAddition.z *= movementSpeed; ray.direction = direction.normalized; Vector3 checkPosition = origin; Vector3 prevCheckPosition = checkPosition; float checkDistance = 0.0f; bool refreshXPlane = true; bool refreshYPlane = true; bool refreshZPlane = true; float xDistance = maxDistance; float yDistance = maxDistance; float zDistance = maxDistance; Chunk chunkCache = null; while (checkDistance <= maxDistance) { bool validBlock = ignoreStartAndEnd == false || ( ( (int)checkPosition.x != (int)origin.x || (int)checkPosition.y != (int)origin.y || (int)checkPosition.z != (int)origin.z ) ); ChunkBlockPair chunkBlockPair = ChunkRepository.GetBlockAtPosition(checkPosition, chunkCache); chunkCache = chunkBlockPair.chunk; if (drawDebug && chunkBlockPair.chunk != null) { Vector3 drawPosition; drawPosition.x = chunkBlockPair.chunk.WorldPosition().x *Chunk.SIZE + Chunk.SIZE / 2; drawPosition.y = chunkBlockPair.chunk.WorldPosition().y *Chunk.SIZE + Chunk.SIZE / 2; drawPosition.z = chunkBlockPair.chunk.WorldPosition().z *Chunk.SIZE + Chunk.SIZE / 2; DebugUtils.DrawCube(drawPosition, Vector3.one * Chunk.SIZE / 2, Color.magenta, 0, true); } Block checkBlock = chunkBlockPair.block; if (checkBlock.IsSolidToTouch() && validBlock) { hitBlock = checkBlock; hitBlockLocation = checkPosition; hit = true; if ((int)prevCheckPosition.y != (int)checkPosition.y) { hitNormal.y = ((int)prevCheckPosition.y).CompareTo((int)checkPosition.y); } else if ((int)prevCheckPosition.x != (int)checkPosition.x) { hitNormal.x = ((int)prevCheckPosition.x).CompareTo((int)checkPosition.x); } else if ((int)prevCheckPosition.z != (int)checkPosition.z) { hitNormal.z = ((int)prevCheckPosition.z).CompareTo((int)checkPosition.z); } break; } else { prevCheckPosition = checkPosition; ray.origin = checkPosition; // ---- X ---- if (refreshXPlane) { if (direction.x < 0.0f) { Vector3 westPlanePosition; if (checkPosition.x == Mathf.Floor(checkPosition.x)) { westPlanePosition.x = Mathf.Floor(checkPosition.x) - 1.0f - INSIDE_WALL_OFFSET; } else { westPlanePosition.x = Mathf.Floor(checkPosition.x) - INSIDE_WALL_OFFSET; } westPlanePosition.y = 0.0f; westPlanePosition.z = 0.0f; plane.SetNormalAndPosition(Vector3.right, westPlanePosition); plane.Raycast(ray, out xDistance); } else if (direction.x > 0.0f) { Vector3 eastPlanePosition; eastPlanePosition.x = Mathf.Floor(checkPosition.x) + 1.0f; eastPlanePosition.y = 0.0f; eastPlanePosition.z = 0.0f; plane.SetNormalAndPosition(Vector3.left, eastPlanePosition); plane.Raycast(ray, out xDistance); } } // ---- Y ---- if (refreshYPlane) { if (direction.y < 0.0f) { Vector3 downwardPlanePosition; downwardPlanePosition.x = 0.0f; if (checkPosition.y == Mathf.Floor(checkPosition.y)) { downwardPlanePosition.y = Mathf.Floor(checkPosition.y) - 1.0f - INSIDE_WALL_OFFSET; } else { downwardPlanePosition.y = Mathf.Floor(checkPosition.y) - INSIDE_WALL_OFFSET; } downwardPlanePosition.z = 0.0f; plane.SetNormalAndPosition(Vector3.down, downwardPlanePosition); plane.Raycast(ray, out yDistance); } else if (direction.y > 0.0f) { Vector3 upwardPlanePosition; upwardPlanePosition.x = 0.0f; upwardPlanePosition.y = Mathf.Floor(checkPosition.y) + 1.0f; upwardPlanePosition.z = 0.0f; plane.SetNormalAndPosition(Vector3.up, upwardPlanePosition); plane.Raycast(ray, out yDistance); } } // ---- Z ---- if (refreshZPlane) { if (direction.z < 0.0f) { Vector3 southPlanePosition; southPlanePosition.x = 0.0f; southPlanePosition.y = 0.0f; if (checkPosition.z == Mathf.Floor(checkPosition.z)) { southPlanePosition.z = Mathf.Floor(checkPosition.z) - 1.0f - INSIDE_WALL_OFFSET; } else { southPlanePosition.z = Mathf.Floor(checkPosition.z) - INSIDE_WALL_OFFSET; } plane.SetNormalAndPosition(Vector3.forward, southPlanePosition); plane.Raycast(ray, out zDistance); } else if (direction.z > 0.0f) { Vector3 northPlanePosition; northPlanePosition.x = 0.0f; northPlanePosition.y = 0.0f; northPlanePosition.z = Mathf.Floor(checkPosition.z) + 1.0f; plane.SetNormalAndPosition(Vector3.back, northPlanePosition); plane.Raycast(ray, out zDistance); } } float distance; if (xDistance > 0.0f && (xDistance < zDistance || zDistance == 0.0f) && (xDistance < yDistance || yDistance == 0.0f)) { distance = xDistance; refreshXPlane = true; } else if (zDistance > 0.0f && (zDistance < yDistance || yDistance == 0.0f)) { distance = zDistance; refreshZPlane = true; if (xDistance == zDistance) { refreshXPlane = true; } } else { distance = yDistance; refreshYPlane = true; if (xDistance == yDistance) { refreshXPlane = true; } if (zDistance == yDistance) { refreshZPlane = true; } } if (distance < 0.0f) { Debug.LogWarning("Distance: " + distance); throw new Exception("Distance: " + distance + ". direction: " + direction + ". x dist: " + xDistance + ". y dist: " + yDistance + ". z dist: " + zDistance); } Vector3 drawPoint1 = checkPosition; if (drawDebug) { DebugUtils.DrawMark(checkPosition, Color.red, 0); Vector3 drawPosition; drawPosition.x = Mathf.Floor(checkPosition.x) + 0.5f; drawPosition.y = Mathf.Floor(checkPosition.y) + 0.5f; drawPosition.z = Mathf.Floor(checkPosition.z) + 0.5f; DebugUtils.DrawCube(drawPosition, Vector3.one / 2.0f, Color.blue, 0, true); } checkPosition = ray.GetPoint(distance); checkDistance += distance; if (drawDebug) { DebugUtils.DrawMark(checkPosition, Color.green, 0); UnityEngine.Debug.DrawLine(drawPoint1, checkPosition, Color.white, 0.0f, true); } xDistance -= distance; yDistance -= distance; zDistance -= distance; } } return(hit); }
private static bool BlockIsActive(BlockSpacePosition position) { return(ChunkRepository.GetBlockAtPosition(position).IsActive()); }
private bool RaytraceLightBeam(BlockSpacePosition lightPosition, BlockSpacePosition samplePosition, CubeSide sampleSide, byte inLightHue, byte inLightSaturation, byte inLightValue, out byte outLightHue, out byte outLightSaturation, out byte outLightValue) { // Setup outLightHue = inLightHue; outLightSaturation = inLightSaturation; outLightValue = inLightValue; Vector3 originVector; Vector3 endpointVector; originVector = lightPosition.GetVector3(); originVector.x += 0.5f; originVector.y += 0.5f; originVector.z += 0.5f; endpointVector = samplePosition.GetVector3(); endpointVector.x += 0.5f; endpointVector.y += 0.5f; endpointVector.z += 0.5f; if (sampleSide == CubeSide.West) { endpointVector.x -= 0.5f; } if (sampleSide == CubeSide.East) { endpointVector.x += 0.5f; } if (sampleSide == CubeSide.North) { endpointVector.z -= 0.5f; } if (sampleSide == CubeSide.South) { endpointVector.z += 0.5f; } if (sampleSide == CubeSide.Bottom) { endpointVector.y -= 0.5f; } if (sampleSide == CubeSide.Top) { endpointVector.y += 0.5f; } // Do the raytrace Vector3 direction = Vector3.Normalize(endpointVector - originVector); float maxDistance = Vector3.Distance(originVector, endpointVector) - 1.0f; Vector3 movementAddition = Vector3.Normalize(direction); float movementSpeed = 0.05f; movementAddition.x *= movementSpeed; movementAddition.y *= movementSpeed; movementAddition.z *= movementSpeed; Vector3 checkPosition = originVector; Vector3 prevCheckPosition = checkPosition; float checkDistance = 0.0f; Chunk chunkCache = null; while (checkDistance <= maxDistance) { bool validBlock = (int)checkPosition.x != (int)originVector.x || (int)checkPosition.y != (int)originVector.y || (int)checkPosition.z != (int)originVector.z; ChunkBlockPair chunkBlockPair = ChunkRepository.GetBlockAtPosition(checkPosition, chunkCache); chunkCache = chunkBlockPair.chunk; Block checkBlock = chunkBlockPair.block; if (checkBlock.IsActive() && checkBlock.IsTransparent()) { HSBColor outLightColor = FilterLightSample(outLightHue, outLightSaturation, outLightValue, checkBlock.FilterColorHue(), checkBlock.FilterColorSaturation(), checkBlock.FilterColorValue()); outLightHue = (byte)(outLightColor.h * byte.MaxValue); outLightSaturation = (byte)(outLightColor.s * byte.MaxValue); outLightValue = (byte)(outLightColor.b * byte.MaxValue); } if (checkBlock.IsSolidToTouch() && validBlock && checkBlock.IsNotTransparent()) { return(true); } else { prevCheckPosition = checkPosition; do { checkPosition += movementAddition; checkDistance += movementSpeed; }while((int)checkPosition.x == (int)prevCheckPosition.x && (int)checkPosition.y == (int)prevCheckPosition.y && (int)checkPosition.z == (int)prevCheckPosition.z); } } return(false); }