public bool SetLight(int2 worldTilePosition, int value, LightType type) { if (!TileUtil.BoundaryCheck(worldTilePosition, mapSize)) { return(false); } int index = TileUtil.To1DIndex(worldTilePosition, mapSize); if (lights[index].GetLight(type) == value) { return(false); } int2 chunkPosition = TileUtil.WorldTileToChunk(worldTilePosition, chunkSize); if (chunks.TryGetValue(chunkPosition, out TileChunk chunk)) { chunk.SetLightDirty(); } else { TileChunk newChunk = GenerateChunk(chunkPosition); newChunk.SetLightDirty(); } lights[index].SetLight(value, type); return(true); }
void OnDrawGizmos() { if (tiles == null) { return; } Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); int2 worldtilePosition = TileUtil.WorldToWorldtile(mousePosition); if (!TileUtil.BoundaryCheck(worldtilePosition, mapSize)) { return; } int tileIndex = TileUtil.To1DIndex(worldtilePosition, mapSize); int tile = tiles[tileIndex]; if (tileInformations[tile].isSolid) { return; } Handles.Label(mousePosition, waterDensities[tileIndex].ToString()); }
public int GetTile(int2 worldTilePosition) { if (!TileUtil.BoundaryCheck(worldTilePosition, mapSize)) { return(-1); } return(tiles[TileUtil.To1DIndex(worldTilePosition, mapSize)]); }
public int GetLight(int2 worldTilePosition, LightType type) { if (!TileUtil.BoundaryCheck(worldTilePosition, mapSize)) { return(0); } return(lights[TileUtil.To1DIndex(worldTilePosition, mapSize)].GetLight(type)); }
void Update() { currentFlowSpeed = Mathf.Clamp01(flowSpeed * Time.deltaTime); if (fluidUpdator == null) { fluidUpdator = StartCoroutine(nameof(UpdateFluid)); } SunLightPropagation(); TorchLightPropagation(ref torchRedLightPropagationQueue, ref torchRedLightRemovalQueue, LightType.R); TorchLightPropagation(ref torchGreenLightPropagationQueue, ref torchGreenLightRemovalQueue, LightType.G); TorchLightPropagation(ref torchBlueLightPropagationQueue, ref torchBlueLightRemovalQueue, LightType.B); UpdateChunks(); Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); int2 worldTilePosition = TileUtil.WorldToWorldtile(mousePosition); if (!TileUtil.BoundaryCheck(worldTilePosition, mapSize)) { return; } if (Input.GetMouseButton(0)) { SetTile(worldTilePosition, tileInformations[1].id); } else if (Input.GetMouseButton(1)) { SetTile(worldTilePosition, tileInformations[0].id); fluidQueue.Enqueue(new Tuple <int, float>(TileUtil.To1DIndex(worldTilePosition, mapSize), 0.0f)); } else if (Input.GetKeyDown(KeyCode.T)) { SetTile(worldTilePosition, tileInformations[3].id); } else if (Input.GetKey(KeyCode.W)) { SetTile(worldTilePosition, tileInformations[2].id); fluidQueue.Enqueue(new Tuple <int, float>(TileUtil.To1DIndex(worldTilePosition, mapSize), waterDensities[TileUtil.To1DIndex(worldTilePosition, mapSize)] + 3.0f)); } }
public bool SetTile(int2 worldTilePosition, int id) { if (!TileUtil.BoundaryCheck(worldTilePosition, mapSize)) { return(false); } int index = TileUtil.To1DIndex(worldTilePosition, mapSize); if (tiles[index] == id) { return(false); } int2 chunkPosition = TileUtil.WorldTileToChunk(worldTilePosition, chunkSize); if (chunks.TryGetValue(chunkPosition, out TileChunk chunk)) { chunk.SetMeshDirty(); } else { TileChunk newChunk = GenerateChunk(chunkPosition); newChunk.SetMeshDirty(); } if (tileInformations[id].isSolid) { fluidQueue.Enqueue(new Tuple <int, float>(index, 0.0f)); } LightEmission beforeEmission = tileInformations[tiles[index]].emission; tiles[index] = id; SetEmission(worldTilePosition, tileInformations[id].emission); CheckTileToUpdateLight(worldTilePosition, id, beforeEmission); return(true); }
void GenerateMesh(int[] tiles, float[] waterDensities) { vertices.Clear(); indices.Clear(); uvs.Clear(); colors.Clear(); paths.Clear();; visited.Clear(); int numQuads = 0; for (int x = 0; x < chunkSize.x; x++) { for (int y = 0; y < chunkSize.y;) { int2 tilePosition = TileUtil.TileToWorldTile(new int2(x, y), chunkPosition, chunkSize); int index = TileUtil.To1DIndex(tilePosition, mapSize); int tile = tiles[index]; if (tile == 0) { y++; continue; } if (visited.Contains(tilePosition)) { y++; continue; } visited.Add(tilePosition); int height; for (height = 1; height + y < chunkSize.y; height++) { int2 nextPosition = tilePosition + TileUtil.Up * height; if (!TileUtil.BoundaryCheck(nextPosition, chunkPosition, chunkSize)) { break; } int nextIndex = TileUtil.To1DIndex(nextPosition, mapSize); int nextTile = tiles[nextIndex]; if (nextTile != tile) { break; } if (!TileManager.tileInformations[tile].isSolid) { break; } if (visited.Contains(nextPosition)) { break; } visited.Add(nextPosition); } bool done = false; int width; for (width = 1; width + x < chunkSize.x; width++) { for (int dy = 0; dy < height; dy++) { int2 nextPosition = tilePosition + TileUtil.Up * dy + TileUtil.Right * width; if (!TileUtil.BoundaryCheck(nextPosition, chunkPosition, chunkSize)) { done = true; break; } int nextIndex = TileUtil.To1DIndex(nextPosition, mapSize); int nextTile = tiles[nextIndex]; if (nextTile != tile || visited.Contains(nextPosition)) { done = true; break; } if (!TileManager.tileInformations[tile].isSolid) { done = true; break; } } if (done) { break; } for (int dy = 0; dy < height; dy++) { int2 nextPosition = tilePosition + TileUtil.Up * dy + TileUtil.Right * width; visited.Add(nextPosition); } } float2 scale = new float2(width, height); List <Vector2> points = new List <Vector2>(); for (int i = 0; i < 4; i++) { Vector2 vertex = tileVertices[i] * scale + tilePosition; vertices.Add(vertex); Vector2 uv2 = tileVertices[i] * scale; Vector4 uv4 = new Vector4(uv2.x, uv2.y, scale.x, scale.y); uvs.Add(uv4); Color32 color = TileManager.tileInformations[tile].color; if (TileManager.tileInformations[tile].isSolid) { colors.Add(color); } else { float density = Mathf.Clamp(waterDensities[index], 0.0f, 1.0f); int2 upPosition = tilePosition + TileUtil.Up; if (TileUtil.BoundaryCheck(upPosition, mapSize)) { int upTile = tiles[TileUtil.To1DIndex(upPosition, mapSize)]; if (!TileManager.tileInformations[upTile].isSolid && upTile != 0) { density = 1.0f; } } int2 downPosition = tilePosition + TileUtil.Down; if (TileUtil.BoundaryCheck(downPosition, mapSize)) { int downTile = tiles[TileUtil.To1DIndex(downPosition, mapSize)]; if (!TileManager.tileInformations[downTile].isSolid && downTile == 0) { density = 1.0f; } } color.a = (byte)(byte.MaxValue * density); colors.Add(color); } // Not Optimized Collider Generation Vector2 point = colliderPoints[i] * scale + tilePosition; points.Add(point); } paths.Add(points); for (int i = 0; i < 6; i++) { indices.Add(tileIndices[i] + numQuads * 4); } y += height; numQuads++; } } }
public void TorchLightPropagation(ref Queue <int2> propagationQueue, ref Queue <Tuple <int2, int> > removalQueue, LightType lightType) { while (removalQueue.Count != 0) { (int2 lightPosition, int torchLight) = removalQueue.Dequeue(); foreach (int2 direction in TileUtil.Direction4) { int2 neighborPosition = lightPosition + direction; if (!TileUtil.BoundaryCheck(neighborPosition, mapSize)) { continue; } int neighborTorchLight = GetLight(neighborPosition, lightType); if (neighborTorchLight != 0 && neighborTorchLight < torchLight) { SetLight(neighborPosition, 0, lightType); removalQueue.Enqueue(new Tuple <int2, int>(neighborPosition, neighborTorchLight)); } else if (neighborTorchLight >= torchLight) { propagationQueue.Enqueue(neighborPosition); } } } while (propagationQueue.Count != 0) { int2 lightPosition = propagationQueue.Dequeue(); int torchLight = GetLight(lightPosition, lightType); if (torchLight <= 0) { continue; } foreach (int2 direction in TileUtil.Direction4) { int2 neighborPosition = lightPosition + direction; if (!TileUtil.BoundaryCheck(neighborPosition, mapSize)) { continue; } int neighborTorchLight = GetLight(neighborPosition, lightType); int resultTorchLight = torchLight - TileLight.SunLightAttenuation; int neighborTile = GetTile(neighborPosition); bool isOpacity = neighborTile != -1 && neighborTile != 0; if (isOpacity) { resultTorchLight -= tileInformations[neighborTile].attenuation; } if (neighborTorchLight >= resultTorchLight) { continue; } SetLight(neighborPosition, resultTorchLight, lightType); propagationQueue.Enqueue(neighborPosition); } } }
public void SunLightPropagation() { while (sunLightRemovalQueue.Count != 0) { (int2 lightPosition, int sunLight) = sunLightRemovalQueue.Dequeue(); foreach (int2 direction in TileUtil.Direction4) { int2 neighborPosition = lightPosition + direction; if (!TileUtil.BoundaryCheck(neighborPosition, mapSize)) { continue; } int neighborSunLight = GetLight(neighborPosition, LightType.S); if (neighborSunLight != 0 && neighborSunLight < sunLight || direction.Equals(TileUtil.Down) && sunLight == TileLight.MaxSunLight) { SetLight(neighborPosition, 0, LightType.S); sunLightRemovalQueue.Enqueue(new Tuple <int2, int>(neighborPosition, neighborSunLight)); } else if (neighborSunLight >= sunLight) { sunLightPropagationQueue.Enqueue(neighborPosition); } } } while (sunLightPropagationQueue.Count != 0) { int2 lightPosition = sunLightPropagationQueue.Dequeue(); int sunLight = GetLight(lightPosition, LightType.S); if (sunLight <= 0) { continue; } foreach (int2 direction in TileUtil.Direction4) { int2 neighborPosition = lightPosition + direction; if (!TileUtil.BoundaryCheck(neighborPosition, mapSize)) { continue; } int neighborSunLight = GetLight(neighborPosition, LightType.S); int resultSunLight = sunLight - TileLight.SunLightAttenuation; int neighborTile = GetTile(neighborPosition); bool isOpacity = neighborTile != -1 && neighborTile != 0; if (isOpacity) { resultSunLight -= tileInformations[neighborTile].attenuation; } if (direction.Equals(TileUtil.Down) && !isOpacity && sunLight == TileLight.MaxSunLight) { SetLight(neighborPosition, TileLight.MaxSunLight, LightType.S); sunLightPropagationQueue.Enqueue(neighborPosition); } else if (neighborSunLight < resultSunLight) { SetLight(neighborPosition, resultSunLight, LightType.S); sunLightPropagationQueue.Enqueue(neighborPosition); } } } }
void CheckTileToUpdateLight(int2 worldTilePosition, int id, LightEmission beforeEmission) { if (id == 0) { foreach (int2 direction in TileUtil.Direction4) { int2 neighborPosition = worldTilePosition + direction; if (!TileUtil.BoundaryCheck(neighborPosition, mapSize)) { continue; } for (int i = 0; i < 4; i++) { LightType lightType = (LightType)i; int neighborLight = GetLight(neighborPosition, lightType); if (neighborLight <= 0) { continue; } switch (lightType) { case LightType.S: sunLightPropagationQueue.Enqueue(neighborPosition); break; case LightType.R: torchRedLightPropagationQueue.Enqueue(neighborPosition); break; case LightType.G: torchGreenLightPropagationQueue.Enqueue(neighborPosition); break; case LightType.B: torchBlueLightPropagationQueue.Enqueue(neighborPosition); break; } } } } else { int sunLight = GetLight(worldTilePosition, LightType.S); SetLight(worldTilePosition, 0, LightType.S); sunLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, sunLight)); foreach (int2 direction in TileUtil.Direction4) { int2 neighborPosition = worldTilePosition + direction; if (!TileUtil.BoundaryCheck(neighborPosition, mapSize)) { continue; } for (int i = 1; i < 4; i++) { LightType lightType = (LightType)i; int neighborLight = GetLight(neighborPosition, lightType); if (neighborLight <= 0) { continue; } switch (lightType) { case LightType.R: torchRedLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, neighborLight)); break; case LightType.G: torchGreenLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, neighborLight)); break; case LightType.B: torchBlueLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, neighborLight)); break; } } } } if (tileInformations[id].emission.r > 0) { torchRedLightPropagationQueue.Enqueue(worldTilePosition); } if (tileInformations[id].emission.g > 0) { torchGreenLightPropagationQueue.Enqueue(worldTilePosition); } if (tileInformations[id].emission.b > 0) { torchBlueLightPropagationQueue.Enqueue(worldTilePosition); } if (beforeEmission.r > 0) { torchRedLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, beforeEmission.r)); } if (beforeEmission.g > 0) { torchGreenLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, beforeEmission.g)); } if (beforeEmission.b > 0) { torchBlueLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, beforeEmission.b)); } }
IEnumerator UpdateFluid() { while (fluidQueue.Count != 0) { (int index, float density) = fluidQueue.Dequeue(); if (TileUtil.BoundaryCheck(index, mapSize)) { waterDensities[index] = density; } } nativeIndices.Clear(); nativeTiles.CopyFrom(tiles); nativeWaterDensities.CopyFrom(waterDensities); for (int i = 0; i < nativeIsSolid.Length; i++) { nativeIsSolid[i] = tileInformations[i].isSolid; } InitDiffJob initJob = new InitDiffJob { waterDiff = nativeWaterDiff }; initJob.Schedule(nativeWaterDiff.Length, 32).Complete(); InitDirtyJob dirtyJob = new InitDirtyJob { waterChunkDirty = nativeWaterChunkDirty }; dirtyJob.Schedule(nativeWaterChunkDirty.Length, 32).Complete(); yield return(null); CalculateFluidJob fluidJob = new CalculateFluidJob { mapSize = mapSize, chunkSize = chunkSize, numChunks = numChunks, maxFlow = maxFlow, minFlow = minFlow, minDensity = minDensity, maxDensity = maxDensity, maxCompress = maxCompress, flowSpeed = currentFlowSpeed, tiles = nativeTiles, waterDensities = nativeWaterDensities, waterDiff = nativeWaterDiff, isSolid = nativeIsSolid, waterChunkDirty = nativeWaterChunkDirty }; fluidJob.Schedule(tiles.Length, 32).Complete(); yield return(null); ApplyFluidJob applyFluidJob = new ApplyFluidJob { minDensity = minDensity, waterDensities = nativeWaterDensities, waterDiff = nativeWaterDiff }; applyFluidJob.Schedule(waterDensities.Length, 32).Complete(); nativeWaterDensities.CopyTo(waterDensities); yield return(null); FilterRemoveFluidJob filterRemoveFluidJob = new FilterRemoveFluidJob { tiles = nativeTiles, isSolid = nativeIsSolid, minDensity = minDensity, waterDensities = nativeWaterDensities }; filterRemoveFluidJob.ScheduleAppend(nativeIndices, tiles.Length, 32).Complete(); yield return(null); foreach (int fluidIndex in nativeIndices) { waterDensities[fluidIndex] = 0.0f; SetTile(TileUtil.To2DIndex(fluidIndex, mapSize), tileInformations[0].id); } nativeIndices.Clear(); FilterCreateFluidJob filterCreateFluidJob = new FilterCreateFluidJob { tiles = nativeTiles, isSolid = nativeIsSolid, minDensity = minDensity, waterDensities = nativeWaterDensities }; filterCreateFluidJob.ScheduleAppend(nativeIndices, tiles.Length, 32).Complete(); yield return(null); foreach (int fluidIndex in nativeIndices) { SetTile(TileUtil.To2DIndex(fluidIndex, mapSize), waterID); } for (int i = 0; i < nativeWaterChunkDirty.Length; i++) { if (!nativeWaterChunkDirty[i]) { continue; } if (chunks.TryGetValue(TileUtil.To2DIndex(i, numChunks), out TileChunk chunk)) { chunk.SetMeshDirty(); } } fluidUpdator = null; }
public void Execute(int tileIndex) { int2 tilePosition = TileUtil.To2DIndex(tileIndex, mapSize); if (tiles[tileIndex] != waterID) { if (isSolid[tiles[tileIndex]]) { waterDensities[tileIndex] = 0.0f; } return; } if (waterDensities[tileIndex] < minDensity) { waterDensities[tileIndex] = 0; return; } float remainingDensity = waterDensities[tileIndex]; if (remainingDensity <= 0) { return; } waterChunkDirty[TileUtil.To1DIndex(TileUtil.WorldTileToChunk(tilePosition, chunkSize), numChunks)] = true; int2 downPosition = tilePosition + TileUtil.Down; int downIndex = TileUtil.To1DIndex(downPosition, mapSize); if (TileUtil.BoundaryCheck(downPosition, mapSize) && !isSolid[tiles[downIndex]]) { float flow = CalculateStableDensity(remainingDensity + waterDensities[downIndex]) - waterDensities[downIndex]; if (flow > minFlow) { flow *= flowSpeed; } flow = Mathf.Clamp(flow, 0, Mathf.Min(maxFlow, remainingDensity)); waterDiff[tileIndex] -= flow; waterDiff[downIndex] += flow; remainingDensity -= flow; } if (remainingDensity < minDensity) { waterDiff[tileIndex] -= remainingDensity; return; } int2 leftPosition = tilePosition + TileUtil.Left; int leftIndex = TileUtil.To1DIndex(leftPosition, mapSize); if (TileUtil.BoundaryCheck(leftIndex, mapSize) && !isSolid[tiles[leftIndex]]) { float flow = (remainingDensity - waterDensities[leftIndex]) / 4.0f; if (flow > minFlow) { flow *= flowSpeed; } flow = Mathf.Clamp(flow, 0, Mathf.Min(maxFlow, remainingDensity)); waterDiff[tileIndex] -= flow; waterDiff[leftIndex] += flow; remainingDensity -= flow; } if (remainingDensity < minDensity) { waterDiff[tileIndex] -= remainingDensity; return; } int2 rightPosition = tilePosition + TileUtil.Right; int rightIndex = TileUtil.To1DIndex(rightPosition, mapSize); if (TileUtil.BoundaryCheck(rightIndex, mapSize) && !isSolid[tiles[rightIndex]]) { float flow = (remainingDensity - waterDensities[rightIndex]) / 3.0f; if (flow > minFlow) { flow *= flowSpeed; } flow = Mathf.Clamp(flow, 0, Mathf.Min(maxFlow, remainingDensity)); waterDiff[tileIndex] -= flow; waterDiff[rightIndex] += flow; remainingDensity -= flow; } if (remainingDensity < minDensity) { waterDiff[tileIndex] -= remainingDensity; return; } int2 upPosition = tilePosition + TileUtil.Up; int upIndex = TileUtil.To1DIndex(upPosition, mapSize); if (TileUtil.BoundaryCheck(upIndex, mapSize) && !isSolid[tiles[upIndex]]) { float flow = remainingDensity - CalculateStableDensity(remainingDensity + waterDensities[upIndex]); if (flow > minFlow) { flow *= flowSpeed; } flow = Mathf.Clamp(flow, 0, Mathf.Min(maxFlow, remainingDensity)); waterDiff[tileIndex] -= flow; waterDiff[upIndex] += flow; remainingDensity -= flow; } if (remainingDensity < minDensity) { waterDiff[tileIndex] -= remainingDensity; } }