Patrolling in Formations

zach.fransen

New member
My general objective is to have a behavior where a group of enemies self-organizes into a formation and patrols multiple waypoints.

Now, I did accomplish this, but I'm thinking the way I approached it may not have been ideal.

I combined the Patrol task from the movement pack with the column task from the formations pack. I went ahead and had these run in parallel, with some modifications.

I neutered the patrol class to have it set a Vector3 shared variable instead of setting destination via the navmeshagent. I also modified the FormationGroup class to have it so that it doesn't end when the formation reaches the destination. I then had the formation task reference the Vector3 set by the patrol task in order to have the crew move around appropriately and the results seem reasonably good. I feel comfortable inheriting from the patrol task instead of modifying it directly, and I can override the appropriate method in my code. However, I don't see a great way to influence the FormationGroup.cs logic without having to override each individual formation or I can yank out a lot of distance calculation and coordination logic and make my own custom formation task, but that's not awesome.

Feel free to tell me what I did was silly and there's a configuration option I missed or some other suggestion.

1680472741379.png
 
One of my goals for the next major update of the Formations Pack is to make it more extensible, but from your description it sounds like you've done all that you can. Looking at your tree the only thing that I notice is that you are running both the Patrol task and the Column task in parallel if the agent is the leader. In this situation both of the tasks will try to control the destination so I'm not sure why that works - you should only need the Patrol task. With that said, it may be related to how you have modified the formations task.
 
Preface-- my understanding of the code may be imperfect here, so if any conclusion I'm drawing is incorrect, please just let me know.

I did try with just the Patrol task on the leader side of the behavior tree, but it seems like the functionality around providing instructions out to the members of the formation is in the formation task (starts on line 303 of FormationGroup.cs). So if that task isn't running for the leader, the rest of the members just sit there--

if (formationStarted) {
// Notify following agents if the target position has updated.
if (targetTransform.Value != null) {
if (targetTransform.Value != prevTargetTransform) {
prevTargetTransform = targetTransform.Value;
for (int i = 1; i < formationTrees.Count; ++i) {
formationTrees.SendEvent("UpdateTarget", targetTransform.Value);
}
}
} else if (targetPosition.Value != prevTargetPosition) {
prevTargetPosition = targetPosition.Value;
for (int i = 1; i < formationTrees.Count; ++i) {
formationTrees.SendEvent("UpdateTargetPosition", targetPosition.Value);
}
}


As you surmised, I did make two changes to get them to work in parallel without fighting for the NavMeshAgent destination (via NavMeshMovement). One change was to Patrol.cs and the other to FormationGroup.cs. On Patrol, I added a SharedVector3 property to the class then just had Patrol set that instead of the NavMeshAgent on line 70:

//SetDestination(Target());
targetPosition.Value = Target();

Understood that this isn't a good general implementation, which is why I will subclass and have it as a standalone task for patrolling in formation specifically or have a shared boolean that changes the behavior, but I'm loathe to modify your code directly in final state.

On the FormationGroup side, I just need the task to continue functioning even when the formation reaches their destination by commenting out lines 358 to 361, which is not a great general implementation and could also be conditioned on a shared boolean that could drive the behavior:


//if (arrived) {
// runStatus = TaskStatus.Success;
// return runStatus;
//}

End result:
 
Top