Navigation blocking issue with my NPC

Hi guys, I don’t know if anyone can help me with a Navigation problem I’m having with my NPC.
I have a fully working Verse code that I tested multiple times, where I had to create and link my NPC definition, the basic locomotion anim preset (for walking animations, etc.), and an Actor Blueprint for my custom NPC.
The NPC moves using “patrol points,” which are Blueprints (CreativeProps). Everything works fine at the start…

I placed some Navigator AIs so the NPC can correctly detect which areas it can access or not. I also used the Debug function during test sessions to check if the NPC could reach certain areas — and it can.
But I don’t understand why sometimes it randomly gets stuck in certain spots.

I already disabled the “can climb on this” option on my meshes (like walls), set their collisions to Block All, and put small decorative elements to Overlap to avoid navigation calculation bugs.
If anyone has an idea or a fix, I’m all ears — I can also send screenshots if needed. Thanks in advance :heart:

using { /Fortnite.com/Devices }

using { /Verse.org/Simulation }

using { /UnrealEngine.com/Temporary/Diagnostics }

using { /Verse.org/Random }

using { /Fortnite.com/Characters }

using { /Fortnite.com/AI }

using { /Fortnite.com/AI/movement_types }

using { /UnrealEngine.com/Temporary/SpatialMath }





NPC_Parameter := struct<concrete>() :

    @editable DistanceDeVueMax : float = 1000.0 # 100.0 = 1 meter

    @editable RayonDeMort : float = 200.0 # 100.0 = 1 meter

    @editable TempsAvantPouvoirTuez : float = 5.0

    @editable PatrolPoints : []creative_prop = array{}

    @editable PropAttacherAuMonstre : creative_prop = creative_prop{}

    

    @editable QuandLeMonstreTue : trigger_device = trigger_device{}

    @editable QuandLeMonstreMarche : trigger_device = trigger_device{}

    @editable QuandLeMonstreCourt : trigger_device = trigger_device{}

    

    # Add safe zones

    @editable SafeZones : []volume_device = array{}




DollHorror := class(creative_device):




    @editable Npc_Spawner : npc_spawner_device = npc_spawner_device{}

    @editable Parameter : NPC_Parameter = NPC_Parameter{}




    var Npc : ?agent = false




    var IsPatrol : logic = false

    var CanKill : logic = true




    OnBegin<override>()<suspends>:void=

        Npc_Spawner.SpawnedEvent.Subscribe(QuandLeNPCApparait)




    AttachProp(PositionTarget:vector3,RotationTarget:rotation)<suspends>:void=

        if(Parameter.PropAttacherAuMonstre.TeleportTo[PositionTarget, RotationTarget]):




    QuandLeNPCApparait(Agent:agent):void=

        set Npc = option{Agent}

        spawn{CommencerLeSysteme()}




    CommencerLeSysteme()<suspends>:void=

        if(Npc?):

            loop:

                Sleep(0.1)

                M_EssayerDeTrouverUneCible := EssayerDeTrouverUneCible()

                if(JoueurCibleActuel:=M_EssayerDeTrouverUneCible? , PositionDeCible := JoueurCibleActuel.GetFortCharacter[].GetTransform().Translation ):

                    spawn:

                        BougerNPC(PositionDeCible,true)

                    Print("Cible Trouver", ?Duration:=6.0)

                else:

                    Print("essay de patrol", ?Duration:=6.0)

                    spawn{PatrolNpc()}

                if(CurrentNPC := Npc? , CurrentNpcCharacter := CurrentNPC.GetFortCharacter[]):

                    spawn:

                        AttachProp(CurrentNpcCharacter.GetTransform().Translation,CurrentNpcCharacter.GetTransform().Rotation)




    # Check if player is in any safe zone

    IsPlayerInSafeZone(Player:player)<transacts>:logic=

        for (SafeZone : Parameter.SafeZones):

            if (SafeZone.IsInVolume[Player]):

                return true

        return false




    EssayerDeTrouverUneCible():?player=

        var JoueurCibler : ?player = false

        for (Player : GetPlayspace().GetPlayers() ) :

            if( NpcAgent := Npc? , NpcCharacter := NpcAgent.GetFortCharacter[] , NpcCharacter.IsActive[] , Playercharacter:=Player.GetFortCharacter[] , Playercharacter.IsActive[]):

                # Skip players in safe zones

                if (IsPlayerInSafeZone(Player) = true):

                    Print("Player in safe zone - skipping")

                else:

                    PositionDuPlayer := Playercharacter.GetTransform().Translation

                    PositionDuMonstre := NpcCharacter.GetTransform().Translation

                    if( Distance(PositionDuPlayer, PositionDuMonstre) <= Parameter.RayonDeMort ) :

                        Print("Player a etait tuer!")

                        spawn{TuerUnJoueurTropProche(Playercharacter)}

                    else if ( Distance(PositionDuPlayer, PositionDuMonstre) <= Parameter.DistanceDeVueMax ):

                        set JoueurCibler = option{Player}

        if(NouvelleCible := JoueurCibler?):

            return option{NouvelleCible}

        else:

            return false




    PlusBougerNPC()<suspends>:void=

        Print("NPC Bouge Plus!")

        if ( NpcAgent := Npc ? , Character := NpcAgent.GetFortCharacter[], Nav := Character.GetNavigatable[]):

            Result := Nav.StopNavigation()




    BougerNPC(Target:vector3,IsRunning:logic)<suspends>:void=

        Print("NPC Bouge!")

        if ( NpcAgent := Npc ? , Character := NpcAgent.GetFortCharacter[], Nav := Character.GetNavigatable[]):

            if(IsRunning=true):

                Parameter.QuandLeMonstreMarche.Reset()

                Parameter.QuandLeMonstreCourt.Trigger()




                Result := Nav.NavigateTo(MakeNavigationTarget(Target),?MovementType := Running , ?ReachRadius := 50.0)

                case(Result):

                    navigation_result.Reached => 

                        Print("NPC reached the target!")

                        set IsPatrol = false

                    navigation_result.Unreachable => 

                        Print("NPC can't reached the target!")

                        set IsPatrol = false

                    _ =>

            else:

                Parameter.QuandLeMonstreCourt.Reset()

                Parameter.QuandLeMonstreMarche.Trigger()




                Result := Nav.NavigateTo(MakeNavigationTarget(Target),?MovementType := Walking , ?ReachRadius := 50.0)

                case(Result):

                    navigation_result.Reached => 

                        Print("NPC reached the target!")

                        set IsPatrol = false

                    navigation_result.Unreachable => 

                        Print("NPC can't reached the target!")

                        set IsPatrol = false

                    _ =>

                        

    PatrolNpc()<suspends>:void=

        if(Parameter.PatrolPoints.Length > 0 , IsPatrol = false):

            set IsPatrol = true

            RandomPatrolIndex := GetRandomInt(0,Parameter.PatrolPoints.Length-1)

            if(RandomPatrol:=Parameter.PatrolPoints[RandomPatrolIndex]):

                spawn{BougerNPC(RandomPatrol.GetTransform().Translation,false)}




    TuerUnJoueurTropProche(Playercharacter:fort_character)<suspends>:void=

        if(CanKill = true):

            set CanKill = false

            Playercharacter.Damage(200.0)

            Parameter.QuandLeMonstreTue.Trigger()

            Sleep(Parameter.TempsAvantPouvoirTuez)

        set CanKill = true