so I found this post on reddit
but its written for a prop monster but it got me thinking can i use this for player behaviour?
this is what i have so far
npc_state_machine
using { /Fortnite.com/AI }
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Fortnite.com/Playspaces }
using { /Verse.org/Simulation }
using { /Verse.org/Colors }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
# Credit to u/Natural_Lemon_1459 from reddit for posting his state machine
# A Verse-authored NPC Behavior that can be used within an NPC Character Definition or an NPC Spawner device's NPC Behavior Script Override.
npc_state_machine<public> := class(npc_behavior):
var CurrentState:[]char = "Patrol"
# reference to utility scripts we're gonna need
var NPCUtilities : npc_utilities = npc_utilities{}
# this is the base example when you generate a behavior we need it for AI debug modules
var ExampleNPCBehavior : new_npc_behavior = new_npc_behavior{}
var IsMoving : logic = false
var LostTarget : logic = false
@editable ActivationRange : float = 3500.0
@editable AttackRange : float = 150.0
@editable ChaseRange : float = 1000.0
@editable SearchTimer : float = 10.0
# This function runs when the NPC is spawned in the world and ready to follow a behavior.
OnBegin<override>()<suspends>:void=
# TODO: Replace this with your code
Print("Hello, NPC!")
NPCBehaviorLoop()
NPCBehaviorLoop()<suspends>:void =
if:
# Get the Agent (the NPC).
Agent := GetAgent[]
# Gets the Fortnite Character interface, which gets you access to its gameplay data
# including its AI module for navigation and focus.
Character := Agent.GetFortCharacter[]
# Get the Navigatable Interface, this allows you to tell it to move.
Navigatable := Character.GetNavigatable[]
# Get the Focus Interface, this allows you to tell it to look at something or somewhere.
Focus := Character.GetFocusInterface[]
then:
loop:
UpdateState()
#GetAllPlayers()
if (CurrentState = "Dead"):
Print("I'm Dead")
Sleep(30.0)
# Handle NPC Behavior
if(CurrentState = "Patrol"):
Print("Patrolling")
Sleep(1.0)
else:
if(CurrentState = "Chase"):
Print("Chasing")
if(IsMoving = false):
ChaseClosestPlayer()
set IsMoving = true
Sleep(1.0)
else:
if(CurrentState = "Attack"):
Print("Attacking")
#todo add attack stuff
Sleep(1.0)
Sleep(1.0)
UpdateState()
UpdateState():void=
var Searching : logic = false
Ref := GetClosestPlayer()
AllPlayers := NPCUtilities.GetAllPlayers()
if(ClosestPlayer := AllPlayers[Ref]):
PlayerDistance := CheckPlayerDistance(ClosestPlayer)
#Print("Closest Player Distance = {PlayerDistance}")
if(PlayerDistance < AttackRange):
set CurrentState = "Attack"
else:
if(PlayerDistance < ChaseRange ):
set CurrentState = "Chase"
else:
set CurrentState = "Patrol"
GetNPCLocation():vector3=
var NPCLocation :vector3 = vector3{}
if:
# Get the Agent (the NPC).
Agent := GetAgent[]
Character := Agent.GetFortCharacter[]
set NPCLocation = Character.GetTransform().Translation
return NPCLocation
WalkToTarget(TargetPlayer:player)<suspends>:void=
if:
# Get the Agent (the NPC).
Agent := GetAgent[]
# Gets the Fortnite Character interface, which gets you access to its gameplay data
# including its AI module for navigation and focus.
Character := Agent.GetFortCharacter[]
# Get the Navigatable Interface, this allows you to tell it to move.
Navigatable := Character.GetNavigatable[]
# Get the Focus Interface, this allows you to tell it to look at something or somewhere.
Focus := Character.GetFocusInterface[]
then:
if(ExampleNPCBehavior.ShowAIDebug?):
Print(new_npc_behavior_message_module.OnBeginMessage(Agent), ?Duration := ExampleNPCBehavior.AIDebugDrawTime)
loop:
# Create a navigation target from these two positions that the navigation interface can use.
NavTargetStart := MakeNavigationTarget(GetNPCLocation())
NavTargetEnd := MakeNavigationTarget(GetClosestPlayerLocation())
# If the debug flag is enabled draw a box around the location the NPC is moving toward for visual
# validation that it is where you expect.
if(ExampleNPCBehavior.ShowAIDebug?):
ExampleNPCBehavior.DrawDebugLocation(GetNPCLocation())
# Tell the navigation interface to walk to the location and store a navigation result for error checking.
NavResultGoTo := Navigatable.NavigateTo(NavTargetStart, ?MovementType:=movement_types.Walking)
NavTarget := MakeNavigationTarget(TargetPlayer)
NavResultGoToNext := Navigatable.NavigateTo(NavTarget, ?MovementType:=movement_types.Walking)
# Check to see if something has interfered with the NPC reaching the intended location and print a
# message to the output log.
if (NavResultGoTo = navigation_result.Unreachable):
if(ExampleNPCBehavior.ShowAIDebug?):
Print(new_npc_behavior_message_module.OnNavigateErrorMessage(Agent,GetNPCLocation().X,GetNPCLocation().Y,GetNPCLocation().Z), ?Duration := ExampleNPCBehavior.AIDebugDrawTime)
else:
# Once it arrives at its location, wait for this duration in seconds
Navigatable.Wait(?Duration := ExampleNPCBehavior.MoveToWaitDuration)
# End of loop, continue the patrol back to the point.
else:
# If code falls here something failed when gathering the agent or its interfaces
if(ExampleNPCBehavior.ShowAIDebug?):
ExampleNPCBehavior.PrintNPCB("Error in NPC Behavior Script on NPC Setup",
?Duration := ExampleNPCBehavior.AIDebugDrawTime,
?TextColor := NamedColors.Red )
MoveToTarget(TargetPlayer:player)<suspends>:void=
if:
# Get the Agent (the NPC).
Agent := GetAgent[]
# Gets the Fortnite Character interface, which gets you access to its gameplay data
# including its AI module for navigation and focus.
Character := Agent.GetFortCharacter[]
# Get the Navigatable Interface, this allows you to tell it to move.
Navigatable := Character.GetNavigatable[]
# Get the Focus Interface, this allows you to tell it to look at something or somewhere.
Focus := Character.GetFocusInterface[]
then:
if(ExampleNPCBehavior.ShowAIDebug?):
Print(new_npc_behavior_message_module.OnBeginMessage(Agent), ?Duration := ExampleNPCBehavior.AIDebugDrawTime)
loop:
# Create a navigation target from these two positions that the navigation interface can use.
NavTargetStart := MakeNavigationTarget(GetNPCLocation())
NavTargetEnd := MakeNavigationTarget(GetClosestPlayerLocation())
# If the debug flag is enabled draw a box around the location the NPC is moving toward for visual
# validation that it is where you expect.
if(ExampleNPCBehavior.ShowAIDebug?):
ExampleNPCBehavior.DrawDebugLocation(GetNPCLocation())
# Tell the navigation interface to walk to the location and store a navigation result for error checking.
NavResultGoTo := Navigatable.NavigateTo(NavTargetStart, ?MovementType:=movement_types.Walking)
NavTarget := MakeNavigationTarget(TargetPlayer)
NavResultGoToNext := Navigatable.NavigateTo(NavTarget)
set IsMoving = false
# Check to see if something has interfered with the NPC reaching the intended location and print a
# message to the output log.
if (NavResultGoTo = navigation_result.Unreachable):
if(ExampleNPCBehavior.ShowAIDebug?):
Print(new_npc_behavior_message_module.OnNavigateErrorMessage(Agent,GetNPCLocation().X,GetNPCLocation().Y,GetNPCLocation().Z), ?Duration := ExampleNPCBehavior.AIDebugDrawTime)
else:
# Once it arrives at its location, wait for this duration in seconds
Navigatable.Wait(?Duration := ExampleNPCBehavior.MoveToWaitDuration)
if(IsMoving = false):
# End of loop, continue the patrol back to the point.
else:
# If code falls here something failed when gathering the agent or its interfaces
if(ExampleNPCBehavior.ShowAIDebug?):
ExampleNPCBehavior.PrintNPCB("Error in NPC Behavior Script on NPC Setup",
?Duration := ExampleNPCBehavior.AIDebugDrawTime,
?TextColor := NamedColors.Red )
SetSearchTimer()<suspends>:void=
loop:
Sleep(SearchTimer)
set LostTarget = true
walkToclosestPlayer():void=
Ref := GetClosestPlayer()
AllPlayers := NPCUtilities.GetAllPlayers()
if(ClosestPlayer := AllPlayers[Ref]):
spawn:
WalkToTarget(ClosestPlayer)
spawn:
SetSearchTimer()
ChaseClosestPlayer():void=
Ref := GetClosestPlayer()
AllPlayers := NPCUtilities.GetAllPlayers()
if(ClosestPlayer := AllPlayers[Ref]):
set IsMoving = false
spawn:
MoveToTarget(ClosestPlayer)
CheckPlayerDistance(Player : player):float =
if (FortCharacter := Player.GetFortCharacter[]):
PlayerLocation := FortCharacter.GetTransform().Translation
NPCLocation := GetNPCLocation()
DeltaX := NPCLocation.X - PlayerLocation.X
DeltaY := NPCLocation.Y - PlayerLocation.Y
DeltaZ := NPCLocation.Z - PlayerLocation.Z
distance := Sqrt(DeltaX * DeltaX + DeltaY * DeltaY + DeltaZ)
Print("Distance = {distance}")
return distance
else:
return -1.0
GetClosestPlayer():int=
# var to hold distance
var LastDistance : float = ActivationRange
# Get Allplayers
AllPlayers:=NPCUtilities.GetAllPlayers()
ClosestPlayer := player
# interger to record the iteration the closest player is found
var PlayerRef : int = 0
# iterate through each player grabbing the fortcharacter
for(CurrentPlayer := 0..AllPlayers.Length):
if (ThisPlayer : player = AllPlayers[CurrentPlayer]):
if (FortCharacter := ThisPlayer.GetFortCharacter[]):
# locations of player & npc
PlayerLocation := FortCharacter.GetTransform().Translation
NPCLocation := GetNPCLocation()
# some fancy ■■■■ to workout distance of 2 vectors
DeltaX := NPCLocation.X - PlayerLocation.X
DeltaY := NPCLocation.Y - PlayerLocation.Y
DeltaZ := NPCLocation.Z - PlayerLocation.Z
distance := Sqrt(DeltaX * DeltaX + DeltaY * DeltaY + DeltaZ)
# check see if distance is less than last distance
if(distance < LastDistance):
# store new shortest distance and playerRef
set LastDistance = distance
set PlayerRef = CurrentPlayer
# I wanted to retun the player but dont know how so i retun the refence to the player position in th players array
return PlayerRef # fill this file with your verse-script
GetClosestPlayerLocation():vector3=
# var to hold distance
var LastDistance : float = ActivationRange
# Get Allplayers
AllPlayers:=NPCUtilities.GetAllPlayers()
ClosestPlayer := player
# interger to record the iteration the closest player is found
var PlayerRef : vector3 = vector3 {X:=0.0,Y:=0.0,Z:=0.0}
# iterate through each player grabbing the fortcharacter
for(CurrentPlayer := 0..AllPlayers.Length):
if (ThisPlayer : player = AllPlayers[CurrentPlayer]):
if (FortCharacter := ThisPlayer.GetFortCharacter[]):
# locations of player & npc
PlayerLocation := FortCharacter.GetTransform().Translation
NPCLocation := GetNPCLocation()
# some fancy ■■■■ to workout distance of 2 vectors
DeltaX := NPCLocation.X - PlayerLocation.X
DeltaY := NPCLocation.Y - PlayerLocation.Y
DeltaZ := NPCLocation.Z - PlayerLocation.Z
distance := Sqrt(DeltaX * DeltaX + DeltaY * DeltaY + DeltaZ)
# check see if distance is less than last distance
if(distance < LastDistance):
# store new shortest distance and playerRef
set LastDistance = distance
set PlayerRef = PlayerLocation
# return location as vector3
return PlayerRef
Idle()<suspends>:void=
if:
# Get the Agent (the NPC).
Agent := GetAgent[]
# Gets the Fortnite Character interface, which gets you access to its gameplay data
# including its AI module for navigation and focus.
Character := Agent.GetFortCharacter[]
# Get the Navigatable Interface, this allows you to tell it to move.
Navigatable := Character.GetNavigatable[]
# Get the Focus Interface, this allows you to tell it to look at something or somewhere.
Focus := Character.GetFocusInterface[]
then:
set LostTarget = false
NavTarget := MakeNavigationTarget(GetNPCLocation())
NavResultGoToNext := Navigatable.NavigateTo(NavTarget)
# Check to see if something has interfered with the NPC reaching the intended location and print a
# message to the output log.
if (NavResultGoToNext = navigation_result.Unreachable):
if(ExampleNPCBehavior.ShowAIDebug?):
Print(new_npc_behavior_message_module.OnNavigateErrorMessage(Agent,GetNPCLocation().X,GetNPCLocation().Y,GetNPCLocation().Z), ?Duration := ExampleNPCBehavior.AIDebugDrawTime)
else:
# Once it arrives at its location, wait for this duration in seconds
Navigatable.Wait(?Duration := 3.0)
npc_utilities
using { /Fortnite.com/Devices }
using { /Fortnite.com/Playspaces }
using { /Verse.org/Simulation }
npc_utilities := class(creative_device):
# Runs when the device is started in a running game
OnBegin<override>()<suspends>:void=
Print("npc_utilities loaded")
GetAllPlayers() : []player =
#Get AllPlayers
Playspace: fort_playspace = GetPlayspace()
AllPlayers: []player = Playspace.GetPlayers()
return AllPlayers
new_npc_behavior (this is just the example file so i have access to debug module)
using { /Fortnite.com/AI }
using { /Fortnite.com/Characters }
using { /Verse.org/Colors }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
# Getting started:
# https://www.epicgames.com/fortnite/en-US/creative/docs/uefn/Verse/onboarding-guide-to-programming-with-verse-in-unreal-editor-for-fortnite
# Create a dedicated debug channel to draw to for this behavior
new_npc_behavior_debug_draw := class(debug_draw_channel) {}
# This module contains functions which return messages used for helpful debugging information that are
# localized and paired with the NPC ID.
new_npc_behavior_message_module:= module:
OnBeginMessage<public><localizes>(Agent:agent):message =
"NPC Agent = {Agent}: OnBegin triggered let's get started."
OnEndMessage<public><localizes>(Agent:agent):message =
"NPC Agent = {Agent}: OnEnd triggered let's cleanup."
OnNavigateBeginMessage<public><localizes>(Agent:agent, X:float, Y:float, Z:float):message =
"NPC Agent = {Agent}: Is moving to [{X},{Y},{Z}]"
OnNavigateErrorMessage<public><localizes>(Agent:agent, X:float, Y:float, Z:float):message =
"NPC Agent = {Agent}: Hit error moving to [{X},{Y},{Z}], please refer to Island Setting's Navigation debug"
# A Verse-authored NPC Behavior that can be used within an NPC Character Definition or a NPC Spawner device's NPC Behavior Script Override.
new_npc_behavior<public> := class(npc_behavior):
# How long to wait in seconds after the NPC navigates to a point before moving on.
@editable
MoveToWaitDuration:float = 5.0
# The negative min and absolute max x & y coordinate offset in centimeters to tell the NPC to move to
@editable
DistanceFromSpawnPtToMove:float = 1500.0
# Whether to draw debug to the NPC channel when Verse Debug Draw is enabled in Island Settings.
@editable
ShowAIDebug:logic = true
# How long in seconds to render the debug draw location and print text.
# It is recommended to keep this in sync with MoveToWaitDuration otherwise the print will not be shown if a previous message is displayed.
@editable
AIDebugDrawTime:float = 5.0
# How long in seconds to render the look at arrow's debug draw.
LookAtDebugDrawDuration:float = 0.5
# Debug Draw instance.
DebugDrawNPC:debug_draw = debug_draw{Channel := new_npc_behavior_debug_draw}
# Used for specifying a point offset from the NPC pelvis to the head to draw the look at arrow from.
VerticalOffsetToNPCHead<private>:float = 55.0
# This function runs when the NPC is spawned in the world and ready to follow a behavior.
OnBegin<override>()<suspends>:void =
if:
# Get the Agent (the NPC).
Agent := GetAgent[]
# Gets the Fortnite Character interface, which gets you access to its gameplay data
# including its AI module for navigation and focus.
Character := Agent.GetFortCharacter[]
# Get the Navigatable Interface, this allows you to tell it to move.
Navigatable := Character.GetNavigatable[]
# Get the Focus Interface, this allows you to tell it to look at something or somewhere.
Focus := Character.GetFocusInterface[]
then:
# TODO: Now that you have the Fortnite Character and the AI interfaces, replace this with your code
# for your desired movement, look at, and other behavior allowed by the AI module.
if(ShowAIDebug?):
Print(new_npc_behavior_message_module.OnBeginMessage(Agent), ?Duration := AIDebugDrawTime)
# Save the position of your character which we'll use to generate more points to move to from.
NPCSpawnPoint := Character.GetTransform().Translation
loop:
# Create a random offset from the spawn point to walk toward.
GoToPoint := NPCSpawnPoint + vector3{X := GetRandomFloat(-DistanceFromSpawnPtToMove,DistanceFromSpawnPtToMove),
Y := GetRandomFloat(-DistanceFromSpawnPtToMove,DistanceFromSpawnPtToMove),
Z := 0.0 }
if(ShowAIDebug?):
Print(new_npc_behavior_message_module.OnNavigateBeginMessage(Agent,GoToPoint.X,GoToPoint.Y,GoToPoint.Z), ?Duration := AIDebugDrawTime)
# Create a navigation target from these two positions that the navigation interface can use.
NavTargetStart := MakeNavigationTarget(GoToPoint)
NavTargetEnd := MakeNavigationTarget(NPCSpawnPoint)
# If the debug flag is enabled draw a box around the location the NPC is moving toward for visual
# validation that it is where you expect.
if(ShowAIDebug?):
DrawDebugLocation(GoToPoint)
# Tell the navigation interface to walk to the location and store a navigation result for error checking.
NavResultGoTo := Navigatable.NavigateTo(NavTargetStart, ?MovementType:=movement_types.Walking)
# Check to see if something has interfered with the NPC reaching the intended location and print a
# message to the output log.
if (NavResultGoTo = navigation_result.Unreachable):
if(ShowAIDebug?):
Print(new_npc_behavior_message_module.OnNavigateErrorMessage(Agent,GoToPoint.X,GoToPoint.Y,GoToPoint.Z), ?Duration := AIDebugDrawTime)
else:
# Once it arrives at its location, wait for this duration in seconds
Navigatable.Wait(?Duration := MoveToWaitDuration)
# Draw more debug visuals to show the point the NPC will look at and move to.
if(ShowAIDebug?):
DrawDebugLocation(NPCSpawnPoint)
# Leveraging concurrency to wait until the NPC reaches its destination, while the calls to look back at its origin point
# and drawing a debug arrow never completes, continuing, ensures only the NavigateTo can win the race.
race:
# Move back to its starting position.
NavResultGoToNext := Navigatable.NavigateTo(NavTargetEnd)
# Sets NPC to look at its previous position which will make it walk backwards.
# This is meant to show the utility of the focus interface.
Focus.MaintainFocus(GoToPoint)
if(ShowAIDebug?):
DrawDebugLookAt(Character, GoToPoint)
else:
Sleep(Inf)
# Check again to see if something has interfered with the NPC reaching the intended location and
# print a message to the output log.
if (NavResultGoToNext = navigation_result.Unreachable):
if(ShowAIDebug?):
Print(new_npc_behavior_message_module.OnNavigateErrorMessage(Agent,GoToPoint.X,GoToPoint.Y,GoToPoint.Z), ?Duration := AIDebugDrawTime)
else:
# This tells the NPC to wait for this amount of time in seconds.
Navigatable.Wait(?Duration := MoveToWaitDuration)
# End of loop, continue the patrol back to the point.
else:
# If code falls here something failed when gathering the agent or its interfaces
if(ShowAIDebug?):
PrintNPCB("Error in NPC Behavior Script on NPC Setup",
?Duration := AIDebugDrawTime,
?TextColor := NamedColors.Red )
# This function draws a box around a specified position for a finite amount of time.
# NOTE: To see this in game, Verse Debug Draw must be enabled in Island Settings.
DrawDebugLocation(Location:vector3):void =
DebugDrawNPC.DrawPoint( Location,
?Color := NamedColors.SteelBlue,
?Thickness := 100.0,
?DrawDurationPolicy := debug_draw_duration_policy.FiniteDuration,
?Duration := AIDebugDrawTime )
# This function draws an arrow from the Agent's head to its look at point every half a second.
# NOTE: To see this in game, Verse Debug Draw must be enabled in Island Settings.
DrawDebugLookAt(Character:fort_character, LookAtPoint:vector3)<suspends>:void=
loop:
DebugDrawNPC.DrawArrow( Character.GetTransform().Translation + vector3{ Z := VerticalOffsetToNPCHead},
LookAtPoint,
?ArrowSize := 50.0,
?Color := NamedColors.Yellow,
?Thickness := 5.0,
?DrawDurationPolicy := debug_draw_duration_policy.FiniteDuration,
?Duration := LookAtDebugDrawDuration )
#This sleep matches the length of time the arrow is drawn to avoid duplicate draws.
Sleep(LookAtDebugDrawDuration)
# Custom wrapper that provides a default duration and color.
PrintNPCB(Msg:string,?Duration:float = AIDebugDrawTime, ?TextColor:color = NamedColors.Green):void =
Print("[new_npc_behavior] {Msg}", ?Color := TextColor, ?Duration := Duration)
# This function runs when the NPC is despawned or eliminated from the world.
OnEnd<override>():void =
# TODO: Replace this with your code for any cleanup that you want to happen.
if(Agent := GetAgent[]):
Print(new_npc_behavior_message_module.OnEndMessage(Agent), ?Duration := AIDebugDrawTime)
else:
PrintNPCB("OnEnd")
so u you need to setup a Npc Definition as a guard with an inventory and patrol modifiers
he should start by patrolling once you get within 100 of him he will chase you
once you outrun him i want him to return to patrolling but he seems to keep the last navtarget and i dont know how to clear it or return him to patrolling