• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GML Running the pathfinding AI only once in a while, without freezing the NPC.

Dr_Nomz

Member
I have a nice AI pathfinding system set up (courtesy of a video tutorial in the spoiler below) which works great for Zombie/follower AI, but unfortunately it's a system that takes up an unreasonable amount of CPU.

Now a solution I heard was just to run the code every so often instead of every single step, but when I put a timer on that code it just freezes the zombie, so really it's doing the exact opposite of what I need.

So what I need is to know how I can rearrange this code to work on a timer so it's not eating the CPU all the time, but without making the zombies just do nothing. (It would be really nice to have a simple timer that I can alter too, especially to add "random" so it doesn't freeze trying to process hundreds of enemies all at once every so often lol.)
Code:
target_x = argument0;
target_y = argument1;

mp_grid_path(grid,path,x,y,target_x,target_y,true);
path_start(path,100,path_action_stop,false);
That script is called to give the NPC (zombie) the path it needs to follow. (based on a grid that's created at the start of the room) In this case "target_x/y" can be anything, but is currently the obj_Character. (Player Character)

The zombie's code:
Code:
///End Step
motion_add(point_direction(x,y,planner.x,planner.y),1);
  if speed>5{
    speed=5;
    }
  target_x = obj_Character.x;
  target_y = obj_Character.y;
  with (planner){
    x=follower.x
    y=follower.y
    scr_NPC_Path(other.target_x,other.target_y);
    }
The "planner" is just an object with the create event for making the path in the first place, and then the zombie follows it from there. It's basically done this way to provide smoother movement.
Code:
planner = instance_create(x,y,obj_Path_Planner);
planner.follower = id;
^That's the zombie's create event, which creates the planner with the ID and everything it needs to function for that specific instance of obj_Zombie.

Basically I'm wondering if anything here "looks wrong", and if so please tell me immediately.
Here's the tutorial I used if anyone's interested:
Now I did have a thread for a similar question, but it didn't have all the information up top like this, and the thread's title wasn't very specific like it is now. (Also the answer was basically "Yes, if you run it every step.")
 
but when I put a timer on that code it just freezes the zombie
If you are finding that your timer is freezing your zombie, then can you show us how you have been doing the timer (as it doesn't appear to be in any of that code above) as it may be just tweaking that to make it work. It would be better to adjust something you have implemented, but are finding not to be working, than us coming up with a brand new timer/alarm system for you when it may not work with what you have.
 

Dr_Nomz

Member
Yeah that's a good point, should've included that. >_<
Code:
///Create
timer=0;
///Step
timer-=1;
///End Step
if timer<0{
with (planner){
    timer=90;
    x=follower.x
    y=follower.y
    scr_NPC_Path(other.target_x,other.target_y);
    }
}
So, instead of running it EVERY step, it should only run it every 90 steps, right? (every 3 seconds) But it just makes the zombie do nothing. So basically I just need it to move along the path EVERY step, but only calculating the path to obj_Character/target_x/y every 90 steps or whatever I need.
 
So, instead of running it EVERY step, it should only run it every 90 steps, right? (every 3 seconds)
If you set it up correctly, then yes.

But my understanding of what you have set up the above is this (having to assume which objects they are for as you haven't mentioned it above):

In the Zombie create event:
you set the timer to 0.

In the Zombie step event:
you minus 1 from the timer (that was set up in the Zombie create event)
if the timer (that was set up in the Zombie create event) is less than 0 (which it will be during the first step) you then set the timer (in the planner object) to be 90 - because you are setting the timer=90 inside the with(planner) section.

I suspect that you actually want to be setting the timer before the with (planner) so that you actually set the timer variable that you defined in the Zombie create event.

I don't know why it doesn't make your Zombie do anything, as it is basically going to run the scr_NPC_Path script every step regardless of whether it needs to or not, so not sure how that timer would make it do nothing.
 
R

Raff

Guest
And this:

Code:
///Create
timer=0;
///Step
timer-=1;
x=follower.x;
y=follower.y;
///End Step
if timer<0{
with (planner){
    timer=90;
    scr_NPC_Path(other.target_x,other.target_y);
    }
}
 

Dr_Nomz

Member
I don't think Raff knows what he's talking about, the PLANNER has to have it's X and Y the same as the object it's following, not the zombie.

I think I have an idea, how about this code:
Code:
///scr_NPC_Path(target_x,target_y)
target_x = argument0;
target_y = argument1;

mp_grid_path(grid,path,x,y,target_x,target_y,true);
path_start(path,100,path_action_stop,false);
All I need to do is put that on a timer within the Planner. (Let me know if that's wrong in any capacity, or point out whatever bugs that may have)

EDIT: No, that froze them too. Gotta try something else.

EDIT2: Okay, how about just having one of those running every step? Because I want the zombies to be moving in the direction of the Player at all times, but they only need to check the path in the grid to avoid objects once in a while.

Problem is when I keep them on a timer, they just stupidly run into walls instead of following their path, so what do I do?
 
Last edited:

Dr_Nomz

Member
Any suggestions? Tried a bunch of different things and nothing seems to work, just stops the zombie from moving at all.

Code:
 if timer<0{
  with (planner){
    x=follower.x
    y=follower.y
    scr_NPC_Path(other.target_x,other.target_y);
    }
    timer=1;
  }
THAT'S what I'm using for the timer, but it doesn't do anything. If it works without the timer, why won't it just work WITH the timer? All that's different is IF it's lower than 0, it runs. Which, without the timer being set to 1, is ALWAYS true, but it doesn't do anything. Why isn't it running?
 
Last edited:
Why isn't it running?
show_debug_message() is your friend. Use it in your code to make sure that things are being run or not. With enough of them, you should be able to track down where things are going wrong. And as @Simon Gust says, are you actually decreasing the timer anywhere?
I am also a bit confused by your reporting of the problem as you have now claimed that two different things are happening because of your timer:
Problem is when I keep them on a timer, they just stupidly run into walls instead of following their path, so what do I do?
Tried a bunch of different things and nothing seems to work, just stops the zombie from moving at all.
But it just makes the zombie do nothing
You might need to break it down better for us as to exactly what is happening with your zombie instances: are they not moving? or are they moving, but not how you want them to be moving?
If it is the latter, then perhaps it is because you are trying to use a path with path_start(), but every step you are overriding this and using the motion_add() and speed variable to move the zombies (that is my understanding of your original post now that I have the time to re-read it) - are you still doing that?
 

Dr_Nomz

Member
Welp, turns out that little blue thing in the top was in fact NOT my grid object, but it behaved the same way in rooms with a grid so IDK what the problem was. However still relevant because:


Turns out it can't follow the "path planner" AND avoid obstacles at the same time, since the objects are normally on top of each other. Here's a video showing how it normally works:


It works like this because the path planner is constantly jumping ahead to the player and then instantly jumping back, therefore planning the course to take.

The whole point of using this code is to make the zombie's movement look smooth instead of all jerky like it's default movement would be. Any way I can make it so it only has to process the path once every few frames while still retaining the same smooth movements? (The tutorial video up there should help if it still doesn't make sense)
 
Last edited:

Simon Gust

Member
And YES it is counting down with timer-=0 in the step event. :p And I tried putting it in the End Step event with the rest of the code, but it didn't make a difference, and thinking about it I don't think it would regardless.
Are you running the timer down with
Code:
timer -= 0;
or
Code:
timer -= 1;
?
 

Dr_Nomz

Member
With this system, is it at all possible to keep it's smooth movement, while not calculating every step? Because I've tried several things, and none of them work. (And trying to have the planner have a count-down timer just froze it in place...)
 
Top