public static void UpdateDiscoveryStatusOnSideThread(DiscoveryMap discoveryMap, List <Observer.Info> observerInfo) { discoveryMap.ClearCurrentVisibilityBlock(); pixelBlock = discoveryMap.asPixelBlock; currentVisibilityBlock = discoveryMap.currentVisibilityPixelBlock; heightArray = discoveryMap.heightMap; mapPixelWidth = discoveryMap.pixelWidth; mapPixelHeight = discoveryMap.pixelHeight; for (int i = 0; i < observerInfo.Count; ++i) { var observer = observerInfo[i]; int startX = Mathf.RoundToInt(observer.mapPositionX); int startY = Mathf.RoundToInt(observer.mapPositionY); // Draw 1/8th of a circle int r = Mathf.RoundToInt(observer.viewRadiusMapUnits); int deltaX = r; int deltaY = 0; do { if (r <= deltaY * deltaY) { deltaX -= 1; r += 2 * deltaX + 1; } DiscoverLOS(discoveryMap, deltaX, deltaY, startX, startY, observer.height); deltaY++; } while (deltaY < deltaX); } }
public void Setup(float worldRadius, DiscoveryMap map) { terrainOffset = map.terrainOffset; terrainSize = map.terrainSize; discoveryMapSize = map.mapSize; UpdatePosition(CachedTransform.position); UpdateRadius(worldRadius); }
private void Start() { discoveryMap = new DiscoveryMap(terrain); discoveryMapMaterial.SetTexture("_Mask", discoveryMap.texture); discoveryMapMaterial.SetTexture("_CurrentVisibility", discoveryMap.currentVisibilityMap); discoveryMapMaterial.SetVector("_TerrainSize", discoveryMap.terrainSize); mainCamera = Camera.main; mainCamTransform = mainCamera.transform; }
private void AdjustHeightMap(DiscoveryMap map, bool add) { Vector2 mapCentre = map.CalculateMapPosition(transform.position); Vector2 mapSpaceSize = map.CalculateMapSpaceDimensions(Size); float orientation = Mathf.Deg2Rad * transform.eulerAngles.y; float cos = Mathf.Cos(orientation); float sin = Mathf.Sin(orientation); Vector2 right = new Vector2(cos, sin); Vector2 up = new Vector2(-sin, cos); Vector2 mapStartPos = mapCentre - (right * mapSpaceSize.x / 2f) - (up * mapSpaceSize.y / 2f); IntVector2 mapStartIndex = new IntVector2(Mathf.RoundToInt(mapStartPos.x), Mathf.RoundToInt(mapStartPos.y)); var actualHeights = relativeHeightMap.actualHeights; Vector2 pos = mapStartPos; float sign = add ? 1f : -1f; for (int y = 0; y < mapSpaceSize.y; ++y) { for (int x = 0; x < mapSpaceSize.x; ++x) { IntVector2 customHeightMapIndex = new IntVector2(x * relativeHeightMap.sizeX / mapSpaceSize.x, y * relativeHeightMap.sizeY / mapSpaceSize.y); IntVector2 nextCustomHeightMapIndex = new IntVector2((x + 1) * relativeHeightMap.sizeX / mapSpaceSize.x, (y + 1) * relativeHeightMap.sizeY / mapSpaceSize.y); int affectedHeightmapPixelCount = 0; float heightAdjustmentValue = 0f; bool paintedAtLeastOnePixel = false; for (int cy = customHeightMapIndex.y; !paintedAtLeastOnePixel || cy < nextCustomHeightMapIndex.y; ++cy) { for (int cx = customHeightMapIndex.x; !paintedAtLeastOnePixel || cx < nextCustomHeightMapIndex.x; ++cx) { paintedAtLeastOnePixel = true; if (cx >= 0 && cx < relativeHeightMap.sizeX && cy >= 0 && cy < relativeHeightMap.sizeY) { float heightDelta = actualHeights[cy, cx] * sign; affectedHeightmapPixelCount++; heightAdjustmentValue += heightDelta; } } } if (affectedHeightmapPixelCount > 0) { Vector2 nextMapPos = mapStartPos + right * x + up * y; int mapIndexX = Mathf.RoundToInt(nextMapPos.x); int mapIndexY = Mathf.RoundToInt(nextMapPos.y); map.heightMap[mapIndexY, mapIndexX] += (heightAdjustmentValue / affectedHeightmapPixelCount); } } } }
public void RemoveFromMap(DiscoveryMap map) { AdjustHeightMap(map, add: false); isPlacedOnMap = false; }
public void PlaceOnMap(DiscoveryMap map) { relativeHeightMap.CalculateActualHeight(Size.y, map.terrainSize.y); AdjustHeightMap(map, add: true); isPlacedOnMap = true; }
private static bool DiscoverLOS(DiscoveryMap map, int deltaX, int deltaY, int startX, int startY, float obsHeight) { pixelBlock[startY * mapPixelWidth + startX] = discovered; // This is essentially a line-drawing routine that has some strong assumptions: // namely that deltaX > deltaY. Then, after the calculation of each point in the line, // it mirrors it 7 times, to replicate a filled circle. bool didUpdate = false; float startHeight = heightArray[startY, startX] + obsHeight; for (int i = 0; i < 8; ++i) { // Negative height means no blocking height found. wBlockerHeight[i] = -startHeight; } int maxLen = pixelBlock.Length; for (int circleSegment = 0; circleSegment < 8; ++circleSegment) { int counter = deltaX / 2; int currentX = startX; int currentY = startY; for (int i = 0; i < deltaX; ++i) { counter += deltaY; if (counter > deltaX) { counter -= deltaX; currentY += 1; } currentX += 1; if (currentX < 0 || currentX >= mapPixelWidth || currentY < 0 || currentY >= mapPixelHeight) { continue; } int dx = currentX - startX; int dy = currentY - startY; // Depending on the segment of the circle we're in, we have to mirror // the original coordinate pair of (dx, dy), in all combinations of (+/-dx and +/-dy), // e.g. in the 1st segment, the pair turns into (-dx, dy), in the next one into (dx, -dy) etc. int wdx = circleSegment < 4 ? dx : dy; int wdy = circleSegment < 4 ? (circleSegment < 2 ? dy : -dy) : (circleSegment < 6 ? dx : -dx); if (circleSegment % 2 != 0) { wdx *= -1; } int y = startY + wdy; int x = startX + wdx; if (x < 0 || x >= mapPixelWidth || y < 0 || y >= mapPixelHeight) { continue; } float currentHeight = heightArray[y, x]; // Found a blocker if the blocker height is > 0f if (wBlockerHeight[circleSegment] < 0f) { if (currentHeight > startHeight) { wBlockerHeight[circleSegment] = currentHeight; } } int index = (y * mapPixelWidth) + x; bool hasNotFoundBlockerYet = wBlockerHeight[circleSegment] < 0f; bool currentHeightHigherThanLastBlocker = currentHeight >= wBlockerHeight[circleSegment]; if (hasNotFoundBlockerYet || currentHeightHigherThanLastBlocker) { if (currentHeight > wBlockerHeight[circleSegment] && !hasNotFoundBlockerYet) { wBlockerHeight[circleSegment] = currentHeight; } if (index < maxLen) { didUpdate = didUpdate || pixelBlock[i].a <= 0; pixelBlock[index] = discovered; currentVisibilityBlock[index] = discovered; // Paint an extra pixel to cover accidental holes if (index + mapPixelWidth < maxLen) { pixelBlock[index + mapPixelWidth] = discovered; currentVisibilityBlock[index + mapPixelWidth] = discovered; } } } } } return(didUpdate); }