A* Pathfinding

Gameplay Programmer | Unreal & Unity


I love reading programming books. One of my favourites: Programming Game AI by Example by Mat Buckland.

In the book, he discusses algorithms for finding a path on a node graph, which inspired me to create a project where I can code something similar.

//----------------------- IndexedPriorityQLow ---------------------------
//
//  Priority queue based on an index into a set of keys. The queue is
//  maintained as a 2-way heap.
//
//  The priority in this implementation is the lowest valued key
//
// Class based on Mat Buckland's book
//------------------------------------------------------------------------
template<class KeyType>
class TDIndexedPriorityQLow
{
private:

    TArray<KeyType>&    m_vecKeys;
    TArray<int>         m_heap;
    TArray<int>         m_invHeap;
    int                 m_iSize,
                        m_iMaxSize;

    void Swap(int a, int b)
    {
        int temp = m_heap[a]; m_heap[a] = m_heap[b]; m_heap[b] = temp;

        //change the handles too
        m_invHeap[m_heap[a]] = a; m_invHeap[m_heap[b]] = b;
    }

    void ReorderUpwards(int nd)
    {
        //move up the heap, swapping the elements until the heap is ordered
        while ((nd > 1) && (m_vecKeys[m_heap[nd / 2]] > m_vecKeys[m_heap[nd]]))
        {
            Swap(nd / 2, nd);

            nd /= 2;
        }
    }

    void ReorderDownwards(int nd, int HeapSize)
    {
        //move down the heap from node nd, swapping the elements until
        //the heap is reordered
        while (2 * nd <= HeapSize)
        {
            int child = 2 * nd;

            //set child to the smaller of nd's two children
            if ((child < HeapSize) && (m_vecKeys[m_heap[child]] > m_vecKeys[m_heap[child + 1]]))
            {
                ++child;
            }

            //if this nd is larger than its child, swap
            if (m_vecKeys[m_heap[nd]] > m_vecKeys[m_heap[child]])
            {
                Swap(child, nd);

                //move the current node down the tree
                nd = child;
            }

            else
            {
                break;
            }
        }
    }


public:

    //you must pass the constructor a reference to the std::vector, the PQ
    //will be indexing int and the maximum size of the queue.
    TDIndexedPriorityQLow(TArray<KeyType>& keys, int MaxSize) :
        m_vecKeys(keys),
        m_iSize(0),
        m_iMaxSize(MaxSize)
    {
        m_heap.Init(0, MaxSize + 1);
        m_invHeap.Init(0, MaxSize + 1);
    }

    bool IsEmpty()const { return (m_iSize == 0); }

    //to insert an item into the queue, it gets added to the end of the heap
    //and then the heap is reordered from the bottom up.
    void Insert(const int32 idx)
    {
        check(m_iSize + 1 <= m_iMaxSize);

        ++m_iSize;

        m_heap[m_iSize] = idx;

        m_invHeap[idx] = m_iSize;

        ReorderUpwards(m_iSize);
    }

    //to get the min item the first element is exchanged with the lowest
    //in the heap and then the heap is reordered from the top down. 
    int Pop()
    {
        Swap(1, m_iSize);

        ReorderDownwards(1, m_iSize - 1);

        return m_heap[m_iSize--];
    }

    //if the value of one of the client key's changes then call this with 
    //the key's index to adjust the queue accordingly
    void ChangePriority(const int idx)
    {
        ReorderUpwards(m_invHeap[idx]);
    }
};

struct FPFNodeTopLeftToBottomRight
{
    bool operator()(const UCPathFindingNode& A, const UCPathFindingNode& B) const;
};

bool FPFNodeTopLeftToBottomRight::operator()(const UCPathFindingNode& A, const UCPathFindingNode& B) const
{
    if (IsValid(&A) && IsValid(&B))
    {
        FVector lLocA = A.GetNodeLocation();
        FVector lLocB = B.GetNodeLocation();

        //If Xs are same check Ys
        //Low Y goes to the left, Big Y goes to the Right
        if (lLocB.X == lLocA.X)
        {
            return lLocB.Y > lLocA.Y;
        }

        //Big X goes to Top Low X goes to Bottom
        return lLocA.X > lLocB.X;
    }
    return false;
}

-Watch the video