Exemple #1
0
        /// <summary>
        /// Generate a Dijkstra Map to aid AI navigation through this map
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="map"></param>
        /// <param name="startingValue"></param>
        /// <param name="targetCondition"></param>
        /// <param name="passCondition"></param>
        /// <param name="blockedValue"></param>
        /// <returns></returns>
        public static ICellMap <int> GenerateDijkstraMap <T>(this ICellMap <T> map, Func <T, bool> targetCondition, Func <T, bool> passCondition,
                                                             int startingValue = 1000000, int blockedValue = -1)
        {
            ICellMap <int> dMap = map.SpawnNewGrid <int>();

            dMap.SetAll(startingValue);
            for (int i = 0; i < map.CellCount; i++)
            {
                T cellValue = map[i];
                if (targetCondition(cellValue))
                {
                    dMap[i] = 0;
                }
                else if (!passCondition(cellValue))
                {
                    dMap[i] = blockedValue;
                }
            }

            while (IterateDijkstraMap(dMap, blockedValue))
            {
            }

            return(dMap);
        }
Exemple #2
0
        /// <summary>
        /// Run one iteration of a dijkstra map update.  Each cell is set to the lowest
        /// adjacent value - 1.
        /// </summary>
        /// <param name="dMap"></param>
        /// <param name="blockedValue"></param>
        /// <returns></returns>
        public static bool IterateDijkstraMap(this ICellMap <int> dMap, int blockedValue = -1)
        {
            bool changed = false;

            for (int i = 0; i < dMap.CellCount; i++)
            {
                int cellValue = dMap[i];
                if (cellValue != blockedValue)
                {
                    int lowestValue = cellValue;
                    for (int ai = 0; ai <= dMap.AdjacencyCount(i); ai++)
                    {
                        int adjacentCellIndex = dMap.AdjacentCellIndex(i, ai);
                        if (dMap.Exists(adjacentCellIndex))
                        {
                            int adjacentValue = dMap[adjacentCellIndex];
                            if (adjacentValue < lowestValue)
                            {
                                lowestValue = adjacentValue;
                            }
                        }
                    }
                    if (lowestValue < cellValue - 1)
                    {
                        dMap[i] = lowestValue + 1;
                        changed = true;
                    }
                }
            }
            return(changed);
        }
Exemple #3
0
 /// <summary>
 /// Set all cells in this map to the same value.
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="map"></param>
 /// <param name="value"></param>
 public static void SetAll <T>(this ICellMap <T> map, T value)
 {
     for (int i = 0; i < map.CellCount; i++)
     {
         map[i] = value;
     }
 }
Exemple #4
0
        private CellCluster[,] CreateClusters(ICellMap map, int clusterSize)
        {
            int matrixWidth  = (int)Math.Ceiling((double)map.Width / clusterSize);
            int matrixHeight = (int)Math.Ceiling((double)map.Height / clusterSize);

            CellCluster[,] clusterMatrix = new CellCluster[matrixWidth, matrixHeight];

            int currentX = 0;

            for (int cx = 0; cx < matrixWidth; cx++)
            {
                int xBorderDelta = map.Width - currentX;
                int actualWidth  = xBorderDelta >= clusterSize ? clusterSize : xBorderDelta;
                int currentY     = 0;
                for (int cy = 0; cy < matrixHeight; cy++)
                {
                    int yBorderDelta = map.Height - currentY;
                    int actualHeight = yBorderDelta >= clusterSize ? clusterSize : yBorderDelta;

                    CellCluster cluster = new CellCluster(new Vector2Int(cx, cy))
                    {
                        Width      = actualWidth,
                        Height     = actualHeight,
                        LeftBottom = new Vector2Int(currentX, currentY),
                        Map        = map
                    };
                    clusterMatrix[cx, cy] = cluster;
                    currentY += actualHeight;
                }

                currentX += actualWidth;
            }

            return(clusterMatrix);
        }
Exemple #5
0
 /// <summary>
 /// Set a cell in this map.  This will back-register the map and index
 /// with the cell itself.
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="map"></param>
 /// <param name="index"></param>
 /// <param name="cell"></param>
 public static void SetCell <T>(this ICellMap <T> map, int index, T cell)
     where T : IMapCell
 {
     map[index] = cell;
     cell.Index = index;
     cell.Map   = map;
 }
Exemple #6
0
 public void UpdateGraph(ICellMap map, IEnumerable <ICellFragment> obstacles, HierarchicalMap graph, NeighbourMode neighbourMode)
 {
     foreach (var obstacle in obstacles)
     {
         UpdateGraph(map, obstacle, graph, neighbourMode);
     }
 }
Exemple #7
0
 public void Initialize(ICellMap mapBase, int clusterSize)
 {
     _mapBase        = mapBase;
     _layeredCellMap = new LayeredCellMap(_mapBase);
     ClusterSizeZero = clusterSize;
     PreBuildGraph(_layeredCellMap);
     _isInitialized = true;
 }
Exemple #8
0
 /// <summary>
 /// Populate this map with cells
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="map"></param>
 public static void InitialiseCells <T>(this ICellMap <T> map)
     where T : IMapCell, new()
 {
     for (int i = 0; i < map.CellCount; i++)
     {
         T cell = new T();
         map.SetCell(i, cell);
     }
 }
Exemple #9
0
        public HierarchicalMap GenerateMap(ICellMap cellMap, NeighbourMode neighbourMode, params int[] clusterSizes)
        {
            if (clusterSizes.Length == 1)
            {
                return(GenerateTwoLevelMap(cellMap, neighbourMode, clusterSizes[0]));
            }

            throw new NotImplementedException();
        }
Exemple #10
0
        static void Main(string[] args)
        {
            Console.BufferWidth  = 300;
            Console.BufferHeight = 240;
            Console.WindowWidth  = 180;

            Console.WriteLine("Press any key to start...");
            Console.ReadKey();

            FileStream mapFileStream = File.Open("Maps/vadim_maze.cmap", FileMode.Open, FileAccess.Read);

            ConsoleMap map = ConsoleMapGenerator.FromText(mapFileStream, 'S', 'E', 'X', '.');

            _map = map;

            InitArrays(2);

            Vector2Int start = map.DefaultStart;
            Vector2Int stop  = map.DefaultStop;

            _start = start;
            _stop  = stop;
            Vector2Int scale   = new Vector2Int(4, 2);
            int        spacing = 4;


            InitConsoleDrawer(map, scale, spacing, start, stop, 0);
            InitConsoleDrawer(map, scale, spacing, start, stop, 1);

            Console.SetCursorPosition(0, map.Height * scale.Y);

            AStarAlgorithm aStarTest = new AStarAlgorithm();
            var            path      = aStarTest.GetPath(_map, start, stop, NeighbourMode.SideOnly);

            if (path != null)
            {
                Console.WriteLine("Path was found");
                DrawPath(path, 0);
            }

            _contestants[0] = new BestFirstSearch();
            _contestants[0].OnCellViewedEvent += OnCellUpdated;

            _contestants[1] = new AStarAlgorithm();
            _contestants[1].OnCellViewedEvent += OnCellUpdated;

            StartPathFinder(0);
            StartPathFinder(1);

            while (_runningTasks > 0)
            {
                Thread.Sleep(100);
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
Exemple #11
0
        private HierarchicalMap GenerateTwoLevelMap(ICellMap cellMap, NeighbourMode neighbourMode,
                                                    int levelZeroClusterSize)
        {
            CellCluster[,] clusterMatrix = CreateClusters(cellMap, levelZeroClusterSize);
            GeneratedClusters            = clusterMatrix;

            HierarchicalMap levelOneMap = new HierarchicalMap(levelZeroClusterSize, levelZeroClusterSize);

            for (int i = 0; i < clusterMatrix.GetLength(0); i++)
            {
                for (int j = 0; j < clusterMatrix.GetLength(1); j++)
                {
                    CellCluster currentCluster = clusterMatrix[i, j];

                    int prevI = i - 1;
                    int prevJ = j - 1;
                    int nextJ = j + 1;
                    if (prevI >= 0)
                    {
                        CellCluster neighbourCluster = clusterMatrix[prevI, j];
                        ProceedNeighbourClusters(currentCluster, neighbourCluster, levelOneMap);
                    }

                    if (prevJ >= 0)
                    {
                        CellCluster neighbourCluster = clusterMatrix[i, prevJ];
                        ProceedNeighbourClusters(currentCluster, neighbourCluster, levelOneMap);
                    }

                    if (prevJ >= 0 && prevI >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals)
                    {
                        CellCluster neighbourCluster = clusterMatrix[prevI, prevJ];
                        ProceedNeighbourClusters(currentCluster, neighbourCluster, levelOneMap);
                    }

                    if (nextJ < cellMap.Height && prevI >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals)
                    {
                        CellCluster neighbourCluster = clusterMatrix[prevI, nextJ];
                        ProceedNeighbourClusters(currentCluster, neighbourCluster, levelOneMap);
                    }
                }
            }

            for (int i = 0; i < clusterMatrix.GetLength(0); i++)
            {
                for (int j = 0; j < clusterMatrix.GetLength(1); j++)
                {
                    _currentCellCluster = clusterMatrix[i, j];
                    clusterMatrix[i, j].CalculatePaths(neighbourMode, OnCellClusterCellViewed);
                }
            }

            levelOneMap.ZeroLevelClusters = clusterMatrix;

            return(levelOneMap);
        }
Exemple #12
0
 private void ShowCellMapDrawerForm(CellMapDrawerForm form, ICellMap map, IList <Vector2Int> path)
 {
     if (InvokeRequired)
     {
         BeginInvoke(new Action <CellMapDrawerForm, ICellMap, IList <Vector2Int> >(ShowCellMapDrawerForm), form, map, path);
         return;
     }
     Debug.WriteLine($"CellMapDrawerForm showed on thread {Thread.CurrentThread.ManagedThreadId}");
     form.ShowMap(map, path);
 }
Exemple #13
0
        public static WeightedGraph <double> GetWeightedGraph(ICellMap map, NeighbourMode neighbourMode)
        {
            WeightedGraphNode <double>[,] nodes = new WeightedGraphNode <double> [map.Width, map.Height];

            for (int x = 0; x < map.Width; x++)
            {
                for (int y = 0; y < map.Height; y++)
                {
                    if (map.IsPassable(x, y))
                    {
                        WeightedGraphNode <double> connectionNode;
                        WeightedGraphNode <double> currentNode = new WeightedGraphNode <double>(Double.PositiveInfinity);
                        nodes[x, y]          = currentNode;
                        currentNode.Position = new Vector2Int(x, y);

                        int prevX = x - 1;
                        int prevY = y - 1;
                        int nextY = y + 1;

                        if (prevX >= 0)
                        {
                            connectionNode = nodes[prevX, y];
                            ConnectNodes(currentNode, connectionNode, 1);
                        }
                        if (prevY >= 0)
                        {
                            connectionNode = nodes[x, prevY];
                            ConnectNodes(currentNode, connectionNode, 1);
                        }

                        if (prevX >= 0 && prevY >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals)
                        {
                            connectionNode = nodes[prevX, prevY];
                            ConnectNodes(currentNode, connectionNode, Sqrt2);
                        }

                        if (nextY < map.Height && prevX >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals)
                        {
                            connectionNode = nodes[prevX, nextY];
                            ConnectNodes(currentNode, connectionNode, Sqrt2);
                        }
                    }
                    else
                    {
                        nodes[x, y] = null;
                    }
                }
            }

            WeightedGraph <double> weightedGraph = new WeightedGraph <double>(nodes, Double.PositiveInfinity);

            return(weightedGraph);

            ;
        }
Exemple #14
0
 /// <summary>
 /// Get the cell adjacent to the cell with the specified
 /// index in the specified direction.
 /// </summary>
 /// <param name="cellIndex">The index of the starting cell</param>
 /// <param name="direction">The direction of the cell to retrieve</param>
 /// <returns></returns>
 public static T AdjacentCell <T>(this ICellMap <T> map, int cellIndex, Vector direction)
 {
     if (map.Exists(cellIndex))
     {
         int i = map.AdjacentCellIndex(cellIndex, direction);
         if (map.Exists(i))
         {
             return(map[i]);
         }
     }
     return(default(T));
 }
Exemple #15
0
        private void PreBuildGraph(ICellMap map)
        {
            Stopwatch sw = new Stopwatch();

            Debug.WriteLine("Hierarchical graph construction started");
            sw.Start();
            HierarchicalMapGenerator generator = new HierarchicalMapGenerator();

            HierarchicalGraph = generator.GenerateMap(map, NeighbourMode.SideOnly, ClusterSizeZero);
            sw.Stop();
            Debug.WriteLine($"Hierarchical graph construction finished in {sw.Elapsed}");
        }
Exemple #16
0
 /// <summary>
 /// Get the specified adjacent cell to the specified cell
 /// </summary>
 /// <param name="cellIndex">The index of the starting cell</param>
 /// <param name="adjacencyIndex">The adjacency index of the cell to retrieve</param>
 /// <returns></returns>
 public static T AdjacentCell <T>(this ICellMap <T> map, int cellIndex, int adjacencyIndex)
 {
     if (map.Exists(cellIndex))
     {
         int i = map.AdjacentCellIndex(cellIndex, adjacencyIndex);
         if (map.Exists(i))
         {
             return(map[i]);
         }
     }
     return(default(T));
 }
Exemple #17
0
        public void ShowMap(ICellMap cellMap)
        {
            _cellMap = cellMap;
            _stage   = 0;

            DrawCellMatrix();

            _pictureBoxGraphics = PictureBox.CreateGraphics();

            AddAlgorithms();

            Show();
        }
Exemple #18
0
        public IList <Vector2Int> GetSmoothedPath(ICellMap map, Vector2Int start, Vector2Int stop, NeighbourMode neighbourMode)
        {
            var rawPath = GetPath(map, start, stop, neighbourMode);

            if (rawPath == null)
            {
                return(null);
            }
            PathSmoother smoother = new PathSmoother();
            var          path     = smoother.GetSmoothedPath(map, rawPath);

            return(path);
        }
Exemple #19
0
        /// <summary>
        /// Get the item in the cell at the specified location
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="map"></param>
        /// <param name="location">A point vector which lies within the cell to be retrieved.</param>
        /// <returns></returns>
        public static T CellAt <T>(this ICellMap <T> map, Vector location)
        {
            int i = map.IndexAt(location);

            if (map.Exists(i))
            {
                return(map[i]);
            }
            else
            {
                return(default(T));
            }
        }
Exemple #20
0
        public IList <Vector2Int> GetPath(ICellMap mapBase, Vector2Int start, Vector2Int stop, NeighbourMode neighbourMode)
        {
            if (_layeredCellMap == null)
            {
                _layeredCellMap = new LayeredCellMap(mapBase);
            }

            bool StartNodeFilter(IWeightedGraphNode <double> node)
            {
                return(node != null && node.Position == start);
            }

            bool StopNodeFilter(IWeightedGraphNode <double> node)
            {
                return(node != null && node.Position == stop);
            }

            IWeightedGraph <double> graph = GraphGenerator.GetWeightedGraph(_layeredCellMap, neighbourMode);
            var nodes = graph.GetWeightedGraphNodes();

            IWeightedGraphNode <double>[] keyNodes = Utils.GetItemsByFilters(nodes, StartNodeFilter, StopNodeFilter);
            var startNode = keyNodes[0];
            var stopNode  = keyNodes[1];

            foreach (var node in nodes)
            {
                if (node == null)
                {
                    continue;
                }
                node.Data = new GraphData()
                {
                    DistanceToStop = GetDistance(node.Position, stop)
                };
            }

            var nodePath = GetPath(graph, startNode, stopNode);

            if (nodePath == null)
            {
                return(null);
            }
            List <Vector2Int> path = new List <Vector2Int>(nodePath.Count);

            foreach (var node in nodePath)
            {
                path.Add(node.Position);
            }

            return(path);
        }
Exemple #21
0
        public static GraphNode[,] GetGraph(ICellMap map, NeighbourMode neighbourMode)
        {
            GraphNode[,] nodes = new GraphNode[map.Width, map.Height];
            for (int x = 0; x < map.Width; x++)
            {
                for (int y = 0; y < map.Height; y++)
                {
                    if (map.IsPassable(x, y))
                    {
                        GraphNode connectionNode;
                        GraphNode currentNode = new GraphNode();
                        nodes[x, y]          = currentNode;
                        currentNode.Position = new Vector2Int(x, y);

                        int prevX = x - 1;
                        int prevY = y - 1;
                        int nextY = y + 1;

                        if (prevX >= 0)
                        {
                            connectionNode = nodes[prevX, y];
                            ConnectNodes(currentNode, connectionNode);
                        }

                        if (prevY >= 0)
                        {
                            connectionNode = nodes[x, prevY];
                            ConnectNodes(currentNode, connectionNode);
                        }

                        if (prevX >= 0 && prevY >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals)
                        {
                            connectionNode = nodes[prevX, prevY];
                            ConnectNodes(currentNode, connectionNode);
                        }

                        if (nextY < map.Height && prevX >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals)
                        {
                            connectionNode = nodes[prevX, nextY];
                            ConnectNodes(currentNode, connectionNode);
                        }
                    }
                    else
                    {
                        nodes[x, y] = null;
                    }
                }
            }

            return(nodes);
        }
Exemple #22
0
        /// <summary>
        /// Get the items in the cells at the specified locations
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="map"></param>
        /// <param name="locations"></param>
        /// <returns></returns>
        public static IList <T> CellsAt <T>(this ICellMap <T> map, IList <Vector> locations)
        {
            var result = new List <T>(locations.Count);

            foreach (Vector location in locations)
            {
                int i = map.IndexAt(location);
                if (map.Exists(i))
                {
                    result.Add(map[i]);
                }
            }
            return(result);
        }
Exemple #23
0
        private IList <Vector2Int> ForwardSmoothing(ICellMap map, IList <Vector2Int> rawPath)
        {
            List <Vector2Int> smoothedPath = new List <Vector2Int>(rawPath.Count);
            bool lineCasterFailed = false;
            BresenhamLinePlotter lineCaster = new BresenhamLinePlotter();
            int        currentIndex = 0, nextIndex = 1, lastValidIndex = 1;
            Vector2Int lastObstacle = default;

            bool IsCellPassable(int x, int y)
            {
                bool isPassable = map.IsPassable(x, y);

                if (!isPassable)
                {
                    OnObstacleDetectedEvent?.Invoke(x, y);
                    lastObstacle     = new Vector2Int(x, y);
                    lineCasterFailed = true;
                }

                return(isPassable);
            }

            bool SetPathCell(int x, int y)
            {
                smoothedPath.Add(new Vector2Int(x, y));
                return(true);
            }

            while (currentIndex < rawPath.Count - 1)
            {
                nextIndex      = currentIndex + 1;
                lastValidIndex = currentIndex;
                while (nextIndex < rawPath.Count)
                {
                    lineCasterFailed = false;
                    lineCaster.CastLine(rawPath[currentIndex], rawPath[nextIndex], IsCellPassable);

                    if (!lineCasterFailed)
                    {
                        lastValidIndex = nextIndex;
                    }
                    nextIndex++;
                }

                lineCaster.CastLine(rawPath[currentIndex], rawPath[lastValidIndex], SetPathCell);
                currentIndex = lastValidIndex + 1;
            }

            return(smoothedPath);
        }
Exemple #24
0
        public void UpdateGraph(ICellMap map, ICellFragment cellFragment, HierarchicalMap graph, NeighbourMode neighbourMode)
        {
            var        clusterMatrix = graph.ZeroLevelClusters;
            int        clusterWidth  = graph.ClusterDefaultWidth;
            int        clusterHeight = graph.ClusterDefaultHeight;
            Vector2Int fragmentSize  = new Vector2Int(cellFragment.Width, cellFragment.Height);

            Vector2Int leftBottomClusterPosition = GetContainingClusterPosition(clusterMatrix, clusterWidth, clusterHeight, cellFragment.LeftBottom);
            Vector2Int rightTopClusterPosition   = GetContainingClusterPosition(clusterMatrix, clusterWidth, clusterHeight, cellFragment.LeftBottom + fragmentSize);

            int iMin = leftBottomClusterPosition.X;
            int iMax = rightTopClusterPosition.X;
            int jMin = leftBottomClusterPosition.Y;
            int jMax = rightTopClusterPosition.Y;

            for (int i = iMin; i <= iMax; i++)
            {
                for (int j = jMin; j <= jMax; j++)
                {
                    CellCluster currentCluster = clusterMatrix[i, j];

                    int prevI = i - 1;
                    int prevJ = j - 1;
                    int nextJ = j + 1;
                    if (prevI >= iMin)
                    {
                        CellCluster neighbourCluster = clusterMatrix[prevI, j];
                        RemoveTransitionNodes(currentCluster, neighbourCluster, graph);
                        ProceedNeighbourClusters(currentCluster, neighbourCluster, graph);
                    }

                    if (prevJ >= jMin)
                    {
                        CellCluster neighbourCluster = clusterMatrix[i, prevJ];
                        RemoveTransitionNodes(currentCluster, neighbourCluster, graph);
                        ProceedNeighbourClusters(currentCluster, neighbourCluster, graph);
                    }
                }
            }

            for (int i = iMin; i <= iMax; i++)
            {
                for (int j = jMin; j <= jMax; j++)
                {
                    CellCluster currentCluster = clusterMatrix[i, j];
                    currentCluster.CalculatePaths(neighbourMode, null);
                }
            }
        }
Exemple #25
0
        /// <summary>
        /// Retrieve a list of all cells adjacent to the one with the specified index
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="map"></param>
        /// <param name="cellIndex"></param>
        /// <returns></returns>
        public static IList <T> AdjacentCells <T>(this ICellMap <T> map, int cellIndex)
        {
            int aC     = map.AdjacencyCount(cellIndex);
            var result = new List <T>(aC);

            for (int i = 0; i < aC; i++)
            {
                int iA = map.AdjacentCellIndex(cellIndex, i);
                if (map.Exists(iA))
                {
                    result.Add(map[iA]);
                }
            }
            return(result);
        }
Exemple #26
0
    public override void RefreshUI()
    {
        object value = Binding.GetBoundValue();

        if (value is ICellMap <int> )
        {
            ICellMap <int> map = (ICellMap <int>)value;
            if (_NewValue != null)
            {
                _OldValue = _NewValue;
            }
            _NewValue = (SquareCellMap <int>)map;
            _Tween    = 0;
        }
    }
Exemple #27
0
        public void ShowMap(ICellMap cellMap, IList <Vector2Int> path)
        {
            _cellMap = cellMap;
            _stage   = 0;

            DrawCellMatrix();

            _pictureBoxGraphics = PictureBox.CreateGraphics();

            AddAlgorithms();

            _userPath = path;

            Show();
        }
Exemple #28
0
        /// <summary>
        /// Get the polyline representing the border of the cell with the specified index
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="map"></param>
        /// <param name="cellIndex"></param>
        /// <returns></returns>
        public static PolyLine CellBorder <T>(this ICellMap <T> map, int cellIndex)
        {
            int vC = map.VertexCount(cellIndex);

            if (vC > 0)
            {
                var result = new PolyLine();
                for (int i = 0; i < vC; i++)
                {
                    result.Add(map.CellVertex(cellIndex, i));
                }
                result.Close();
                return(result);
            }
            return(null);
        }
Exemple #29
0
        public static Bitmap GetBitmap(ICellMap map, int scale)
        {
            Bitmap bitmap = new Bitmap(map.Width * scale, map.Height * scale);

            for (int x = 0; x < map.Width; x++)
            {
                for (int y = 0; y < map.Height; y++)
                {
                    if (!map.IsPassable(x, y))
                    {
                        DrawScaledPixel(bitmap, Color.Black, x, y, scale);
                    }
                }
            }

            return(bitmap);
        }
Exemple #30
0
        private bool IsLayerCellPassable(int index, int x, int y)
        {
            ICellMap   layer  = _layers[index];
            Vector2Int offset = _layerOffsets[index];

            int shiftedX = x - offset.X;
            int shiftedY = y - offset.Y;

            if (!layer.IsInBounds(shiftedX, shiftedY))
            {
                return(true);
            }
            else
            {
                bool layerIsPassable = layer.IsPassable(shiftedX, shiftedY);
                return(layerIsPassable);
            }
        }