Customize Path Following Every Tick

Modify standard Unreal Engine pathing via C++ to introduce customized path following behavior without rewriting the who.

Updated over 2 years ago Edit Page Revisions

Overview

600px

Original Author: ()

Dear Community, As gif above shows there is a way to modify standard UE4 pathing via C++ to introduce customized path following behavior without rewriting the whole system!

In gif above I am telling the unit how to jump from one nav mesh piece to another using only C++ (nothing was placed in the editor other than basic nav mesh, and I can add new level geometry any time)

I am also drawing each UE4 Nav Area that the unit is passing through, and I use Nav Mesh Traces + the area info to identify how the unit should jump, and at what angle, to path over terrain that requires jumping.

The point of this wiki is that my method involves only C++ code and a custom Path Following Component.

I am adding to the stock UE4 code, keeping its benefits, while introducing my own custom path following mechanics.

Rama C++ AI Jumping Video

I used the code structure I am describing in this wiki to train my AI to do jump pathing calculations using just UE4 C++!

More Rama AI Jumping Videos

Rama Video ~ Training PhysX Simulating Balls to Navigate Narrow Ledges!

In this video you can see that I use a custom path following component ( as explained in this wiki ) to enable PhysX simulating characters to navigate narrow ledges!

Steps

You need to do several things

Have your own Custom ai controller (extends AAIController)

Here's the required header info

#pragma once

//Super
#include "AIController.h"

#include "JoyController.generated.h"

UCLASS() 
class AJoyController : public AAIController
{ 
    GENERATED_BODY()
public:
    AJoyController(const FObjectInitializer& ObjectInitializer);

Tell ai controller to use custom path following component, which extends the base UE4 class

Here's the code for that, you just modify the constructor

//      UJoyPathFollowComp is used here!
AJoyController::AJoyController(const FObjectInitializer& ObjectInitializer)
   : Super(ObjectInitializer.SetDefaultSubobjectClass(TEXT("PathFollowingComponent")))
{

Make sure your build.cs is including AIModule as part of your dependencies

PublicDependencyModuleNames.AddRange(new string[] { 
    "Core", 
    "CoreUObject", 
    "Engine", 
    "InputCore" ,
        "Landscape",
       "UMG",

        "PhysX",  "APEX",

    "AIModule"      //GetNavigationSystem();
        if(!NavSys) return NULL; 
        return NavSys->GetMainNavData(CreateNewIfNoneFound);
    }

    //Choose Which Nav Data To Use
    FORCEINLINE const ANavigationData* JoyGetNavData() const
    {
        const FNavAgentProperties& AgentProperties = MovementComp->GetNavAgentPropertiesRef() ;
        const ANavigationData* NavData = GetNavDataForProps(AgentProperties) ;
        if (NavData == NULL)
        {
            VSCREENMSG("ERROR USING MAIN NAV DATA"); 
            NavData = GetMainNavData();
        }
           
        return NavData;
    }

//VERY IMPORTANT FOR CRASH PROTECTION !!!!!
FORCEINLINE bool TileIsValid(const ARecastNavMesh* NavMesh,int32 TileIndex) const
{
    if(!NavMesh) return false;
    //~~~~~~~~~~~~~~
    const FBox TileBounds = NavMesh->GetNavMeshTileBounds(TileIndex);
    
    return TileBounds.IsValid != 0;
}

//add this to your custom path follow component!
bool NavPoly_GetAllPolys(TArray& Polys);
//Rama's UE4 Nav code to get all the nav polys!
bool UJoyPathFollowComp::NavPoly_GetAllPolys(TArray& Polys)
{
    if(!MovementComp) return false;
    //~~~~~~~~~~~~~~~~~~
    
    //Get Nav Data
    const ANavigationData* NavData = JoyGetNavData();
     
    const ARecastNavMesh* NavMesh = Cast(NavData);
    if(!NavMesh)
    {
        return false;
    }
    
    TArray EachPolys;
    for(int32 v = 0; v < NavMesh->GetNavMeshTilesCount(); v++)
    {
        
                //CHECK IS VALID FIRST OR WILL CRASH!!! 
               //     256 entries but only few are valid!
                // use continue in case the valid polys are not stored sequentially
        if(!TileIsValid(NavMesh,v)) 
                {
                    continue;
        }   
    
        NavMesh->GetPolysInTile(v,EachPolys);
    }   
      
    
    //Add them all!
    for(int32 v = 0; v < EachPolys.Num(); v++)
    {
        Polys.Add(EachPolys[v].Ref);
    }
}

Conclusion

Have fun writing your own custom Path Following code that integrates with the UE4 standard Path Following code!

Now you can extend the wonderful foundation that the AI engineers at Epic built for you!

Enjoy!

()