Reputation: 53
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
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
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
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
Reputation: 26409
Solution:
For each ghost for every update:
return
/continue
)return
/continue
)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
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