前書き
本記事は「Verseデバイス」を作成し、機能を実装することを理解している人向けとなります。Verseってなんぞや…という人には少し難しいかもしれませんので、一度別の記事やチュートリアルで勉強してみるのをオススメします。基本的に、用語や前提知識を知っている状態で進めていきます。
NPCスポナーとnpc_behavior

Verseファイルを作成する画面を見てみると、「NPC behavior basic」と呼ばれるテンプレートが用意されているはずです。これは、NPCを実装するうえで最低限必要なコードと一緒にファイルを作成してくれます。
今回は、こちらのテンプレートからNPCの機能を試していこうと思います。NPC Behavior Nameは自由に決めていただき、作成を押してみましょう。

Verseコードをビルドしてみると、Verseデバイスと同様にVerseクラスアセットが生成されるはずです。

これをレベル上にドラッグすると、NPCスポナーと呼ばれる専用のデバイスが配置されるはずです。VerseのNPCは全て「NPCスポナー」と紐づけてスポーンさせたり、デスポーンさせたりの処理を行います。イベントバインディングやVerseでスポーンさせる機能を呼び出したり、時間経過で自動でスポーンする設定をしたりと、一般的な仕掛けと同じような扱いです。
# Used to spawn NPCs made with Character Definition asset.
npc_spawner_device<public> := class<concrete><final>(creative_device_base):
# Signaled when a character is spawned.
# Sends the `agent` character who was spawned.
SpawnedEvent<public>:listenable(agent) = external {}
# Signaled when a character is eliminated.
# `Source` is the `agent` that eliminated the character. If the character was eliminated by a non-agent then `Source` is 'false'.
# `Target` is the character that was eliminated.
EliminatedEvent<public>:listenable(device_ai_interaction_result) = external {}
# Enables this device. Characters will start to spawn.
Enable<public>():void = external {}
# Disables this device. Characters will despawn if *Despawn AIs When Disabled* is set.
Disable<public>():void = external {}
# Resets the spawn count allowing spawning of a new batch of characters.
Reset<public>():void = external {}
# Tries to spawn a character.
Spawn<public>():void = external {}
# Despawns all characters. If set, `Instigator` will be considered as the eliminator of those characters.
DespawnAll<public>(Instigator:?agent):void = external {}
Verseの定義にも、「npc_spawner_device」として用意されています。
NPCキャラクター定義

ここで、NPCスポナーを扱ううえで必要な要素である「NPCキャラクター定義」についても見ていきます。
VerseだけではNPCの見た目や移動速度、その他細かいパラメーターの調整を行うことができません。そのため、「AI > NPCキャラクター定義」に用意されているこちらのアセットを使用します。

アセット作成後は、NPCスポナー内の「NPCキャラクター定義」に作成したものを入れることができます。
NPCスポナーが複数個あった場合、同じNPCキャラクター定義を使うこともあれば、スポナーごとに別々のアセットを作成して分けることもあります。

定義を開いてみると、キャラクタービジュアルや体力の数値など、キャラクター自信の個性を決めるパラメータがいくつも用意されています。これらはまた後々解説しますが、現状は「VerseのNPC」と「NPCキャラクター定義」はセットで使われる、と覚えていただければ大丈夫です。
npc_behavior
using { /Fortnite.com/AI }
using { /Verse.org/Simulation }
# Getting started: https://www.epicgames.com/fortnite/en-US/creative/docs/uefn/Verse/onboarding-guide-to-programming-with-verse-in-unreal-editor-for-fortnite
# A Verse-authored NPC Behavior that can be used within an NPC Character Definition or an NPC Spawner device's NPC Behavior Script Override.
new_npc_behavior_basic := class(npc_behavior):
# 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!")
# This function runs when the NPC is despawned or eliminated from the world.
OnEnd<override>():void=
# TODO: Replace this with your code
Print("Goodbye, NPC!")
さて、Verseの方に戻って基本的な部分を見ていきます。
npc_behaviorはVerseデバイスと同様に、OnBeginと呼ばれる関数をオーバーライドすることができます。Verseデバイスの場合はゲーム開始と同時に呼び出されていましたが、NPCの場合はNPCスポナーからスポーンされると同時にOnBeginが呼び出されます。
試しにゲーム内で確認をしてみると、スポーンのタイミングで「Hello, NPC!」が、倒したりデスポーンをさせると「Goodbye, NPC!」と左上に表示されるはずです。
OnEndに関してはVerseデバイスでは使うことはなかったかもしれません(一応用意はされていますが)。ただ、NPCはゲームの状況に合わせて人数が増えたり減ったり、はたまた何体も連続でスポーンやデスポーンが繰り返されるなど、常にNPCが存在しているとは限りません。
そのため、OnEndを使って「倒された際は○○という処理を停止する」といった処理を書くことで、ゲームを安定して動かすことができるようになるのです。
GetAgent
# Inherit from this to create a custom NPC behavior.
# The npc_behavior can be defined for a character in a CharacterDefinition asset, or in a npc_spawner_device.
npc_behavior<native><public> := class<abstract>:
# This function is called when the NPC is added to the simulation.
OnBegin<native_callable><public>()<suspends>:void = external {}
# This function is called when the NPC is removed from the simulation.
OnEnd<native_callable><public>():void = external {}
# Returns the agent associated with this behavior.
GetAgent<native><public>()<transacts><decides>:agent
npc_behaviorには「GetAgent」と呼ばれる失敗関数が用意されています。これは、スポーンしたNPC自体を指す「agent」を取得する関数です。
フォートナイトのプレイヤーはagentと呼ばれる型で定義されています。同様に、NPCもagentと呼ばれる型で定義されています。agentは仕掛けに対して情報を渡す際や、「誰」に「何」をするかの指示をする際に重要な要素となっています。
using { /Fortnite.com/AI }
using { /Verse.org/Simulation }
using { /Fortnite.com/Characters }
# Getting started: https://www.epicgames.com/fortnite/en-US/creative/docs/uefn/Verse/onboarding-guide-to-programming-with-verse-in-unreal-editor-for-fortnite
# A Verse-authored NPC Behavior that can be used within an NPC Character Definition or an NPC Spawner device's NPC Behavior Script Override.
new_npc_behavior_basic := class(npc_behavior):
# 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!")
if:
NPCAgent := GetAgent[]
NPCCharacter := NPCAgent.GetFortCharacter[]
then:
# This function runs when the NPC is despawned or eliminated from the world.
OnEnd<override>():void=
# TODO: Replace this with your code
Print("Goodbye, NPC!")
実際に使う場合はこのように記述します。GetAgent自体はnpc_behaviorの一部であるため、npc_behavior内であれば先頭に何かを付け足す(○○.GetAgent[]」とする必要はありません。また、プレイヤー同様にfort_characterに変換することもできます。Damage関数を呼び出したり、IsOnGround関数で着地しているかなど、fort_characterの機能も一通り使えます。
次回
次回はNPCに行動をさせるための方法を紹介します。例えばNavigateToという関数を使って、目的地まで歩かせたり…NPCの一番楽しい部分が始まるので、楽しみにしておきましょう。