このセクションでは、魅力的なゲームプレイを実現するために、バークなどの音声や、カメラの揺れなどの視覚効果を設定する方法について説明します。
オーディオ プレイヤーの仕掛け
オーディオ プレイヤー の仕掛けを使用すると、ガードのセリフを設定できます。ゲーム開発では、これらは、多くの場合、バーク と呼ばれています。

インポートされた音声は、「Project folder > Barks」にあります。[Play (再生)] アイコンをクリックしてオーディオ ファイルを聴いて、オーディオ ファイルを島にドラッグ アンド ドロップします。

島にオーディオ ファイルをドロップすると、オーディオ プレイヤーの仕掛けが配置されます。オーディオ プレイヤーの仕掛けはVerse の仕掛けに接続され、一連のカスタム ガードのコールアウトを再生します。 これらのコールアウトは、プレイヤーを見つけたときやダメージを受けたときなど、さまざまなイベントに反応します。
再生したいオーディオ 1 つにつきオーディオ プレイヤーを 1 つ配置します。 このチュートリアルでは、14 種類のバークを使用しているため、14 種類のオーディオ プレイヤーの仕掛けを配置しています。
これらの仕掛けを設定するには、以下の設定をカスタマイズします。

オプション | Value | 説明 |
---|---|---|
Volume (ボリューム) | 4.0 | この設定はレコーディングによって異なる場合があります。 |
Restart Audio when Activated (起動時にオーディオをリスタート) | True (オン) | この音声は、アクティベートすると最初から再生されます。 |
Play on Hit (ヒットで再生) | オフ | この仕掛けは、プレイヤーがヒットしても音声が再生されません。 |
Play Location (再生位置) | Instigating Player (発信プレイヤー) | 仕掛けの位置ではなく、発信プレイヤーの位置に基づいて音声が再生されます。 |
Enable Volume Attenuation (音量の減衰を有効化) | オフ | 再生するために設定された仕掛けまたはガードからの距離に基づいて音量を変更します。このチュートリアルでは、プレイヤーはどれほど離れていても音声を聞くことができます。 |
次に、ゲーム中にオーディオ プレイヤーの仕掛けをトリガーするロジックを処理する Verse スクリプトを設定し、Verse の仕掛けを配置します。このチュートリアルでは、この仕掛けに「Stronghold Bark Manager」という名前を付けています。
次の Verse スクリプトを貼り付けます。
using { /Fortnite.com/Devices}
using { /Fortnite.com/Game}
using { /Fortnite.com/Characters}
using { /Verse.org/Random}
using { /Verse.org/Simulation}
using { /UnrealEngine.com/Temporary/Diagnostics}
using { /UnrealEngine.com/Temporary/SpatialMath}
#NPC で再生できるオーディオ バークです。
audio_npc_bark := class<concrete>:
# バークを再生する音声の仕掛けです。
@editable
BarkDevice:audio_player_device := audio_player_device{}
#NPC がバークをリピートできるオプションです。
@editable
CanRepeat:logic = true
# イベント発生からバークの開始までの遅延です。
@editable
Delay:float = 0.0
# このバークをリピートするまでの遅延です。
@editable
Cooldown:float = 5.0
# ログ記録用のバーク名です。
@editable
BarkID:string = "ID がありません"
# クールダウン タイマーが経過したかどうかを示します。
var <private> IsInCooldown:logic = false
# バークを停止するイベントです。
StopBarkEvent<private>:event() = event(){}
PlayBark(Agent:agent)<suspends>:void=
var IsPlaying:logic = false;
defer:
if (IsPlaying?):
set IsPlaying = false
set IsInCooldown = false
BarkDevice.Stop(Agent)
race:
block:
StopBarkEvent.Await()
return
block:
AwaitAgentDown(Agent)
return
block:
if (Delay > 0.0):
Sleep(Delay)
if (IsInCooldown?):
return
BarkDevice.Play(Agent)
set IsPlaying = true
set IsInCooldown = true
Sleep(2.0)
set IsPlaying = false
if (CanRepeat?):
Sleep(Cooldown)
set IsInCooldown = false
StopBark():void=
StopBarkEvent.Signal()
AwaitAgentDown<private>(Agent:agent)<suspends>:void=
if (Character := Agent.GetFortCharacter[]):
loop:
if (Character.GetHealth() <= 0.0):
return
Character.DamagedEvent().Await()
# ガードのバークを処理するスクリプトです。
stronghold_bark_manager := class(creative_device):
# 知覚イベントを監視するゲーム マネージャーの参照です。
@editable
StrongholdGameManager:stronghold_game_manager := stronghold_game_manager{}
# オーディオ プレーヤーの仕掛けです。
@editable
BarkNPCDown:audio_npc_bark = audio_npc_bark{BarkID := "Man Down", Delay := 0.3}
@editable
BarkFallback:audio_npc_bark = audio_npc_bark{BarkID := "Fallback", CanRepeat := false, Delay := 3.0}
@editable
BarkNeedBackup:audio_npc_bark = audio_npc_bark{BarkID := "Need Backup", CanRepeat := false, Delay := 2.0}
@editable
BarkGoToLeash:audio_npc_bark = audio_npc_bark{BarkID := "Reinforcements En Route", CanRepeat := false, Delay := 4.0}
@editable
BarkDamageTaken:audio_npc_bark = audio_npc_bark{BarkID := "Took Damage", Delay := 0.2}
@editable
BarkDamagePlayer:audio_npc_bark = audio_npc_bark{BarkID := "Hit Player", Delay := 0.2}
@editable
BarkEliminatedPlayer:audio_npc_bark = audio_npc_bark{BarkID := "Eliminated Player", Delay := 0.3}
@editable
BarkPlayerSpotted:audio_npc_bark = audio_npc_bark{BarkID := "Spotted Player", CanRepeat := false}
@editable
BarkPlayerLost:audio_npc_bark = audio_npc_bark{BarkID := "Lost Player", Cooldown := 10.0}
@editable
BarkGuardSuspicious:audio_npc_bark = audio_npc_bark{BarkID := "Suspicious", Cooldown := 10.0}
@editable
BarkGuardUnaware:audio_npc_bark = audio_npc_bark{BarkID := "Unaware", Cooldown := 10.0}
# ガードがターゲットを探していたかどうかを格納する変数です。
var<private> HasLostTarget:logic := false
# 実行中のゲームで仕掛けが開始されたときに実行します
OnBegin<override>()<suspends>:void=
ConfigureBarks()
sync:
AwaitReinforcements()
AwaitFallback()
PlayAwarenessBarks()
PlayBark(Bark:audio_npc_bark, Guard:agent):void=
spawn {Bark.PlayBark(Guard)}
# 援軍が要請されたときにバークを再生します。
AwaitReinforcements<private>()<suspends>:void=
AlertedGuard := StrongholdGameManager.ReinforcementsCalledEvent.Await()
PlayBark(BarkNeedBackup, AlertedGuard)
# ガードが要塞で再編成されたときにバークを再生します。
AwaitFallback<private>()<suspends>:void=
StrongholdGameManager.FallbackEvent.Await()
if:
Guard := StrongholdGameManager.AlertedGuards[0]
then:
PlayBark(BarkFallback, Guard)
PlayAwarenessBarks<private>()<suspends>:void=
loop:
race:
PlayGuardsSuspiciousBark()
PlayPlayerSpottedBark()
PlayPlayerLostBark()
PlayGuardsUnawareBark()
PlayPlayerSpottedBark<private>()<suspends>:void=
Guard:=StrongholdGameManager.PlayerDetectedEvent.Await();
set HasLostTarget = false
PlayBark(BarkPlayerSpotted, Guard)
PlayPlayerLostBark<private>()<suspends>:void=
Guard:=StrongholdGameManager.PlayerLostEvent.Await();
set HasLostTarget = true
PlayBark(BarkPlayerLost, Guard)
PlayGuardsSuspiciousBark<private>()<suspends>:void=
Guard:=StrongholdGameManager.GuardsSuspiciousEvent.Await();
PlayBark(BarkGuardSuspicious, Guard)
PlayGuardsUnawareBark<private>()<suspends>:void=
Guard:=StrongholdGameManager.GuardsUnawareEvent.Await();
if (HasLostTarget?):
set HasLostTarget = false
if (not StrongholdGameManager.FallbackTriggered?):
PlayBark(BarkGuardUnaware, Guard)
SubscribeToGuardSpawnerEvents(GuardSpawnerDevice:guard_spawner_device):void =
GuardSpawnerDevice.DamagedEvent.Subscribe(OnGuardDamaged)
GuardSpawnerDevice.EliminatedEvent.Subscribe(OnGuardEliminated)
GuardSpawnerDevice.EliminatingEvent.Subscribe(OnPlayerEliminated)
# Configure all barks
ConfigureBarks():void=
# Subscribe To Player Damage Event
AllPlayers := GetPlayspace().GetPlayers()
for (StrongholdPlayer : AllPlayers, StrongholdPC := StrongholdPlayer.GetFortCharacter[]):
StrongholdPC.DamagedEvent().Subscribe(OnPlayerDamaged)
# Run through guards spawner list from stronghold manager and subscribe to all key events
for (GuardSpawner : StrongholdGameManager.GuardsInitialSpawners):
SubscribeToGuardSpawnerEvents(GuardSpawner)
for (GuardSpawner : StrongholdGameManager.GuardsReinforcementSpawners):
SubscribeToGuardSpawnerEvents(GuardSpawner)
# 援軍がスポーンされたときのための別のケースを設定します。
if:
FirstReinforcementSpawner := StrongholdGameManager.GuardsReinforcementSpawners[0]
then:
FirstReinforcementSpawner.SpawnedEvent.Subscribe(HandleReinforcementSpawned)
# ガードがダウンしている場合、最も近くにいる警戒状態にあるガードでバークの再生を試みます。
OnGuardEliminated(InteractionResult:device_ai_interaction_result):void=
if (EliminatedGuard := InteractionResult.Target?):
# 生きている最も近いガードを見つけて、このバークを再生します。
var ClosestGuard:?agent = false
if:
set ClosestGuard = option{StrongholdGameManager.AlertedGuards[0]}
EliminatedGuardCharacter := EliminatedGuard.GetFortCharacter[]
then:
for (AlertedGuard : StrongholdGameManager.AlertedGuards, AlertedGuardCharacter := AlertedGuard.GetFortCharacter[]):
if:
not ClosestGuard?= AlertedGuard
ClosestGuardCharacter := ClosestGuard?.GetFortCharacter[]
DistanceSquaredToAlertedGuard := DistanceSquared(AlertedGuardCharacter.GetTransform().Translation, EliminatedGuardCharacter.GetTransform().Translation)
DistanceSquaredToClosestGuard := DistanceSquared(ClosestGuardCharacter.GetTransform().Translation, EliminatedGuardCharacter.GetTransform().Translation)
DistanceSquaredToAlertedGuard < DistanceSquaredToClosestGuard
then:
set ClosestGuard = option{AlertedGuard}
if (Guard := ClosestGuard?):
spawn {BarkNPCDown.PlayBark(Guard)}
# ガードにヒットした場合で、ガードがダウンしていないときは、バークの再生を試みます
OnGuardDamaged(InteractionResult:device_ai_interaction_result):void=
if (Guard := InteractionResult.Target?):
spawn {BarkDamageTaken.PlayBark(Guard)}
# プレイヤーにヒットした場合、プレイヤーにダメージを与えたガードでバークの再生を試みます
OnPlayerDamaged(DamageResult:damage_result):void=
if:
fort_character[DamageResult.Target].GetHealth() > 0.0
Guard := DamageResult.Instigator?.GetInstigatorAgent[]
then:
spawn {BarkDamagePlayer.PlayBark(Guard)}
# プレイヤーがダウンしている場合、プレイヤーを撃破したガードでバークの再生を試みます
OnPlayerEliminated(InteractionResult:device_ai_interaction_result):void=
if (Guard := InteractionResult.Source?):
spawn {BarkEliminatedPlayer.PlayBark(Guard)}
HandleReinforcementSpawned(Guard:agent):void=
spawn {BarkGoToLeash.PlayBark(Guard)}
このスクリプトは、各オーディオ プレイヤーの仕掛けへの参照を格納し、ガード スポナーの参照のコンジットとして 要塞ゲーム マネージャー Verse の仕掛けを参照します。
カスタマイズ可能なライト

AI ガードからの音声のフィードバックの取得だけでなく、環境からのビジュアルのフィードバックもプレイヤーに与えることができます。
このチュートリアルでは、2 セットの カスタマイズ可能なライト仕掛けを要塞の周囲に使用します。赤のライトは検知ステータスを、オレンジのライトは警戒ステータスを示します。
これらの仕掛けを設定するには、以下の設定をカスタマイズします。
オプション | Value | 説明 |
---|---|---|
Initial State (最初の状態) | False | この仕掛けを有効にしたときのライトの初期状態を決定します。 |
Light Size (ライトのサイズ) | 100.00 | ライト フレアのサイズ、範囲、振幅を決定します。 |
Cast Shadows (シャドウをキャスト) | True | ライトによりシャドウをキャストすることができます。 |
Enabled During Phase (有効なゲーム フェーズ) | Gameplay Only (ゲームプレイのみ) | ライトはゲームプレイ中にのみ有効になります。 |
Light Intensity (ライトの明度) | 30.0 | ライトの強度を決定します。 |
Rhythm Time (リズム時間) | x8 | リズム プリセットの時間の倍率を決定します。 |
Dimming Amount (明かりを暗くする量) | 100.0 | チャンネル コントロールを使用する際の調光量を決定します。 |
Dimming Time (明かりが暗くなるまでの時間) | 0.1 | 暗くなるまでにかかる時間を秒単位で決定します。 |
VFX クリエイター

このチュートリアルでは、ベースの上部にある VFX クリエイターの仕掛けを使用して、プレイヤーが最初に検知されたときに援軍のシグナル フレアとして機能するようにします。このフレアは Verse の仕掛けによって制御され、ガードが警戒状態にあるとコーナー ライトとともに消灯し、ガードの状態を視覚的に明確に示します。
これらの仕掛けを設定するには、以下の設定をカスタマイズします。

オプション | Value | 説明 |
---|---|---|
Start Effects When Enabled (有効時にエフェクトを開始) | False | 有効になった際に、仕掛けがエフェクトを実行するのかを決定します。 |
Sprite Size (スプライトのサイズ) | 2.0 | エフェクトのスプライトの初期サイズを設定します。 |
Sprite Duration (スプライト持続時間) | 5.0 | 各スプライトの表示時間を設定します。 |
Main Color (メイン カラー) | Red (赤) | エフェクトのメインカラーを設定します。 |
Main Color Brightness (メイン カラーの明るさ) | 200.0 | Main Color (メイン カラー) の明るさを設定します。 |
Sprite Speed (スプライトの速度) | 100.0 | エフェクトのスプライトが動き出す速度を設定します。 |
Effect Gravity (エフェクトの重力) | 15.0 | エフェクトスプライトがどのくらいの速さで落下するのかを設定します。 |
Randomness (ランダム性) | 100.0 | 動きのランダム性を設定し、サイズにバリエーションを加えます。 |
Keep Size (サイズを維持) | False | スプライトのサイズを維持するか、時間の経過とともに変化するカスタム サイズを使用するかを設定します。 |
Effect Generation Amount (エフェクトの生成量) | 4.0 | エフェクトのスプライトの生成数を設定します。 |
Spawn Zone Shape (スポーン ゾーンの形状) | Point (ポイント) | スプライトが最初に表示される空間の形状を決定します。 |
Spawn Zone Size (スポーン ゾーンのサイズ) | 0.05 | スポーン形状のサイズをタイル単位で設定します。 |
Enabled During Phase (有効なゲーム フェーズ) | Gameplay Only (ゲームプレイのみ) | 仕掛けが有効になるゲーム フェーズを決定します。 |
Loop (ループ) | Never (なし) | エフェクトが一度だけ再生されるか、恒久的にループするか、カスタマイズされた回数だけ再生されるかを決定します。 |
ラジオの仕掛け
このチュートリアルでは 2 つの ラジオの仕掛けを使用しています。1 つは緊張感のある戦闘サウンド用で、もう 1 つは警戒を促すサウンド用です。
緊張感のあるプレイヤーの音楽では、[Radio (ラジオ)] > [Music Loops (音楽ループ)] > 「Music_StW_Low_Combat01_Cue'」を使用します。
プレイヤーが見つかったときの戦闘サウンドは、[Radio] > [Music Loops (音楽ループ)] > 「Music_StW_High_Combat01_Cue」を使用します。
Stronghold_Alert_Manager を呼び出して、ガードがプレイヤーを検知したとき、またはすべてのガードがプレイヤーを見失ったときに、要塞内の 2 つの状態を交互にリッスンできる Verse スクリプトを設定します。
次の Verse スクリプトを貼り付けます。
using { /Verse.org/Simulation}
using { /Verse.org/Simulation/Tags}
using { /Verse.org/Colors}
using { /UnrealEngine.com/Temporary/Diagnostics}
using { /Fortnite.com/Devices}
# カスタマイズ可能なライトのタグ
alerted_lights_tag := class(tag){}
combat_lights_tag := class(tag){}
# ガードが警戒状態にあるときに音楽を処理し、ライトを点灯させるスクリプト
stronghold_alert_manager := class(creative_device):
# 知覚イベントを監視するゲーム マネージャーの参照です。
@editable
StrongholdGameManager:stronghold_game_manager := stronghold_game_manager{}
# 戦闘サウンドを再生するラジオの参照
@editable
RadioCombat:radio_device := radio_device{}
# 警戒状態中のサウンドを再生するラジオの参照
@editable
RadioAlerted:radio_device := radio_device{}
#警報/フレアが撃たれたときに再生される VFX
@editable
FlareAlarmVFXCreator:vfx_creator_device := vfx_creator_device{}
# クラス データ
var <private> CustomizableLightDevicesAlerted: []customizable_light_device = array{}
var <private> CustomizableLightDevicesCombat: []customizable_light_device = array{}
# プレイヤーを見失ったとき/プレイヤーがキルされた場合、キャンプを警戒状態に変更します
WaitForAlerted()<suspends>:void=
# フォールバック後は、警戒状態に戻しません
if (StrongholdGameManager.FallbackTriggered?):
Sleep(Inf)
StrongholdGameManager.GuardsUnawareEvent.Await()
Sleep(3.0)
SetAlertedMood()
# プレイヤーが検知された場合、キャンプを戦闘中に変更します
WaitForCombat()<suspends>:void=
race:
StrongholdGameManager.PlayerDetectedEvent.Await()
StrongholdGameManager.FallbackEvent.Await()
Sleep(2.0)
SetCombatMood()
# 実行中のゲームで仕掛けが開始されたときに実行します
OnBegin<override>()<suspends>:void=
FindLightsWithTag()
MonitorStrongholdAlertStatus()
# 要塞が戦闘状態か警戒状態かをチェックするメイン ループ
MonitorStrongholdAlertStatus()<suspends>:void=
loop:
WaitForCombat()
WaitForAlerted()
# ライトを赤に切り替え、迫力のあるサウンドを再生することで、ベースを戦闘状態に設定します
SetCombatMood():void=
# 戦闘状態ライトをループ処理して、点灯させます
for(LightsToTurnOn: CustomizableLightDevicesCombat):
LightsToTurnOn.TurnOn()
# 警戒状態ライトをループ処理して、消灯します
for(LightsToTurnOff: CustomizableLightDevicesAlerted):
LightsToTurnOff.TurnOff()
# 戦闘状態オーディオをオンにして、警戒状態オーディオをオフにします
RadioCombat.Play()
RadioAlerted.Stop()
FlareAlarmVFXCreator.Toggle()
# ライトを黄色に切り替え、緊張感のあるサウンドを再生することで、ベースを警戒状態に設定します
SetAlertedMood():void=
for(LightsToTurnOn: CustomizableLightDevicesAlerted):
LightsToTurnOn.TurnOn()
for(LightsToTurnOff: CustomizableLightDevicesCombat):
LightsToTurnOff.TurnOff()
RadioCombat.Stop()
RadioAlerted.Play()
# この特定の Verse タグを持つライトのクリエイティブの仕掛けをループ処理し、リストに保存します
FindLightsWithTag() : void=
TaggedAlertedLightDevices := GetCreativeObjectsWithTag(alerted_lights_tag{})
TaggedCombatLightDevices := GetCreativeObjectsWithTag(combat_lights_tag{})
for(AlertedLight : TaggedAlertedLightDevices, CustomizableLight := customizable_light_device[AlertedLight] ):
CustomizableLight.TurnOff()
set CustomizableLightDevicesAlerted += array{CustomizableLight}
for(CombatLight : TaggedCombatLightDevices, CustomizableLight := customizable_light_device[CombatLight] ):
CustomizableLight.TurnOff()
set CustomizableLightDevicesCombat += array{CustomizableLight}
これで要塞ゲームを作成することができました。