Intro
In case you aren't familiar with Patrol Paths in RPGB, here's quickly how they work.
You create a game object in the scene and assign a PatrolPath script to it. From there you can add Points for your AI to patrol.
Next you need to configure a PatrolTemplate and configure your AI in RPGB so it uses the Patrol state logic. Once that's all done it will spawn, go on patrol, and be happy.
Behind the scenes, in order for your NPC to find the PatrolPath you created, there is GameObject.Find("...") code that will load the FIRST instance of a PatrolPath in your game scene that matches the name you assigned to the PatrolPathName field in the template.
But there is a lingering problem for me with just this default behavior. If you don't use a unique name for the PatrolPath you put in the scene, the GameObject.Find("...") will only ever pull one PatrolPath, and so all the mobs who share a PatrolPath with that name will go down the same path.
Now's a good time to watch a video so you can see what I mean in action:
The expected approach designed in RPGB is to use unique names for PatrolPaths. That's a good idea if there are only a few patrol paths in your game. But if you want to put hundreds/thousands of patrol paths down you will need to create a template for each one, and also maintain unique names for all of them. That happens to be my use case. What I'm doing is maintaining a set of RPGB AI templates, and don't want to duplicate them for just a naming difference between PatrolPaths.
So here's my approach:
Tag the PatrolPath game object. I called the tag NPCPatrolPath.
In the AIStatePatrol.cs script you do a few things:
Get all the tagged PatrolPaths and put them in a PatrolPathsArray.
Get the distance between the newly spawned AIEntity and all of the tagged GameObjects in the PatrolPathsArray.
Get the closest PatrolPath and assign it to the AIEntity.
As long as your NPC spawns on top of the first patrol point you want them to start patrolling from, this approach will work. You can achieve this by putting the Starting Point and PatrolPath on top of each other in the prefab. You can see how I structured my prefab in the screenshot below.
In this post I didn't implement the Random PatrolPath component available in the PatrolTemplate. At the end of this post there's a link to the code that implements the Random component.
Note: You won't be able to follow along with this post unless you already own a copy of RPG Builder. Please check out our RPG Builder Resource post to learn more about the product.
As always, backup and version control your projects before modding them.
Disclaimer: There is no guarantee or future support offered regarding these changes. I tested them out at the time I wrote them, and they worked within the scope of my needs. However, I am not the author of RPGB and therefore am not the authoritative source on whether these mods are complete. Use at your own risk. Reach out to me on Discord (iNSiPiD1) if you have any thoughts or suggestions about this mod.
Modded RPGB v2.0.6. New code additions are always highlighted in green, whilst RPGB code is always highlighted in blue.
Mod AIStatePatrol.cs
We're using linq so first include the proper using statement at the top of the file:
using System.Linq;
Next, inside the Initialize() method we replace these lines
... (inside the Initialize() method around line 33)
patrolPath = patrolTemplate.RandomPath ? GameObject.Find(patrolTemplate.PatrolPathNames[Random.Range(0, patrolTemplate.PatrolPathNames.Count)]).GetComponent<PatrolPath>()
: GameObject.Find(patrolTemplate.PatrolPathName).GetComponent<PatrolPath>();
...
with these:
var patrolPathArray = GameObject.FindGameObjectsWithTag("NPCPatrolPath");
float[] patrolPathDistances = new float[patrolPathArray.Length];
for (int i = 0; i < patrolPathDistances.Length; i++)
{
patrolPathDistances[i] = Vector3.Distance(ThisAIEntity.transform.position,
patrolPathArray[i].transform.position);
}
if (patrolPathArray.Length == 0)
{
// Invoke RPGB default if no patrols are tagged and notify the console
Debug.Log("You didn't tag any patrol paths in this scene. Using default behavior.");
patrolPath = patrolTemplate.RandomPath ? GameObject.Find(patrolTemplate.PatrolPathNames[Random.Range(0, patrolTemplate.PatrolPathNames.Count)]).GetComponent<PatrolPath>()
: GameObject.Find(patrolTemplate.PatrolPathName).GetComponent<PatrolPath>();
}
else
{
var closestPatrolPathIndex = Array.IndexOf(patrolPathDistances, patrolPathDistances.Min());
patrolPath = patrolTemplate.RandomPath ? GameObject.Find(patrolTemplate.PatrolPathNames[Random.Range(0, patrolTemplate.PatrolPathNames.Count)]).GetComponent<PatrolPath>()
: patrolPathArray[closestPatrolPathIndex].GetComponent<PatrolPath>();
}
The End
With this mod you can create prefabs out of Patrol Paths, something that would be hard to manage without using the tag-based approach outlined here.
If you liked this mod, then check out how to add randomness in the next post.
Comments