AI unable to catch up to player

I don’t have too much time and I’m away from my computer so I can’t test it, but isn’t there a delay with pathfinding? I’m pretty sure that computing a path yields the thread until a path is returned. I’m unsure how long that takes (I usually write my own pathfinding scripts) but that could be at least one source of delay. Might be too fast to notice though.

Try making it so it goes directly towards the player if you’re within a certain range of them to see if that fixes it.

Server-based entities will still have to deal with server to client latency of course, but this might be able to reduce the overall latency maybe.

I managed to make a script that solves this issue

That’s already what the system I’m making does. However, you did bring up a point that I missed, about pathfindingservice yielding until a result is ready to be returned. I had forgotten about that, so perhaps I can redesign part of my system to incorporate this.

What if you did something similar to TweenServiceV2 aka handle movement in client and verify on server?

That way, the npc will be able to match up to the player while also being mostly consistent between all clients since server verifies the position every second or so.

Alright, here’s the result of my work. It isn’t perfect, but it’s at least functional. For me that is. Let me know if it works for you.

https://www.roblox.com/library/9386031202/Pathfinding-Dummy
And here’s the module you need to use with it:
https://www.roblox.com/library/9386023524/EasyPing
You should put the module inside of ReplicatedStorage.

So I don’t know if I did something wrong (I placed EasyPing in ReplicatedStorage and the dummy in the Workspace), but unfortunately, it doesn’t seem to be working at all. If I don’t move, the AI will run off to the right seemingly indefinitely. If I move, it will pathfind pretty well sometimes and momentarily catch up to me before floating mid-air trailing behind me and other times won’t pathfind at all and will instead just travel in the same direction I’m traveling. I’m not sure what could be causing this because I don’t know enough about the material. The fact that it appears not to pathfind at certain points makes me think it’s something to do with the pathfinding script, but I’m not sure. I’m not getting any errors from what I see.

Has anyone else tested the pathfinding dummy? I’m hoping this is just something on my end because I don’t want to push @BuilderBob25620 any further with their injury if it’s still an issue. The EasyPing module is definitely useful and I’m sure could also be used for other purposes in game.

Don’t worry. I’m doing better now and have regained full use of my limb (at least for typing). Still not allowed to lift anything above 5 pounds, but other than that I’m good.

What seems to be the issue? Also, now that I think about it, I only tested this in studio. I can test it later in a running game instance.

Yes, I’m planning on releasing it as a community resource once I finish the documentation and tutorial.

1 Like

I posted about the issue earlier in the thread and a brief recap is that the AI seems to be acting completely randomly and with total disregard for the scripts you wrote. I wouldn’t worry about the difference between studio and a live server because I’ve only tested everything in studio so far. I followed your instructions about what to place where to the best of my understanding. Am I forgetting something?

Eh. I guess I’ll do some more in-depth testing. Also, what is you are ping while in-game?

Did you try setting the SetNetworkOwner to nil? Network Ownership
This could get rid of the shuttering that the npc is doing.

The script already does this. I knew about it reducing stuttering since the beginning, but it does nothing for making sure the AI actually maintains an accurate position of the player.

I can’t really find anything wrong with what I created. There are a few bits that aren’t as accurate as they could be, but nothing to account for what’s happening in your video.

It must be something on my end, then. I don’t know what could be causing it, because I would assume that there isn’t anything different about my implementation and yours. Maybe I should load the character and scripts into a blank game and test it? I can’t imagine other stuff in the game is messing with things.

This method actually works for me. I manage to make the SimplePath module chase the player.
It’s just if the player’s walkspeed is faster than the AI, then it won’t be able to catch up.
However, it would only move at space forwards to the player’s position. To avoid this, check if the enemy is in near range of the player, if it is then use :MoveTo() at the enemy’s humanoid and target the player until it is not range anymore.

Heres the preview of my AI Chase:

As you can see when I jump, my walkspeed increase faster than the AI speed, therefore it won’t be able to catch me. However, when I stop jumping it finally catches me even when I change directions.

My source code:

local enemy = SimplePath.new(game.Workspace.Enemy)
local target = SimplePath.GetNearestCharacter(enemy.Position)
local position = target.HumanoidRootPart.Position + target.HumanoidRootPart.Velocity.Unit * 10

while task.wait() do
    if (target.HumanoidRootPart.Position - model.Head.Position).Magnitude <= 20 then
  		enemy.Humanoid:MoveTo(Target.HumanoidRootPart.Position)
	else
	    game.Workspace.Enemy(target.HumanoidRootPart.Position + target.HumanoidRootPart.Velocity.Unit * 10)
   	end
end

This is just a sample code, you need to add a counter if the enemy:MoveTo() is stuck then recalculate the waypoints and go to the waypoints instead
The rest of the code is getting the player’s magnitude between the enemy and check if it’s near so it can kill the player.

This problem is actually super annoying but thanks to this post created that I manage to overcome it on my game

4 Likes

I just saw this. What is the size of your AI’s hitboxes? It seems like it’s grabbing you from further away than my AI would be. I’m trying to keep the attack radius rather tight for my enemies so people don’t feel cheated while fighting them.

Hey, I’ve recently come across this problem as well. I’ve actually solved it; though, how good my solution is will need to be seen. Further testing is required especially for certain edge cases.

Basically, just like with making cosmetic projectiles, you can make cosmetic NPCs. The general gist is that the server is still accurate, just in the past. So a server NPC does touch actually touch the player - it just doesn’t look like it does because the client (you) is ahead.

A client simulated NPC won’t have any latency and thus will be able to reach you. With the server NPC as the authority, you can send remotes when the server NPC touches the player in the past and the client NPC can do whatever you need to do, and its position should be accurate. You might notice a slight delay, depending on your ping, but honestly it’s better than being hit 3 kilometers away.

The edge cases I’ve mentioned (I haven’t tested thoroughly enough, I got sidetracked on my project) is probably desync between client NPC and server NPC, plus really laggy players might mess up the system.

I like this system because it doesn’t depend on “predicting” player movement. It’s nigh impossible to accurately do so unless the player moves like a snail, any fast paced gameplay will probably throw any prediction off, due to its rapidly changing nature.

I’m using magnitude to get the the player distance between the enemy, so therefore the hitbox is just a radius of sphere.

Also the problem about this code is that when the you are in range of the enemy’s, and there’s a wall blocking the enemy’s path, then using :MoveTo() will be very bad as the enemy would just stick to the wall.

So I managed to make a bit of progress (I think). I found that if you send the position of the character from the client to the server via a remote event, it’s far more accurate than pulling the character’s position from the server.

image

In this image, the blue part (hard to see) is client-only (pulls the HRP’s position/CFrame from the client and can’t be seen on the server) and is bound to the RenderStepped event. The green part is server-only (pulls the HRP’s position/CFrame from the server) and is bound to the Heartbeat event. The orange part has a local script with a function bound to RenderStepped that gets the position/CFrame of the HRP, then compares it to a previous value to see if it changed at all, and if it did, uses a remote event to fire it to the server, where a server script changes the part’s position/CFrame to whatever positional data it gets.

I don’t know how this’ll translate to AI pathfinding, or if this is even efficient and can be scaled up, but I have a good feeling. The only data being transmitted is a table of numerical values (CFrame) so I can’t imagine it’ll be too intensive. Feel free to let me know if there’s a way to make this thought process even more accurate or efficient, I’m just going off of what little I know.

1 Like

I completed this test with pathfinding, which garners better, but not perfect results. The AI does get slightly closer, but it doesn’t ever actually touch you. However, I noticed something that recontextualized the whole problem for me; @TimeVector actually mentioned it earlier and I didn’t catch on until I saw it for myself. When running a test server, the AI caught up to me quickly on the server, but never on the client.

In the picture below is the same moment in time viewed from the client (left) and server (right):
image

If I’m making a zombie game as I said, and these dummies are meant to be attacking you and draining your health, then I don’t see the point in making them super-accurate for every client when they work just fine as is. I was under the misguided assumption before that they weren’t reaching you even on the server, meaning they could never attack you, but that’s incorrect. How far you want to go with making the AI line up with you on the client is up to you, but personally, I’m satisfied with the remote-event-provided positional data system I tested. I’ll mark this as the solution unless someone gives a better solution that doesn’t take a lot of effort to implement. For me, messing around with the client could get really complex really fast in a multiplayer game like I’m making.

4 Likes