aishere
aishere

Reputation: 53

Move ghost toward player in maze if player is nearby?

I think this is a fairly easy thing to implement but I just want the ghost to begin moving one space at a time toward the player, if the player is within 5 spaces of the ghost. In my if statement in move_to_x_y is where the change should be added. How can I do the if statement to move depending on where the player is?

Here is the function checking to see if the ghost is within five spaces:

bool Game::nearby (Ghost & ghost) const
{
if (abs(m_player->get_x() - ghost.get_x()) < 5)
    return true;
if (abs(m_player->get_y() - ghost.get_y()) < 5)
    return true;
return false;
}

Then here is the ghost's move function, he usually just moves in a random direction, which is the else case for when the player is not within five spaces:

void Ghost::move (Game & game) {
Floor *     floor;
int         r;
bool        moved = false;

floor = game.get_curr_floor();
do
{
    if (game.nearby(*this))
        r = //WHAT TO ADD HERE???
    else {
    r = rand() % 4;
    switch (r)
    {
    case 0:
        moved = floor->move_to_x_y (game, *this, 1, 0);
        break;
    case 1:
        moved = floor->move_to_x_y (game, *this, 0, -1);
        break;
    case 2:
        moved = floor->move_to_x_y(game, *this, -1, 0);
        break;
    case 3:
        moved = floor->move_to_x_y(game, *this, 0, 1);
        break;
    }
    }
}
while (! moved);
}

So depending on where the player is, either move up, down, left or right, toward them.

Thanks for the help!

Upvotes: 2

Views: 391

Answers (5)

stefan
stefan

Reputation: 3759

I'd change the bool Game::nearby to return a compass point if the player is nearby.


EDIT: a comment to misunderstanding of the design

Game::nearby() is not intended to imperatively move the ghost. It is meant to provide the ghost with information about the players position. It is up to the ghosts strategy how to use this information. So nearby should return a direction in degrees, compass points or as distance vector. The ghost then may decide to approach the player or sit and duck. In a pacman game all 4 monsters could use this function but apply different strategies.

Upvotes: 2

Tabula Rasa
Tabula Rasa

Reputation: 134

Your function returns whether or not the player is nearby, but gives no information as to which direction the player is in. Change the return value from a bool to an int, or something to indicate the direction. For example:

int Game::nearby (Ghost & ghost) const
{
if (ghost.get_x() - m_player->get_x() < 5 && ghost.get_x() - m_player->get_x() > 0)
    return 2;
if (m_player->get_x() - ghost.get_x() < 5 && m_player->get_x() - ghost.get_x() > 0)
    return 0;
if (ghost.get_y() - m_player->get_y() < 5 && ghost.get_y() - m_player->get_y() > 0)
    return 3;
if (m_player->get_y() - ghost.get_y() < 5 && m_player->get_y() - ghost.get_y() > 0)
    return 1;
return -1;
}

This will return the number that already corresponds to the direction you want him to move in your switch statement. So all you have to do in your move function is set r to the int "nearby" returns, and if it returns -1, set it to a random direction as before.

r = game.nearby(*this);
if (r == -1)
    r = rand() % 4;

switch (r) .... etc

Upvotes: 3

Mooing Duck
Mooing Duck

Reputation: 66922

Two parts. First, try to move closer to the player

void Ghost::move (Game & game) {
    Floor *     floor game.get_curr_floor();
    bool        moved = false;

    if (game.nearby(*this)) {
        //try to move closer in x direction
        if (game.get_player()->get_x() > ghost.get_x())
            moved = floor->move_to_x_y (game, *this, 1, 0);
        else if (ghost.get_x() > game.get_player()->get_x())
            moved = floor->move_to_x_y (game, *this, -1, 0);
        //if we haven't moved, try to move closer in y direction
        if (!moved && game.get_player()->get_y() > ghost.get_y())
            moved = floor->move_to_x_y (game, *this, 0, 1);
        else if (!moved && ghost.get_y() > game.get_player()->get_y())
            moved = floor->move_to_x_y (game, *this, 0, -1);
    }

If that fails or the player is too far away, try to move randomly. If a random direction fails, try the next direction in order. This means we will try at most four directions, with no chance of an infinite loop. This has a slight bias at three way intersections, but that's probably not noticeable. It also has the side effect that if the ghost literally cannot move, the game doesn't freeze.

    //if not moved closer, move randomly
    if (!moved) {
        int r = rand() % 4; //pick random direction
        switch(r) {
        case 0: 
            if(floor->move_to_x_y (game, *this, 1, 0))
                break; //if it failed, try the next one
        case 1: 
            if(floor->move_to_x_y (game, *this, -1, 0))
                break; //if it failed, try the next one
        case 2: 
            if(floor->move_to_x_y (game, *this, 0, 1))
                break; //if it failed, try the next one
        case 3: 
            if(floor->move_to_x_y (game, *this, 0, -1))
                break; //if it failed, try the next one
        default: 
            //if it was case 3, need to try all other directions still
            if(floor->move_to_x_y (game, *this, 1, 0))
                break; //if it failed, try the next one
            if(floor->move_to_x_y (game, *this, -1, 0))
                break; //if it failed, try the next one
            floor->move_to_x_y (game, *this, 0, 1);
            //at this point, all directions have been tried. We're done.
        }//switch             
    } //if
}

Comments point out there's a bug in the nearby function, that it considers anything on the same x axis to be "close".

Upvotes: 0

SigTerm
SigTerm

Reputation: 26409

Solution:

For each ghost for every update:

  1. Attempt to acquire player position.
  2. If player position cannot be acquired (blocked by the wall), do nothing for this ghost in this update (return/continue)
  3. Measure distance to player.
  4. If distance is higher than maximum "awareness range", do nothing for this ghost in this update (return/continue)
  5. Move in direction of player.

Also, do not use "magic numbers" (case 0:) in your code. Use either enums or constants.

So, get rid of "nearby" and replace it with function that returns player position.

Upvotes: 0

Andreas Vennstr&#246;m
Andreas Vennstr&#246;m

Reputation: 715

I would probably do something like this:

if (game.nearby(*this))
{
    int x = player_position_x - ghost_position_x;
    int y = player_position_y - ghost_position_y;

    if (abs(x) > abs(y))
    {
        assert(x != 0);
        x = x / abs(x);
        y = 0;
    }
    else
    {
        assert(y != 0);
        x = 0;
        y = y / abs(y);
    }

    floor->move_to_x_y (game, *this, x, y);
    moved = true;
}

Upvotes: 5

Related Questions