Hey yall I did a deep dive into how my behavior tree works!
I am going to post more tutorials for how to install btrees5 and nevermore soon.
Hi,
Looks pretty cool.
So you are using a customized pathfinding? How are you getting it to pause and then get ready to eat?
Also what is ‘btrees5 and nevermore’ used for?
Thanks
Hiya,
For the actually pathfinding, I am using native roblox pathfinding—looping through all the waypoints and calling humanoid:MoveTo()
. But I have built a lot of helpful things on top of roblox to make it easier for my game like wrapper functions inside my npc navigation class e.g humanoid:MoveTo()
is used multiple times for things like navigation:PathToTarget()
or navigation:PathToRandomTarget()
. Additionally my pathfinding is tied to using Behavior Trees to determine if a npc succeed
, failed
, or is currently running
on the path to its target.
In regards to the pausing, that is due to my behavior tree via the BTrees5 plugin by Defaultio. In a behavior tree you set up a sequence of tasks to do. So like: Path, Wait, Eat. The behavior tree will know what do based on the order of tasks. Its very useful for a more advanced AI. In the video at [1:55] you can see how eating is performed and on the very right side you its says Wait
before the Eat
task.
To reiterate, Btrees5 is the plugin for using behavior trees in Roblox. Its great! I don’t a video explaining it but I highly recommend watching this video by Paul1Rb https://www.youtube.com/watch?v=_GavB4qIIJA . He has a very dense video on how to use behavior trees in general.
Nevermore is one of the beasts of Roblox programming. You can think of it as a library or collection of code with very helpful scripts like the Draw library for displaying raycast or region queries. But one of its most powerful libraries is the bootstrapper aka loader library. It sets up your code files so that you can require scripts by string name instead the file location. Here is the doc for loader Loader | Nevermore so you can see it.
Ok, thanks I will check some of the things out.
Can your npcs in real time go to waypoints that move during the game? A lot of pathfinding systems I have seen cannot goto a way point that moves during the play, they instead move the the original position before the waypoint was moved and do not go to the new position.
During real time, can they go to new waypoints that are generated during the game play? verses static waypoints that are pre determined at run time.
Also I saw the door open when the NPC gets there. I have made a door system for npcs, but wondering on yours, is it triggering a point before the door that opens it and the door (at least for the NPC) has collision off?
Thanks, I like that you shared the background logic of what you have created.
Yes, my npc can follow a target. I have that logic in a different behavior tree for the chase behavior. If you watch the video at [4:53]. You can see a glimpse of that logic. Its an older version, which is why there are not doors, but you can see what its doing based on the emoji above Pepe’s head.
:) state
means pepe is going to random positions in a random room
>:) state
means pepe is following target
The switching of these states
is why behavior trees are so powerful.
To help you specifically, you need to update your targetPosition.
Store two variables:
target
as a reference to the target instance e.g. the player
targetPosition
as a reference to the last target position you are pathing to
Then you check the distance between targetPosition
and target.Character.PrimaryPart.Position
to see if its greater than say 5 studs. If it is, update targetPosition
to the new value and repath. Else continue as normal.
The doors is alot more complicated to explain. But in concept. I’m using a combination of things:
1. collisiongroups
to separate collision with assets like doors and the parts I use to clean the navMesh
so its grouped by rooms via pathfindingModifiers
and Labels
.
2. using pathfindingLinks
to do actions
based the label
. Also since my navMeshes
are separated by rooms, it makes links
much easier to use. The only thing that connects rooms are the links
. So it must use that door to go next room.
3. referencing my objectserivce
—which is my collection of objects my npc can use—to dynamically give me the specific door object class I need to call that door’s open/close function.
mmm ok… I have not worked with Navmeshes before … to get my door system working it was pretty complicated also, but I also wanted the door to collide with the NPC so that like if it was partially open by a player, they could not just go through it…
thanks again for the details…
Ahh, yes. Physics on doors is definitely harder. I tried that at first, but I found it was not important enough to our game to justify spending the time to solve that problem.
Glad I was able to help ya tho.
Do you know if there is a way of queueing waypoints, in that if it is going to say waypoint 2, you can already have waypoint 3 set up as the next priority , even if as it is going to waypoint 2 , it does not know about 3 yet? because there is no clear path to 3, until it gets to 2?
I was wondering also with the queueing if this might eliminate some of the delays (note I also read one of the other posts you were in about npc stuttering ) …
For this issue there 3 possible solutions I can give:
-
The roblox method. What it seems like you are trying to do is implement your own
PathfindingLink
PathfindingLink | Documentation - Roblox Creator Hub. But I would recommend conforming to roblox and using it like this Character Pathfinding | Documentation - Roblox Creator Hub.
Links
are specifically made to connect untraversable areas. So if you put a Link
between 2 NavMeshes
the internal roblox PathfindingService
will know to go to your Link
to reach the next area.
It will trust that the Action
associated to that Link
will be handled by you. So if its a ocean away: teleport to boat, tween to end position, teleport to land; ifs its a broken wall: play crouch animation, call humanoid:MoveTo(holeEndingPosition)
or humanoid:Move(holeEndingPosition)
, ifs its a door: open door, humanoid:MoveTo(doorEndingPosition)
or humanoid:Move(doorEndingPosition)
.
The choice of using Move()
or MoveTo()
will be determined by how traversable your in-between zone is.
-
The custom way. You can ignore the roblox and make your own, which will potentially be harder and lead to more bugs. But essentially you set up a
"trigger box"
which will act as theLink
. Usingtouched
on this part is not advised for performance. Rather in your code have a table of all thesetrigger boxes
and store functions for how your npc will use thetrigger box
to move locations.
When you want to use it, force the npc to go to walk to trigger box 1
and use the associated function to cross zones to trigger box 2
. However, the real complexity arises when chasing a player and using it dynamically as npc attempts to follow a player across zones.
For this, you must check your target positions
before trying to Path or else it will fail. Figure out where our npc wants to go. If its in the next area. Take control and move between zones. Then Resume letting the npc follow the player.
This is just one way to do it and I am probably over-looking some things as well in this implementation. But trust it will be hard.
-
The dirty easy way.
Waypoints
are tables in an ordered array format. You can also have multiplePaths
Path | Documentation - Roblox Creator Hub . CreatewaypointsTable1
andwaypointsTable2
. Then combine thewaypoints
where you want them. Overall this will get complicated QUICK tho.
Also the studder is a network ownership issue. Animations not should be played over the server. Rather be handled on client side.
The reason why it happens is because when something is owned by the server, the npc body must wait to replicate all physics aka motion to all clients. Which causes that brief moment of non-movement which stops the animation.
Once an owner is set to a cilent, animations will smooth for that person. Others will probably see the stutter still. This can also be relived by extending the waypoint distance or entirely fixed by making your own animation script that will just play regardless of physics.
mm, ok some more things for me to research.
for option 3, if the door has collide on for everyone, and the door is closed, I thought then the NPC will not know about any way point inside of the room when the door is closed…
but anyhow, great info, to me it seems a custom combined system is needed to get through all the various logic
hmm, I thought I saw people were setting the npc network ownership to nil… how is it set to the client, and then what if there are multiple clients around the npc, does every client then get the ownership?
Depends how you set up PathfindingModifiers
and CollisionGroups
. You can still have collisions
on the door, but have `PathfndingModifer’ that say yes you can still pass through this door. The NPC will walk into it now regardless of the door.
Right, but then it does not collide with the door… which I wanted it to , like if the door is being opened it pushed the NPC, and or if the door is open like at a 90 deg, it has to walk around it… it would look goofy if it walked through it when it was open at 90 deg…
I messed around with the way roblox say do to it, like you say and it just walk though it , unlike a player… which would not be cool to players if it was a pvp shooter or even anything… like if the player is in the room, cannot see the npc and it walks though the door…
and ya, what you need then is a trigger system like you have…but if the npc is coming along the wall parrell to the door, and it triggers the door open, then it would walk through it as it opens?.. or when you trigger it could turn a second part the size of the door to collide on, then perhaps the NPC has to recompute around the door… then if the door is closed, turn collide off on the second part and the npc can stilll compute into the room…
that might work…
the other challenge with above, is that then the npc is opening the door sometime when it is not really near enough to open the door… which I have seen in other non roblox games and that again if goofy looking… so you could have a trigger point with a slight delay…
(and wow roblox just said I cannot do more then 3 replies in a row, until I get a reply, so I have to edit the last one)
and now I lost my train of thought… which was doors that slide open…not open out or inward…
Network Ownership
is derived from all BaseParts
BasePart | Documentation - Roblox Creator Hub . Here is some info on it: Network Ownership | Documentation - Roblox Creator Hub
By setting it to nil
you are overriding automatic ownership to explicitly use the server as the owner. Which will cause the issue. You can do this if you want, but you MUST make a custom client animation script that fires signals to all clients on which animation to play for the npc on their screen. This may be the easier solution you may want.
Edit: The stutter occurs when you have server animation but a client takes ownership. Causing the server to wait for physics updates from the client, producing the stutter.
- To fix this either dedicate to pure server logic by setting ownership nil, but I HIGHLY RECOMMEND making a custom client animation script that fires signals to all clients on which animation to play for the npc on their screen. Animations are a heavy process.
- Or create your own auto ownership system to pass the ownership between clients. It is okay to have the server handle physics but be mindful of the stress your game puts on the server and how it affects your core gameplay. You ought to minimize your server work to only wants needed for fast performance. So it still HIGHLY RECOMMEND create a custom client animation script.
To set to a client, give it the player instance. But as you noticed too, it becomes difficult to say who should get the best physics. This is a problem beyond Roblox and is a general Server/Client issue across all networked games. This is why in games in general you can float out of cars when its moving fast.
I don’t know a good solution for this, but it is common to go by closet proximity or who ever is prioritized, say the player its chasing.
Also remember! Network Owner
is for all BasePats
so make sure to iterate through your entire npc and set all basePart's
ownership.
hmm, I’ll have to look at one of my npc codes… I could have sworn that’s what people were saying to do,
what happens to the NPC if you give to the nearest client and the player dies? does it automatically revert to something else?
Ah yes, you are right. So that means you definitely want your navMesh
to take into account the doors position, so it can walk around or open when its closed. And if thats the case, then you need something like a link
or trigger box
to say these areas are still traversable when the door is closed.
This is the post I was reading where you are in the last comment Pathfinding NPC stuttering - #15 by F0xBirdmansBFF
and yes the dude you replied to says to set the networkownership to the client and then the guy below the guy you replied to says to do it on the server… and the original poster was setting it to nil…
ah good times…
well thanks for the chat and info… I shall now mosey off to bed and dream of npcs getting stuck at a door… but you and I have fixed that issue… somewhat…
Oh oh oh my mistake, I was partially wrong here. It does get confusing. I missed remembered. This was all a lot of info dumping at one time lol.
Context: this was issue before that post.
So for me, I got the stutter consistently after 1 min in game. Which baffled me, because it looked clean and stutter-free before 1 min.
The issue was caused by default roblox ownership being is set to auto. So as a player stays in the game their domain of ownership expands, taking objects from the server as it grows. Which for me happend around the 1 min mark.
At the time, my npc was instantiated on server and used server animations. Which worked great when the Server had ownership from auto. But the moment the client owned it, it lagged, because nowww the server to needs to wait for the cilent to handle the physics.
Sorry, for the wrong info before. Sooooooo
Setting to ownership to nil, will make it work.
You are forcing physics to be handled server side. But be wary as your server will lag if you have too many npcs relaying on server physics and animations. Which is why you still want a make a client animation script. In general animations should never be played on the server, its alot to handle.
By doing so you will let your server focus on more core gameplay elements like door physics, or precise bullet hit detection.