2
\$\begingroup\$

I have a game where there are multiple enemies who must chase a single player. I have pathfinding set up using the GML A* pathfinding with mp_grid and a path. However, these enemies can walk on top of each other when seeking the player. To fix this, I also told the path to ignore enemies as well with mp_grid_add_instances, but then they stop moving altogether because they see themselves as obstacles, thus trapping themselves within a bounding box. Is there a way I can add "all other enemies BUT self" with mp_grid_add_instances?

Here's my grid creation code (in a CONTROLS class for initializing variables):

global.zombie_ai_grid = mp_grid_create(0, 0, room_width / 50, (room_height - sp_dashboard.sprite_height) / 50, 50, 50);
mp_grid_add_instances(global.zombie_ai_grid, obj_obstacle, false);

This is my path initialization code (in Zombie class):

path = path_add();
alarm[0] = 5;

This is my path creation code in Alarm 0 (path updates every 2 seconds):

mp_grid_path(global.zombie_ai_grid, path, x, y, nearest.x, nearest.y, true);
path_set_kind(path, 1);
path_set_precision(path, 8);

path_end();
path_start(path, MAX_SPEED, 0, true);

alarm[0] = room_speed * 2;
\$\endgroup\$
1
\$\begingroup\$

Probably the easiest way is to alter the A* heuristic. Once a tile has been used in a path, increase the heuristic for this tile so that the next pathfinding call will try to avoid that tile. This will also make the zombies gather around the player.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

Instead of using A-star from each zombie to the player, use a breadth-first (ie Dijstra's) out from the player, and as you encounter each zombie assign it the current best path. Have each zombie ignore other zombies for pathfinding but skip a step if the next node is occupied by a zombie.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

Basically, you'll want the zombies to all be added to the grid EXCEPT the one who is currently pathfinding, correct? That way, it won't consider itself an obstacle and get stuck in place. Update the grid using "with" and doing an ID check. The downside is that we have to clear the grid all the time to constantly update enemy positions, but in my example each enemy had their own specific grid rather than a controller with a global variable grid. It looks like this:

// ---STEP EVENT---

mp_grid_clear_all(grid);
with enemy
{
    if (id != other.id) mp_grid_add_instances(other.grid, id, 0);
}

This code is run WITHIN the enemy itself. When it references "other", it's calling back to itself and checking its own ID. Real simple and it works flawlessly for having enemies avoid overlap and work their way around each other. In my case, I chose non-precise collisions because I didn't need to worry about that.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.