Пример #1
0
    private PathResult FindPath(Vector2Int begXY, Vector2Int endXY, Bounds2Int bounds,
                                List <PawnTransition> pawnTransitions, params Transform[] contentContainers)
    {
        if (begXY == endXY)
        {
            return(new PathResult(true, new List <Vector2Int>()));
        }
        else
        {
            _tileTextsContainer.transform.DestroyAllChildren();
            begXY -= bounds.Min;
            endXY -= bounds.Min;
            //Debug.Log(GetType() + ".FindPathToTarget: bounds: " + bounds.Min + " " + bounds.Max + " " + bounds.Size + " ");
            //Debug.Log(GetType() + ".FindPathToTarget: " + begXY + "->" + endXY);
            var nodes = CreateCellNodes(begXY, endXY, bounds, pawnTransitions, contentContainers);

            HashSet <Vector2Int> nodesXY = new HashSet <Vector2Int>()
            {
                begXY
            };
            bool targetReached = false;
            while (nodesXY.Count > 0)
            {
                nodesXY = UpdateCellNodes(nodes, bounds, nodesXY, endXY, ref targetReached);
            }
            ClearTilesMeshTexts(bounds);
            return(new PathResult(targetReached, CreatePath(nodes, bounds, begXY, endXY)));
        }
    }
Пример #2
0
    private List <Vector2Int> CreatePath(CellNode[] nodes, Bounds2Int bounds, Vector2Int begXY, Vector2Int endXY)
    {
        List <Vector2Int> path    = new List <Vector2Int>();
        CellNode          endNode = nodes[GetCellNodeIndex(endXY, bounds.Size)];

        if (begXY != endXY && endNode.distance < float.MaxValue / 2f)
        {
            //Debug.Log(GetType() + ".GetPath: " + begXY + "->" + endXY);
            CellNode begNode       = nodes[GetCellNodeIndex(begXY, bounds.Size)];
            bool     begNodeLocked = begNode.locked;
            begNode.locked = false;

            Vector2Int nodeXY = endXY;
            path.Add(nodeXY);
            while (nodeXY != begXY)
            {
                nodeXY = GetMinDistanceNgbrCellNodeXY(nodes, nodeXY, bounds);
                path.Add(nodeXY);
            }
            if (path.Count > 1)
            {
                path.RemoveAt(path.Count - 1);
            }
            for (int i = 0; i < path.Count; i++)
            {
                path[i] += bounds.Min;
                //Debug.Log(GetType() + ".GetPath: " + path[i]);
            }
            begNode.locked = begNodeLocked;
        }
        return(path);
    }
Пример #3
0
    private HashSet <Vector2Int> UpdateCellNodes(CellNode[] nodes, Bounds2Int bounds, HashSet <Vector2Int> nodesXY, Vector2Int targetXY,
                                                 ref bool targetReached)
    {
        HashSet <Vector2Int> nextNodesXY = new HashSet <Vector2Int>();
        //targetReached = false;
        Func <CellNode, int, bool> ngbrClosed = null;

        if (_cellNodeEnterRiskLevel > 0)
        {
            ngbrClosed = (ngbrNode, i) => ngbrNode.ngbrsEnterRisk[i];
        }
        else
        {
            ngbrClosed = (ngbrNode, i) => false;
        }
        foreach (var nodeXY in nodesXY)
        {
            int      nodeIndex = GetCellNodeIndex(nodeXY, bounds.Size);
            CellNode node      = nodes[nodeIndex];
            node.@checked = true;
            nextNodesXY.Remove(nodeXY);
            for (int i = 0; i < _cellNgbrsDeltaXY.Length; i++)
            {
                Vector2Int ngbrDeltaXY = _cellNgbrsDeltaXY[i];
                Vector2Int ngbrXY      = nodeXY + ngbrDeltaXY;
                if (CellNodeInBounds(ngbrXY, bounds.Size))
                {
                    int      ngbrNodeIndex = GetCellNodeIndex(ngbrXY, bounds.Size);
                    CellNode ngbrNode      = nodes[ngbrNodeIndex];
                    if (!ngbrNode.locked && !ngbrClosed(ngbrNode, i))
                    {
                        float delta = ngbrDeltaXY.x == 0 || ngbrDeltaXY.y == 0 ? 1f : SQRT2;
#if LOCKED_CELLS_HEIGHTS
                        for (int j = 0; j < 3; j++)
                        {
                            delta += 1.5f * ngbrNode.lockedNgbrsCount[j] / (8 * (i + 1));
                        }
#endif
                        float ngbrDistance = node.distance + delta * 0.25f + ngbrNode.ngbrPlayerPawnsCount[0];
                        //float ngbrDistance = node.distance + delta;
                        if ((!ngbrNode.@checked || ngbrDistance < ngbrNode.distance) && !nextNodesXY.Contains(ngbrXY))
                        {
                            nextNodesXY.Add(ngbrXY);
                        }
                        ngbrNode.distance = Mathf.Min(ngbrNode.distance, ngbrDistance);
#if DEBUG_SHOW_DISTANCES
                        SetTileMeshText(ngbrXY + bounds.Min, ngbrNode.distance.ToString("F1") + "\n" + ngbrNode.ngbrPlayerPawnsCount[0]);
#endif
                        if (ngbrXY == targetXY)
                        {
                            targetReached = true;
                            //nextNodesXY.Clear();
                            //return nextNodesXY;
                        }
                    }
                }
            }
        }
        return(nextNodesXY);
    }
Пример #4
0
    public PathResult FindPathToBoundsMin(TileContent begTileContent, params Transform[] contentContainers)
    {
        Vector2Int begXY  = _tilemap.WorldToCell(begTileContent.transform.position);
        Bounds2Int bounds = _tilemap.GetTilesContentCellBounds(begXY, contentContainers);
        Vector2Int endXY  = bounds.Min;

        _cellNodeEnterRiskLevel = 0;
        return(FindPath(begXY, endXY, bounds, null, contentContainers));
    }
Пример #5
0
    public IEnumerator FindPathRoutine(TileContent begTileContent, TileContent endTileContent, Action <PathResult> onEnd,
                                       List <PawnTransition> pawnTransitions, params Transform[] contentContainers)
    {
        Vector2Int begXY  = _tilemap.WorldToCell(begTileContent.transform.position);
        Vector2Int endXY  = _tilemap.WorldToCell(endTileContent.transform.position);
        Bounds2Int bounds = _tilemap.GetTilesContentCellBounds(begXY, endXY, contentContainers);

        _cellNodeEnterRiskLevel = 0;
        yield return(FindPathRoutine(begXY, endXY, bounds, onEnd, pawnTransitions, contentContainers));
    }
Пример #6
0
 private void ClearTilesMeshTexts(Bounds2Int bounds)
 {
     for (int y = bounds.Min.y; y <= bounds.Max.y; y++)
     {
         for (int x = bounds.Min.x; x <= bounds.Max.x; x++)
         {
             BoardTile tile = _tilemap.GetTile(new Vector2Int(x, y));
             if (tile)
             {
                 tile.TextMesh = null;
             }
         }
     }
 }
Пример #7
0
    private IEnumerator UpdateCellNodesRoutine(CellNode[] nodes, Bounds2Int bounds, Vector2Int begXY, Vector2Int endXY, Action <bool> onEnd)
    {
        HashSet <Vector2Int> nodesXY = new HashSet <Vector2Int> {
            begXY
        };
        bool targetReached = false;

        while (nodesXY.Count > 0)
        {
            nodesXY = UpdateCellNodes(nodes, bounds, nodesXY, endXY, ref targetReached);
            yield return(new WaitForSeconds(0.1f));
        }
        onEnd(targetReached);
    }
Пример #8
0
    private void SetCellNodesNgbrPlayerPawnsCount(CellNode[] nodes, Bounds2Int bounds)
    {
        Vector2Int size    = bounds.Size;
        int        columns = bounds.Size.x;

        for (int y = 1; y < size.y - 1; y++)
        {
            for (int x = 1; x < size.x - 1; x++)
            {
                CellNode cellNode = nodes[GetCellNodeIndex(x, y, columns)];
                if (!cellNode.locked)
                {
                    for (int k = 0; k < 3; k++)
                    {
                        cellNode.ngbrPlayerPawnsCount[k] = 0;
                        int   n_even = 2 + 2 * k;
                        int   n_odd  = n_even + 1; //3 + 2 * k;
                        int[] deltaJ = new int[n_odd];
                        for (int j = 1; j < n_odd - 1; j++)
                        {
                            deltaJ[j] = n_even;
                        }
                        deltaJ[0] = deltaJ[n_odd - 1] = 1;
                        //string s = "\n";
                        int offset = k + 1;
                        for (int i = 0; i < n_odd; i++)
                        {
                            int dy = i - offset;
                            for (int j = 0; j < n_odd; j += deltaJ[i])
                            {
                                int        dx     = j - offset;
                                Vector2Int ngbrXY = new Vector2Int(x + dx, y + dy);
                                //s += "(" + dx + "," + dy + ")";
                                if (CellNodeInBounds(ngbrXY, bounds.Size))
                                {
                                    int      ngbrNodeIndex = GetCellNodeIndex(ngbrXY, bounds.Size);
                                    CellNode ngbrNode      = nodes[ngbrNodeIndex];
                                    cellNode.ngbrPlayerPawnsCount[k] += ngbrNode.isPlayerPawn ? 1 : 0;
                                }
                            }
                            //s += "\n";
                        }
                        //Debug.Log(GetType() + "." + s);
                    }
                }
            }
        }
    }
Пример #9
0
    private CellNode[] CreateCellNodes(Vector2Int begXY, Vector2Int endXY, Bounds2Int bounds,
                                       List <PawnTransition> pawnTransitions, params Transform[] contentContainers)
    {
        var nodes = new CellNode[bounds.Size.x * bounds.Size.y];

        for (int i = 0; i < nodes.Length; i++)
        {
            nodes[i] = new CellNode();
        }
        int columns = bounds.Size.x;
        int nodeIndex;

        foreach (Transform container in contentContainers)
        {
            bool isPlayerPawnsContainer = container.childCount > 0 && container.GetChild(0).GetComponent <PlayerPawn>();
            foreach (Transform child in container)
            {
                Vector2Int cell = _tilemap.WorldToCell(child.position);
                nodeIndex = GetCellNodeIndex(cell - bounds.Min, columns);
                nodes[nodeIndex].locked       = true;
                nodes[nodeIndex].isPlayerPawn = isPlayerPawnsContainer;
            }
        }
        if (pawnTransitions != null)
        {
            foreach (var pawnTransition in pawnTransitions)
            {
                nodeIndex = GetCellNodeIndex(pawnTransition.EndCell - bounds.Min, columns);
                nodes[nodeIndex].locked = true;
                nodeIndex = GetCellNodeIndex(pawnTransition.BegCell - bounds.Min, columns);
                nodes[nodeIndex].locked = false;
            }
        }
        CellNode begNode = nodes[GetCellNodeIndex(begXY, columns)];
        CellNode endNode = nodes[GetCellNodeIndex(endXY, columns)];

        begNode.distance = 0f;
        begNode.locked   = false;
        endNode.locked   = false;

        SetCellNodesNgbrPlayerPawnsCount(nodes, bounds);
        SetCellNodesEnterRisks(nodes, bounds, begXY, endXY);
        ResetCellNodesNgbrPlayerPawnsCountAroundTarged(nodes, bounds, endXY, 2);

        return(nodes);
    }
Пример #10
0
    public PathResult FindPath(Pawn pawn, TileContent target,
                               List <PawnTransition> pawnTransitions, params Transform[] contentContainers)
    {
        Vector2Int begXY      = _tilemap.WorldToCell(pawn.transform.position);
        Vector2Int endXY      = _tilemap.WorldToCell(target.transform.position);
        Bounds2Int bounds     = _tilemap.GetTilesContentCellBounds(begXY, endXY, contentContainers);
        PathResult pathResult = null;

        for (int i = 0; i < 3; i++)
        {
            _cellNodeEnterRiskLevel = 2 - i;
            pathResult = FindPath(begXY, endXY, bounds, pawnTransitions, contentContainers);
            Debug.Log(GetType() + ".FindPath: _cellNodeEnterRiskLevel: " + _cellNodeEnterRiskLevel + " pathResult.PathFound: " + pathResult.PathFound);
            if (pathResult.PathFound)
            {
                break;
            }
        }
        return(pathResult);
    }
Пример #11
0
    private void ResetCellNodesNgbrPlayerPawnsCountAroundTarged(CellNode[] nodes, Bounds2Int bounds, Vector2Int endXY, int offset)
    {
        int columns = bounds.Size.x;

        for (int y = endXY.y - offset; y <= endXY.y + offset; y++)
        {
            for (int x = endXY.x - offset; x <= endXY.x + offset; x++)
            {
                if (CellNodeInBounds(x, y, bounds.Size))
                {
                    CellNode cellNode = nodes[GetCellNodeIndex(x, y, columns)];
                    if (!cellNode.locked)
                    {
                        for (int k = 0; k < 3; k++)
                        {
                            cellNode.ngbrPlayerPawnsCount[k] = 0;
                        }
                    }
                }
            }
        }
    }
Пример #12
0
    private IEnumerator FindPathRoutine(Vector2Int begXY, Vector2Int endXY, Bounds2Int bounds, Action <PathResult> onEnd,
                                        List <PawnTransition> pawnTransitions, params Transform[] contentContainers)
    {
        if (begXY == endXY)
        {
            onEnd?.Invoke(new PathResult(true, new List <Vector2Int>()));
        }
        else
        {
            _tileTextsContainer.transform.DestroyAllChildren();
            begXY -= bounds.Min;
            endXY -= bounds.Min;
            var nodes = CreateCellNodes(begXY, endXY, bounds, pawnTransitions, contentContainers);

            HashSet <Vector2Int> nodesXY = new HashSet <Vector2Int>()
            {
                begXY
            };
            yield return(UpdateCellNodesRoutine(nodes, bounds, begXY, endXY, targetReached => {
                ClearTilesMeshTexts(bounds);
                onEnd?.Invoke(new PathResult(targetReached, CreatePath(nodes, bounds, begXY, endXY)));
            }));
        }
    }
Пример #13
0
    private Vector2Int GetMinDistanceNgbrCellNodeXY(CellNode[] nodes, Vector2Int nodeXY, Bounds2Int bounds)
    {
        float      minDistance   = float.MaxValue;
        Vector2Int minDistNgbrXY = default;

        foreach (var ngbrDeltaXY in _cellNgbrsDeltaXY)
        {
            Vector2Int ngbrXY = nodeXY + ngbrDeltaXY;
            if (CellNodeInBounds(ngbrXY, bounds.Size))
            {
                int      ngbrNodeIndex = GetCellNodeIndex(ngbrXY, bounds.Size);
                CellNode ngbrNode      = nodes[ngbrNodeIndex];
                if (!ngbrNode.locked && ngbrNode.distance < minDistance)
                {
                    minDistance   = ngbrNode.distance;
                    minDistNgbrXY = ngbrXY;
                }
            }
        }
        //Debug.Log(GetType() + ".GetMinDistanceCellNodeNgbrXY: " + minDistNgbrXY);
        return(minDistNgbrXY);
    }
Пример #14
0
    private void SetCellNodesEnterRisks(CellNode[] nodes, Bounds2Int bounds, Vector2Int begXY, Vector2Int endXY)
    {
        if (_cellNodeEnterRiskLevel > 0)
        {
            Vector2Int size    = bounds.Size;
            int        columns = bounds.Size.x;
            bool NodeIsPlayerPawn(int nodeX, int nodeY)
            {
                return(nodes[GetCellNodeIndex(nodeX, nodeY, columns)].isPlayerPawn);
            }

            Action <int, int, CellNode, CellNode[], int> setCellNodeEnterRisks = SetCellNoneEnterRisksLevel1;
            if (_cellNodeEnterRiskLevel > 1)
            {
                setCellNodeEnterRisks += SetCellNoneEnterRisksLevel2;
            }
            for (int y = 1; y < size.y - 1; y++)
            {
                for (int x = 1; x < size.x - 1; x++)
                {
                    CellNode cellNode = nodes[GetCellNodeIndex(x, y, columns)];
                    if (!cellNode.locked)
                    {
                        setCellNodeEnterRisks(x, y, cellNode, nodes, columns);
                        for (int i = 0; i < 8; i++)
                        {
                            Vector2Int delta = _cellNgbrsDeltaXY[i].Negative();
                            cellNode.ngbrsEnterRisk[i] |= NodeIsPlayerPawn(x + delta.x, y + delta.y);
                        }
                    }
                }
            }
            CellNode endNode = nodes[GetCellNodeIndex(endXY, columns)];
            for (int i = 0; i < 8; i++)
            {
                CellNode begNgbrNode = nodes[GetCellNodeIndex(begXY + _cellNgbrsDeltaXY[i], columns)];
                begNgbrNode.ngbrsEnterRisk[i] = false;
                endNode.ngbrsEnterRisk[i]     = false;
                //CellNode endNgbrNode = nodes[GetCellNodeIndex(endXY + _cellNgbrsDeltaXY[i], columns)];
                //for (int j = 0; j < 8; j++)
                //{
                //    endNgbrNode.ngbrsEnterRisk[j] = false;
                //}
            }
#if DEBUG_SHOW_CELL_ENTER_RISK
            for (int y = 1; y < size.y - 1; y++)
            {
                for (int x = 1; x < size.x - 1; x++)
                {
                    CellNode   cellNode       = nodes[GetCellNodeIndex(x, y, columns)];
                    bool[]     ngbrsEnterRisk = cellNode.ngbrsEnterRisk;
                    Vector2Int cell           = new Vector2Int(x + bounds.Min.x, y + bounds.Min.y);
                    int[]      risks          = new int[ngbrsEnterRisk.Length];
                    for (int i = 0; i < ngbrsEnterRisk.Length; i++)
                    {
                        risks[i] = ngbrsEnterRisk[i] ? 1 : 0;
                    }
                    string risksText = risks[5] + "" + risks[2] + "" + risks[4] + "\n";
                    risksText += risks[1] + "0" + risks[0] + "\n";
                    risksText += risks[7] + "" + risks[3] + "" + risks[6];
                    SetTileMeshText(cell, risksText);
                }
            }
#endif
        }
    }