/// <summary> /// Calculates FOV with the given center point and radius (of shape circle), and stores the result in the FOV property. All tiles that are in the resulting FOV /// are marked as explored. /// </summary> /// <param name="x">X-value of the center point for the new FOV to calculate.</param> /// <param name="y">Y-value of the center point for the new FOV to calculate.</param> /// <param name="radius">The radius of the FOV. Defaults to infinite.</param> public virtual void CalculateFOV(int x, int y, double radius = double.MaxValue) { _fov.Calculate(x, y, radius); foreach (var pos in _fov.NewlySeen) { Explored[pos] = true; } }
/// <summary> /// Calculates FOV with the given center point and radius, and stores the result in the <see cref="FOV"/> property. All tiles that are in the /// resulting FOV are marked as explored. Other non-angle-based overloads call this one, so if you need to override functionality, override /// this function. /// </summary> /// <param name="x">X-value of the center point for the new FOV to calculate.</param> /// <param name="y">Y-value of the center point for the new FOV to calculate.</param> /// <param name="radius">The radius of the FOV. Defaults to infinite.</param> /// <param name="radiusShape">The shape of the FOV to calculate. Can be specified as either <see cref="Distance"/> or <see cref="Radius"/> types /// (they are implicitly convertible).</param> public virtual void CalculateFOV(int x, int y, double radius, Distance radiusShape) { _fov.Calculate(x, y, radius, radiusShape); foreach (var pos in _fov.NewlySeen) { Explored[pos] = true; } }
public void SetEmittingCell_AdjacentCells_UpdatedCorrectly() { var cell = SetLightCell(10, 10, 4); var area = new List <EmberCell>(); GetRadiusNeighbors(cell, cell.LightProperties.LightRadius, area); var points = area.ToDictionary(a => a.Position, a => a); var fov = new FOV(_grid.FieldOfView); fov.Calculate(cell.Position, cell.LightProperties.LightRadius); for (int x = 0; x < _grid.GridSizeX; x++) { for (int y = 0; y < _grid.GridSizeY; y++) { if (fov.BooleanFOV[x, y]) { Assert.IsTrue(points.TryGetValue(new Point(x, y), out EmberCell value)); Assert.IsTrue(value.LightProperties.Brightness > 0f); } } } }
static void TestFOV() { using (FOV f = new FOV(new Size(10, 10))) { // . # . // # . . // . . . f.SetCell(new Point(0, 0), true, true); f.SetCell(new Point(1, 0), false, false); f.SetCell(new Point(2, 0), true, true); f.SetCell(new Point(0, 1), false, false); f.SetCell(new Point(1, 1), true, true); f.SetCell(new Point(2, 1), true, true); f.SetCell(new Point(0, 2), true, true); f.SetCell(new Point(1, 2), true, true); f.SetCell(new Point(2, 2), true, true); Console.WriteLine(f.GetCellTransparent(new Point(2, 2))); Console.WriteLine(f.GetCellWalkable(new Point(2, 2))); f.Calculate(new Point(0, 0), 5, true, FovAlgorithm.Shadow); Console.WriteLine(f.IsInView(new Point(2, 0))); Console.WriteLine(f.IsInView(new Point(0, 2))); Console.WriteLine(f.IsInView(new Point(2, 2))); } }
private void SetLightSource(EmberCell cell) { if (cell.LightProperties.EmitsLight) { var fov = new FOV(GridManager.Grid.FieldOfView); fov.Calculate(cell.Position, cell.LightProperties.LightRadius); var toChangeCells = new List <(EmberCell, float)>(); for (int x = 0; x < GridManager.Grid.GridSizeX; x++) { for (int y = 0; y < GridManager.Grid.GridSizeY; y++) { // If cell is in the field of view of the object if (fov.BooleanFOV[x, y]) { var pos = new Point(x, y); var distanceOfCenter = cell.Position.SquaredDistance(pos); var cellToAdd = GridManager.Grid.GetCell(x, y); if (!cellToAdd.LightProperties.EmitsLight) { if (cellToAdd.LightProperties.LightSources == null) { cellToAdd.LightProperties.LightSources = new List <EmberCell>(); } cellToAdd.LightProperties.LightSources.RemoveAll(a => a.Position == cell.Position); cellToAdd.LightProperties.LightSources.Add(cell); } toChangeCells.Add((cellToAdd, distanceOfCenter)); } } } HandleBrightnessLayers(toChangeCells, cell); } }
public void FOVCurrentHash() { var map = BoxResMap(50, 50); var fovMap = new LambdaTranslationMap <double, bool>(map, d => d >= 1.0 ? false : true); var fov = new FOV(fovMap); fov.Calculate(20, 20, 10); // Inefficient copy but fine for testing HashSet <Coord> currentFov = new HashSet <Coord>(fov.CurrentFOV); for (int x = 0; x < map.Width; x++) { for (int y = 0; y < map.Height; y++) { if (fov[x, y] > 0.0) { Assert.AreEqual(true, currentFov.Contains((x, y))); } else { Assert.AreEqual(false, currentFov.Contains((x, y))); } } } }
public void FOVCurrentHash() { var map = new BoxResMap(50, 50); var fov = new FOV(map); fov.Calculate(20, 20, 10); // Inefficient copy but fine for testing HashSet <Coord> currentFov = new HashSet <Coord>(fov.CurrentFOV); for (int x = 0; x < map.Width; x++) { for (int y = 0; y < map.Height; y++) { if (fov[x, y] > 0.0) { Assert.AreEqual(true, currentFov.Contains(Coord.Get(x, y))); } else { Assert.AreEqual(false, currentFov.Contains(Coord.Get(x, y))); } } } }
private void SearchForTarget(Actor actor) { FOV fov = new FOV(actor.Parent.CurrentMap.TransparencyView); fov.Calculate(actor.Parent.Position); foreach (Coord pos in fov.CurrentFOV) { if (!(actor.Parent.CurrentMap.GetObject(pos).GetComponent <Actor>() is Actor otherActor)) { continue; } if (actor.Being.Alignment.GetRelation(otherActor.Being.Alignment) != AlignmentRelation.Enemy) { continue; } _target = otherActor; _targetLastSeen = otherActor.Parent.Position; return; } _target = null; }
public void FOVTest() { var testMap = new ArrayMap <bool>(5, 5); foreach (Coord coord in testMap.Positions()) { testMap[coord] = true; } var centre = new Coord(2, 2); foreach (Coord coord in new RadiusAreaProvider(centre, 2, Radius.CIRCLE).CalculatePositions()) { testMap[coord] = false; } foreach (Coord coord in new RadiusAreaProvider(centre, 1, Distance.EUCLIDEAN).CalculatePositions()) { testMap[coord] = true; } var resMap = new ArrayMap <bool>(5, 5); foreach (Coord coord in testMap.Positions()) { resMap[coord] = testMap[coord]; } var FOV = new FOV(resMap); FOV.Calculate(centre, 1, Distance.EUCLIDEAN); Coord[] calculated = FOV.CurrentFOV.OrderBy(p => p.X).ThenBy(p => p.Y).ToArray(); Assert.True(calculated.SequenceEqual(new[] { new Coord(1, 2), new Coord(2, 1), new Coord(2, 2), new Coord(2, 3), new Coord(3, 2) })); }
public void InitializeFOV(Dungeon dungeon, int level) { int mapWidth = dungeon.dungeon[level].Width; int mapHeight = dungeon.dungeon[level].Height; fovMap = new ArrayMap <bool>(mapWidth, mapHeight); ArrayMap <Tile> map = dungeon.dungeon[level].GetLevel(); for (int x = 0; x < mapWidth; x++) { for (int y = 0; y < mapHeight; y++) { if (map[x, y].IsSolid() == true) { fovMap[x, y] = false; //set to false if it does block FOV } else { fovMap[x, y] = true; } } } fov = new FOV(fovMap); fov.Calculate(new Point(Position.X, Position.Y), 12); }
public void RemoveMultipleEmittingCells_AdjacentCells_UpdatedCorrectly() { var positions = new[] { new Point(10, 10), new Point(13, 10), new Point(11, 13) }; var radiuses = new int[] { 4, 6, 4 }; for (int i = 0; i < positions.Length; i++) { SetLightCell(positions[i].X, positions[i].Y, radiuses[i]); UnsetLightCell(positions[i].X, positions[i].Y); } for (int i = 0; i < positions.Length; i++) { var fov = new FOV(_grid.FieldOfView); fov.Calculate(positions[i], radiuses[i]); for (int x = 0; x < _grid.GridSizeX; x++) { for (int y = 0; y < _grid.GridSizeY; y++) { if (fov.BooleanFOV[x, y]) { Assert.IsTrue(_grid.GetCell(x, y).LightProperties.Brightness == 0f); } } } } }
public void RemoveMultipleEmittingCells_AdjacentCells_UpdatedCorrectly() { var cells = new[] { SetLightCell(10, 10, 4), SetLightCell(13, 10, 6), SetLightCell(11, 13, 4) }; cells = new[] { UnsetLightCell(10, 10), UnsetLightCell(13, 10), UnsetLightCell(11, 13) }; var radiuses = new int[] { 4, 6, 4 }; for (int i = 0; i < cells.Length; i++) { var area = new List <EmberCell>(); GetRadiusNeighbors(cells[i], radiuses[i], area); var points = area.ToDictionary(a => a.Position, a => a); var fov = new FOV(_grid.FieldOfView); fov.Calculate(cells[i].Position, radiuses[i]); for (int x = 0; x < _grid.GridSizeX; x++) { for (int y = 0; y < _grid.GridSizeY; y++) { if (fov.BooleanFOV[x, y]) { Assert.IsTrue(points.TryGetValue(new Point(x, y), out EmberCell value)); Assert.IsTrue(value.LightProperties.Brightness == 0f); } } } } }
/// <summary> /// Calculates the FieldOfView component /// </summary> public void Calculate() { if (_fieldOfView == null) { return; } _fieldOfView.Calculate(_actor.Position, _actor.FieldOfViewRadius, _distanceCalculationMethod); }
public void RemoveOneEmittingCell_FromManyEmittingCells_AdjacentCells_UpdatedCorrectly() { var setCells = new[] { SetLightCell(10, 10, 4), SetLightCell(13, 10, 6), SetLightCell(11, 13, 4) }; var unsetCells = new[] { UnsetLightCell(13, 10) }; foreach (var cell in setCells.Except(unsetCells)) { var area = new List <EmberCell>(); GetRadiusNeighbors(cell, cell.LightProperties.LightRadius, area); var points = area.ToDictionary(a => a.Position, a => a); var fov = new FOV(_grid.FieldOfView); fov.Calculate(cell.Position, cell.LightProperties.LightRadius); for (int x = 0; x < _grid.GridSizeX; x++) { for (int y = 0; y < _grid.GridSizeY; y++) { if (fov.BooleanFOV[x, y]) { Assert.IsTrue(points.TryGetValue(new Point(x, y), out EmberCell value)); Assert.IsTrue(value.LightProperties.Brightness > 0f); } } } } // Check unset cell for light sources = null has 0 brightness var area2 = new List <EmberCell>(); GetRadiusNeighbors(unsetCells[0], unsetCells[0].LightProperties.LightRadius, area2); var points2 = area2.ToDictionary(a => a.Position, a => a); var fov2 = new FOV(_grid.FieldOfView); fov2.Calculate(unsetCells[0].Position, unsetCells[0].LightProperties.LightRadius); bool someCellsAreUnset = false; for (int x = 0; x < _grid.GridSizeX; x++) { for (int y = 0; y < _grid.GridSizeY; y++) { if (fov2.BooleanFOV[x, y]) { Assert.IsTrue(points2.TryGetValue(new Point(x, y), out EmberCell value)); if (value.LightProperties.LightSources == null && !value.LightProperties.EmitsLight) { someCellsAreUnset = true; Assert.IsTrue(value.LightProperties.Brightness == 0f); } } } } Assert.IsTrue(someCellsAreUnset); }
public static TimeSpan TimeForSingleLightSourceFOV(int mapWidth, int mapHeight, int lightRadius, int iterations) { Stopwatch s = new Stopwatch(); var map = rectangleMap(mapWidth, mapHeight); var fov = new FOV(map); // Warm-up for processor, stabilizes cache performance. Also makes it a fair test against // fov since we have to do this to force the first memory allocation fov.Calculate(5, 6, lightRadius, Radius.CIRCLE); // Calculate and test s.Start(); for (int i = 0; i < iterations; i++) { fov.Calculate(5, 6, lightRadius, Radius.CIRCLE); } s.Stop(); return(s.Elapsed); }
public void FOVNewlySeenUnseen() { var map = BoxResMap(50, 50); var fovMap = new LambdaTranslationMap <double, bool>(map, d => d >= 1.0 ? false : true); var fov = new FOV(fovMap); fov.Calculate(20, 20, 10, Radius.SQUARE); var prevFov = new HashSet <Coord>(fov.CurrentFOV); fov.Calculate(19, 19, 10, Radius.SQUARE); var curFov = new HashSet <Coord>(fov.CurrentFOV); var newlySeen = new HashSet <Coord>(fov.NewlySeen); var newlyUnseen = new HashSet <Coord>(fov.NewlyUnseen); foreach (var pos in prevFov) { if (!curFov.Contains(pos)) { Assert.AreEqual(true, newlyUnseen.Contains(pos)); } else { Assert.AreEqual(false, newlyUnseen.Contains(pos)); } } foreach (var pos in curFov) { if (!prevFov.Contains(pos)) { Assert.AreEqual(true, newlySeen.Contains(pos)); } else { Assert.AreEqual(false, newlySeen.Contains(pos)); } } }
public static long MemorySingleLightSourceFOV(int mapWidth, int mapHeight, int lightRadius) { FOV fov; long startingMem, endingMem; ArrayMap <double> map = rectangleMap(mapWidth, mapHeight); // Start mem test startingMem = GC.GetTotalMemory(true); fov = new FOV(map); fov.Calculate(5, 6, lightRadius, Radius.CIRCLE); // Must calculate to force allocations endingMem = GC.GetTotalMemory(true); return(endingMem - startingMem); }
public void ManualPrintFOV() { var map = new ArrayMap <bool>(10, 10); QuickGenerators.GenerateRectangleMap(map); FOV myFov = new FOV(map); myFov.Calculate(5, 5, 3); Console.WriteLine(myFov); Console.WriteLine(); Console.WriteLine(myFov.ToString(3)); }
public void RemoveOneEmittingCell_FromManyEmittingCells_AdjacentCells_UpdatedCorrectly() { var setCells = new[] { SetLightCell(10, 10, 4), SetLightCell(13, 10, 6), SetLightCell(11, 13, 4) }; var unsetCells = new[] { UnsetLightCell(13, 10) }; foreach (var cell in setCells.Except(unsetCells)) { var fov = new FOV(_grid.FieldOfView); fov.Calculate(cell.Position, cell.LightProperties.LightRadius); for (int x = 0; x < _grid.GridSizeX; x++) { for (int y = 0; y < _grid.GridSizeY; y++) { if (fov.BooleanFOV[x, y]) { Assert.IsTrue(_grid.GetCell(x, y).LightProperties.Brightness > 0f); } } } } // Check unset cell for light sources = null has 0 brightness var fov2 = new FOV(_grid.FieldOfView); fov2.Calculate(unsetCells[0].Position, unsetCells[0].LightProperties.LightRadius); bool someCellsAreUnset = false; for (int x = 0; x < _grid.GridSizeX; x++) { for (int y = 0; y < _grid.GridSizeY; y++) { if (fov2.BooleanFOV[x, y]) { var value = _grid.GetCell(x, y); if (value.LightProperties.LightSources == null && !value.LightProperties.EmitsLight) { someCellsAreUnset = true; Assert.IsTrue(value.LightProperties.Brightness == 0f); } } } } Assert.IsTrue(someCellsAreUnset); }
public void Act(Monster monster) { var dungeonMap = GameController.DungeonMap; var player = GameController.Instance.Player; var fov = new FOV(dungeonMap.Map.TransparencyView); if (!monster.TurnsAlerted.HasValue) { fov.Calculate(monster.Position, monster.FOVRadius, Radius.DIAMOND); if (fov[player.Position] > 0) { monster.TurnsAlerted = 1; } } if (!monster.TurnsAlerted.HasValue) { return; } var path = dungeonMap.Map.AStar.ShortestPath(monster.Position, player.Position); if (path == null) { return; } //var inputAction = new BasicMoveAndAttackAction(monster); var moveDir = Direction.GetDirection(monster.Position, path.GetStep(0)); //inputAction.Run(moveDir); monster.TurnsAlerted++; if (monster.TurnsAlerted > 15) { monster.TurnsAlerted = null; } var moveCommand = new MoveCommand(monster, moveDir); //moveCommand.OnSuccessMethod = OnMoveSuccess; GameController.CommandManager.PushAndRun(moveCommand); }
public void FOVBooleanOutput() { var map = new ArrayMap <bool>(10, 10); QuickGenerators.GenerateRectangleMap(map); var fov = new FOV(map); fov.Calculate(5, 5, 3); Console.WriteLine("FOV for reference:"); Console.WriteLine(fov.ToString(2)); foreach (var pos in fov.Positions()) { bool inFOV = fov[pos] != 0.0; Assert.AreEqual(inFOV, fov.BooleanFOV[pos]); } }
public void SetEmittingCell_AdjacentCells_UpdatedCorrectly() { var cell = SetLightCell(10, 10, 4); var fov = new FOV(_grid.FieldOfView); fov.Calculate(cell.Position, cell.LightProperties.LightRadius); for (int x = 0; x < _grid.GridSizeX; x++) { for (int y = 0; y < _grid.GridSizeY; y++) { if (fov.BooleanFOV[x, y]) { Assert.IsTrue(_grid.GetCell(x, y).LightProperties.Brightness > 0f); } } } }
public void RemoveEmittingCell_AdjacentCells_UpdatedCorrectly() { SetLightCell(10, 10, 4); UnsetLightCell(10, 10); var fov = new FOV(_grid.FieldOfView); fov.Calculate(new Point(10, 10), 4); for (int x = 0; x < _grid.GridSizeX; x++) { for (int y = 0; y < _grid.GridSizeY; y++) { if (fov.BooleanFOV[x, y]) { Assert.IsTrue(_grid.GetCell(x, y).LightProperties.Brightness == 0f); } } } }
public void UpdateFOV(ScrollingConsole console, Coord position) { FOV.Calculate(position); SpaceMap.SeeCoords(FOV.NewlySeen); // Cells outside of FOV are gray on black, // with only the glyph of the terrain showing. var unseenCell = new Cell(Color.DarkGray, Color.Black, ' '); foreach (var location in FOV.NewlyUnseen.Where(c => console.ViewPort.Contains(c))) { // Wiping the effect restores the original cell colors, // so it must happen before setting OOV appearance EffectsManager.SetEffect(console.Cells[location.Y * Width + location.X], null); unseenCell.Glyph = SpaceMap.GetItem(location).Terrain.Cell.Glyph; console.SetCellAppearance(location.X, location.Y, unseenCell); } UpdateViewOfCoords(console, FOV.NewlySeen); }
public void CircleRadius() { var testResMap = new EmptyResMap(17, 17); var myFov = new FOV(testResMap); var myLighting = new SenseMap(testResMap); // Circle at 8, 8; radius 7 myLighting.AddSenseSource(new SenseSource(SourceType.SHADOW, Coord.Get(8, 8), 7, Radius.CIRCLE)); myFov.Calculate(8, 8, 7, Radius.CIRCLE); myLighting.Calculate(); for (int x = 0; x < testResMap.Width; x++) { for (int y = 0; y < testResMap.Height; y++) { Console.Write(myLighting[x, y].ToString("0.00") + " "); Assert.AreEqual(myFov[x, y], myLighting[x, y]); // Both got the same results } Console.WriteLine(); } }
public void EqualLargeMap() { var testResMap = TestResMap(17, 17); var testFOVMap = new LambdaTranslationMap <double, bool>(testResMap, d => d >= 1.0 ? false : true); testResMap[8, 8] = 0.0; // Make sure start is free var myFov = new FOV(testFOVMap); var myLighting = new SenseMap(testResMap); // Circle at 8, 8; radius 7 myLighting.AddSenseSource(new SenseSource(SourceType.SHADOW, (8, 8), 7, Radius.CIRCLE)); myFov.Calculate(8, 8, 7, Radius.CIRCLE); myLighting.Calculate(); Console.WriteLine("LOS: "); for (int x = 0; x < testResMap.Width; x++) { for (int y = 0; y < testResMap.Height; y++) { Console.Write($"{myFov[x, y].ToString("N2")}\t"); } Console.WriteLine(); } Console.WriteLine("\nLighting:"); for (int x = 0; x < testResMap.Width; x++) { for (int y = 0; y < testResMap.Height; y++) { Console.Write($"{myLighting[x, y].ToString("N2")}\t"); } Console.WriteLine(); } for (int x = 0; x < testResMap.Width; x++) { for (int y = 0; y < testResMap.Height; y++) { System.Console.WriteLine($"We have ({x},{y}) fov {myFov[x, y]}, lighting {myLighting[(x, y)]}"); Assert.AreEqual(myFov[x, y], myLighting[x, y]); // Both got the same results } } }
private bool testLOS(Radius shape) { var map = rectResMap(MAP_WIDTH, MAP_HEIGHT); // Start out at false bool[,] radiusMap = new bool[MAP_WIDTH, MAP_HEIGHT]; bool[,] losMap = new bool[MAP_WIDTH, MAP_HEIGHT]; var los = new FOV(map); los.Calculate(CENTER.X, CENTER.Y, RADIUS_LEGNTH, shape); for (int x = 0; x < MAP_WIDTH; x++) { for (int y = 0; y < MAP_HEIGHT; y++) { if (los[x, y] > 0) { losMap[x, y] = true; } } } var radArea = new RadiusAreaProvider(CENTER, RADIUS_LEGNTH, shape); foreach (var pos in radArea.CalculatePositions()) { radiusMap[pos.X, pos.Y] = true; } Console.WriteLine("Radius Shape: "); printArray(radiusMap); Console.WriteLine("LOS Shape: "); printArray(losMap); return(equivalentArrays(radiusMap, losMap)); }
private void ModifyLight(Light light, bool add) { //HashSet<Coord> litSpaces = new HashSet<Coord>(); if (!_transparencyMap.Contains(light.Pos)) { return; } FOV litFov = new FOV(_transparencyMap); litFov.Calculate(light.Pos, light.Range); IEnumerable <Coord> litSpaces = litFov.CurrentFOV; foreach (Coord litSpace in litSpaces) { //double falloff = litFov[litSpace]; double dist = Distance.EUCLIDEAN.Calculate(litSpace, light.Pos); double sqrDist = Math.Max(dist, .1);; //Math.Max(dist * dist, .1); if (!map.Contains(litSpace)) { continue; } if (add) { map[litSpace].Add(Brightness(light.Color, (int)(light.Brightness - sqrDist))); } else { map[litSpace].Subtract(Brightness(light.Color, (int)(light.Brightness - sqrDist))); } } }
public virtual void UpdateFov() { fovmap.Calculate(Position.X, Position.Y, VisionRange, Distance.EUCLIDEAN); }
public void AdjustLightLevels(EmberCell newCell, EmberCell oldCell) { if (oldCell.LightProperties.EmitsLight == newCell.LightProperties.EmitsLight) { return; } var fov = new FOV(GridManager.Grid.FieldOfView); if (!newCell.LightProperties.EmitsLight) { fov.Calculate(newCell.Position, oldCell.LightProperties.LightRadius); var toChangeCells = new List <EmberCell>(); for (int x = 0; x < GridManager.Grid.GridSizeX; x++) { for (int y = 0; y < GridManager.Grid.GridSizeY; y++) { // If cell is in the field of view of the object if (fov.BooleanFOV[x, y]) { var pos = new Point(x, y); var cellToAdd = newCell.Position == pos ? newCell : GridManager.Grid.GetCell(x, y); cellToAdd.LightProperties.LightSources.Remove(newCell); toChangeCells.Add(cellToAdd); } } } foreach (var cell in toChangeCells) { if (cell.LightProperties.LightSources.Any()) { continue; } cell.LightProperties.LightSources = null; cell.LightProperties.Brightness = 0f; cell.LightProperties.LightRadius = 0; cell.LightProperties.LightColor = default; GridManager.Grid.SetCellColors(cell, Game.Player, cell.CellProperties.NormalForeground, cell.CellProperties.ForegroundFov); if (cell != newCell) // We don't need an infinite loop here :) It's passed by reference. { GridManager.Grid.SetCell(cell); } } return; } var cells = new List <(EmberCell, float)>(); fov.Calculate(newCell.Position, newCell.LightProperties.LightRadius); for (int x = 0; x < GridManager.Grid.GridSizeX; x++) { for (int y = 0; y < GridManager.Grid.GridSizeY; y++) { // If cell is in the field of view of the object if (fov.BooleanFOV[x, y]) { var pos = new Point(x, y); var distanceOfCenter = newCell.Position.SquaredDistance(pos); var cellToAdd = newCell.Position == pos ? newCell : GridManager.Grid.GetCell(x, y); if (cellToAdd.LightProperties.LightSources == null) { cellToAdd.LightProperties.LightSources = new List <EmberCell>(); } cellToAdd.LightProperties.LightSources.Add(newCell); cells.Add((cellToAdd, distanceOfCenter)); } } } var orderedCells = cells.OrderBy(a => a.Item2); var layers = orderedCells.Select(a => a.Item2).Distinct().ToList(); var brightnessLayers = CalculateBrightnessLayers(newCell, layers); foreach (var lightedCell in orderedCells) { var brightness = brightnessLayers[lightedCell.Item2]; if (lightedCell.Item1.LightProperties.Brightness < brightness) { lightedCell.Item1.LightProperties.Brightness = brightness; } GridManager.Grid.SetCellColors(lightedCell.Item1, Game.Player, newCell.LightProperties.LightColor, Color.Lerp(newCell.LightProperties.LightColor, Color.Black, .5f)); if (lightedCell.Item1 != newCell) // We don't need an infinite loop here :) It's passed by reference. { GridManager.Grid.SetCell(lightedCell.Item1); } } }