简体   繁体   中英

Implementing a* pathfinding in c++

Trying to implement A* pathfinding for a small game. Running into some strange bugs.

Code:

class PathNode
{
private:
    const PathNode* parent;
    GameObject position;

    int g;
    int h;
    int f;

public:
    PathNode(GameObject _position, int _g, int _h, const PathNode* _parent = nullptr) {

        parent = _parent;
        position = _position;

        g = _g;  // distance between the start node and the current node
        h = _h;  // distance between the current node and the end node
        f = g + h;  // Total cost of the node (g + h)
    }

    PathNode(const PathNode& other) {

        position = other.position;
        g = other.g;  // distance between the start node and the current node
        h = other.h;  // distance between the current node and the end node
        f = other.f;  // Total cost of the node (g + h)

        parent = other.parent;
    }

    bool operator==(const PathNode& other) const {

        return (this->position == other.position);
    }

    bool operator!=(const PathNode& other) const {

        return !operator==(other);
    }

// GETTERS:
    int getg() const;
    int geth() const;
    int getf() const;
    const PathNode* getParent() const;
    const GameObject getPosition() const;

// SETTERS:
    void setg(int newG);
    void seth(int newH);
    void setf(int newF);
    void setParent(const PathNode* newParent);
    void setPosition(GameObject newPos);
};

And The PathFinding code:

char Ghost::aStar(char board[BoardYSize][BoardXSize], GameObject end) {

    int startEndDistance = pow((getX() - end.getX()), 2) + pow((getY() - end.getY()), 2);

    PathNode startNode(getPosition(), 0, startEndDistance);  // in the ctor of PathNode, the default values of Parent == nullptr.

    PathNode endNode(end, startEndDistance, 0);  // in the ctor of PathNode, the default values of Parent == nullptr.

    // Initialize both Open and Closed Lists:
    vector<PathNode> openList;
    vector<PathNode> closedList;

    openList.reserve(500);
    closedList.reserve(500);

    // Add the StartNode:
    openList.push_back(startNode);

    // Loop until you find the end:
    while (openList.size() > 0) {

        // Get the current Node.
        PathNode currentNode(openList[0]);  // Default copy ctor.

        int index = 0;

        for (int i = 0; i < openList.size(); i++) {

            if (openList[i].getf() < currentNode.getf()) {

                index = i;
                currentNode = openList[i];
            }
        }

        // Pop Current off openList, and add to closedList:
        openList.erase(openList.begin() + index);
        closedList.push_back(currentNode);

        // If found the end, return:
        if (currentNode == endNode) {

            // return direction of the first move of the path:
            const PathNode* nextNode = &currentNode;
            const PathNode* firstMoveNode = nullptr;

            while (*nextNode != startNode) {

                firstMoveNode = nextNode;
                nextNode = nextNode->getParent();
            }

            GameObject newPos = firstMoveNode->getPosition();
            GameObject currentPos = startNode.getPosition();

            if (newPos.getX() - currentPos.getX() == 0 && newPos.getY() - currentPos.getY() == 1)

                return 'w';

            else if (newPos.getX() - currentPos.getX() == 0 && newPos.getY() - currentPos.getY() == -1)

                return 'x';

            else if (newPos.getX() - currentPos.getX() == 1 && newPos.getY() - currentPos.getY() == 0)

                return 'd';

            else if (newPos.getX() - currentPos.getX() == -1 && newPos.getY() - currentPos.getY() == 0)

                return 'a';

            else
                return 's';
        }

        // Generate Children:
        vector <PathNode> children;

        // temp is used to generate the children of the currentNode.
        GameObject temp[4];
        temp[0] = GameObject(0, 1);   // Position above currentNode
        temp[1] = GameObject(1, 0);   // Position right of currentNode
        temp[2] = GameObject(0, -1);  // Position left of currentNode
        temp[3] = GameObject(-1, 0);  // Position below currentNode

        for (int i = 0 ; i < 4; i++) {

            // Get Node Position:
            GameObject nodePosition(currentNode.getPosition() + temp[i]);

            // Make Sure within Range of board & Not a Wall (walkable terrain):
            if (!checkLegalMove(nodePosition, board))

                continue;
            
            PathNode newNode(nodePosition, 0, 0, &currentNode);
            children.push_back(newNode);
        }

        // Loop through Children:

        for (auto child : children) {

            bool addChild = true;

            // Child is on the closedList:
            for (auto closedChild : closedList) {

                if (child == closedChild) {

                    addChild = false;
                    continue;
                }
            }

            if (!addChild)  continue;

            // Create the G H and F values:
            child.setg(currentNode.getg() + 1);
            child.seth(pow((child.getPosition().getX() - endNode.getPosition().getX()), 2) + pow((child.getPosition().getY() - endNode.getPosition().getY()), 2));
            child.setf(child.getg() + child.geth());

            // Child is already in the openList:
            for (auto openNode : openList) {

                if (child == openNode && child.getg() > openNode.getg()) {

                    addChild = false;
                    continue;
                }
            }

            if (!addChild)  continue;

            openList.push_back(child);
        }
    }

    return 's';
}

My goal is to use A* to find a route and simply return the direction of the first position to travel to.

The Problem I run into: The problem is that when the condition of currentNode == endNode is met (reached the goal). Every PathNode's parent is simply a pointing to itself (according to the debugger). I don't understand why it's happening, I assume The current pointer gets destroyed at some point in time but i can't figure out why it's happening.

You're storing a pointer to a local variable, so every node will have that same local variable as the parent (and any access to it would be Undefined Behavior once it has been destroyed). This happens in the PathNode newNode(nodePosition, 0, 0, &currentNode); declaration.

You might want to change currentNode to be a pointer, rather than an object, and have it point to the parent object in the closedList vector. This would allow you to update what node it points at without having to make copies. You've reserved enough space for 500 entries so you won't have a problem with dangling pointers until you add the 501st element to the vector.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM