【Unreal Engine】Event TickとTimerの使い分け:近づいた間だけ動く見張り塔を作る

作成: 2025-12-12最終更新: 2026-09-05

毎フレームのTick、一定間隔のTimer、出来事で呼ばれるイベントを使い分けます。近づくと0.5秒ごとに回り、離れると止まる見張り塔で、Timerの開始・Handleの保存・停止を試します。

HPが変わっていないか、プレイヤーが近くにいないか。Event Tickへつなぐと毎フレーム確認できますが、本当にそこまで細かく調べる必要があるでしょうか。

HPの表示なら、HPが変わったとき。一定間隔の見回りなら、0.5秒ごと。処理を動かすきっかけを選ぶと、何のために実行しているのかが分かりやすくなり、不要な繰り返しも減らせます。

この記事では、Tick・Timer・イベントの使い分け を整理します。実践では、プレイヤーが近づいた間だけ見張り塔の腕が回り、離れると止まる仕組みを作ります。

他のエンジンでいうと: Tick は Unity の Update() 、Godot の _process(delta) です。Timer は Unity の Invoke やコルーチン、Godot の Timer ノードが近い役割になります。

ずっと回し車を走る人形と、ベルを待つ人形。繰り返し確認する方法と、出来事を待つ方法

この記事でわかること

  • 毎フレーム・一定間隔・出来事で、処理を分ける考え方
  • Set Timer by Eventの作成と、Timer Handleを使った停止
  • Overlapで「近くにいる間だけ動く」を作る方法
  • Tickを残す場面と、回数だけでは性能を判断できない理由

Sponsored

Event Tickは、毎フレームの更新に使う

フレーム は、ゲームが状態を更新し、画面を描くときの1回分です。60FPSなら、1秒間におよそ60フレーム進みます。

Event Tickは、ActorのTickが有効で、Tick Intervalが0なら毎フレーム呼ばれます。たとえば60FPSで100体すべてがTick内の処理を実行すると、合計は 60 × 100 = 6000回/秒 です。

この数だけで「重い」とは決まりません。足し算1回と、周囲のActorを大量に探す処理では、1回の負担が違います。見るべきなのは 1回の処理内容、繰り返す頻度、実行するActor数 の組み合わせです。

60FPSのTickは1体で約60回、100体�で約6000回。0.5秒のTimerは1体で約2回。回数と処理内容を合わせて考える

毎フレームHPを読み、前の値と比べて表示を変えるような、繰り返し様子を見に行く方法を ポーリング と呼びます。必要な場面もありますが、HPを変更する側から「変わった」と知らせれば、変化していない間の確認は不要になります。

望遠鏡で確認し続ける方法と、ベルが鳴ったときに反応する方法

こうした 出来事をきっかけに処理する設計 がイベント駆動です。「Tickを全部消す」ことが目的ではなく、必要なタイミングで動かすための選択肢です。

処理のきっかけを、3つの道具で選ぶ

Timerは決めた間隔、Event Dispatcherは出来事の通知、Collision Eventsは接触や領域への出入りをきっかけにする

一定間隔ならTimer

Timer は、「この時間がたったら、指定した処理を呼ぶ」という予約です。Set Timer by Event のTimeを0.5、Loopingをオンにすると、指定したイベントを0.5秒ごとに繰り返します。

毒で1秒ごとにHPを減らす、数秒おきに資源を補充する、といった処理に向いています。60FPSで毎フレーム呼ぶ代わりに0.5秒間隔にすれば、通常は60回/秒から約2回/秒へ減らせます。

ただし、Timerで定期的に敵を探すなら、それもポーリングの一種です。確認をなくしたのではなく、確認する間隔を選んだ と考えてください。

変化を知らせるならEvent Dispatcher

HPが減った、アイテムを拾った、扉が開き終わった。起きたことを別の担当へ知らせたいなら、Event Dispatcherを使えます。

受け手はあらかじめBindで登録し、発信側は出来事のときにCallで通知します。HP表示のために毎フレーム値を読み直す必要がなくなります。作り方はEvent Dispatcherの記事で試せます。

領域への出入りならOverlap

Sphere CollisionやBox Collisionを検知用の領域にすると、Overlap=当たり判定の形どうしが重なること をきっかけにできます。

On Component Begin Overlap は重なり始めたとき、On Component End Overlap は重なりが終わったときに呼ばれます。範囲内にいる間ずっと、Begin Overlapが毎フレーム呼ばれるわけではありません。

プレイヤーが近づいたら装置を起動し、離れたら止める。次の実践では、この出入りのイベントでTimerを開始・停止します。

実践:近づいた間だけ、見張り塔を回す

作るのは、0.5秒ごとに腕が30度回る見張り塔 です。プレイヤーが検知範囲の外にいる間は止まり、範囲へ入ると回り始め、出るとその向きで止まります。

ステルスゲームの監視装置や、近くのときだけ働く迎撃塔へつながる仕組みです。今回は動く期間を分かりやすく見るため、腕を一定角度ずつ回します。滑らかな回転や敵への照準は、ここでは扱いません。

範囲外では停止、範囲内では0.5秒ごとに腕が30度回り、範囲を出るとその向きで止まる見張り塔

UE5のThird PersonテンプレートをBlueprintで作り、VariantがあればNoneを選びます。操作プレイヤーは1人とし、新しい練習フォルダで進めます。

① 見張り塔の部品を用意する

Actorを親に BP_Guard を作ります。DefaultSceneRootを残し、次の部品を追加します。位置・回転・Scaleは 親の部品から見た相対値 です。

名前種類・親設定
BaseStatic Mesh/DefaultSceneRootの子標準Cylinder、位置(0, 0, 100)、Scale(1, 1, 2)
RadarPivotScene/DefaultSceneRootの子位置(0, 0, 220)、Scale(1, 1, 1)
ArmStatic Mesh/RadarPivotの子標準Cube、位置(100, 0, 0)、Scale(2, 0.2, 0.2)
DetectionSphereSphere Collision/DefaultSceneRootの子位置(0, 0, 100)、Sphere Radius 800、Scale(1, 1, 1)

回転はすべて0にします。CubeやCylinderが見つからない場合は、アセット選択のSettingsで「Show Engine Content」をオンにし、Engine/BasicShapes から選びます。

Scene Component は、位置や向きを持つ部品です。RadarPivotには見た目がありませんが、その子にしたArmを一緒に回せます。ArmをX方向へずらしてあるので、RadarPivotを回すと塔の中心を軸に腕が回ります。

RadarPivotの子にArmを置くComponent構成。RadarPivotを回しても、別の子であるBaseは回らない

BaseとArmはCollision PresetsをNoCollision、Simulate Physicsをオフにします。RadarPivotとArmのMobilityはMovableにします。

「Class Defaults」→「Actor Tick」の Start with Tick Enabledをオフ にします。今回使うのはTimerとOverlapなので、このActorのEvent Tickは不要です。

② プレイヤーの出入りを検知できるようにする

DetectionSphereを選び、次を設定します。

項目設定
Collision PresetsCustom
Collision EnabledQuery Only
Collision ResponsesPawnだけOverlap、ほかはIgnore
Generate Overlap Eventsオン

Query Only は、重なりなどの検出に使い、物理的に押し返すためには使わない設定です。半径800は800cm、つまり8mです。ただし検知するのは形どうしの重なりなので、プレイヤーの中心までの距離がぴったり8mになった瞬間とは限りません。

BP_ThirdPersonCharacterを開き、Capsule ComponentのGenerate Overlap Eventsをオンにします。この練習では、MeshのGenerate Overlap Eventsはオフにして、プレイヤーの検知をカプセル1つにそろえます。CapsuleのObject TypeがPawnであることも確認してください。

双方をCompile・保存し、BP_Guardをレベルへ1個置きます。ActorのScaleは1、回転は0で、Rootの位置を床に合わせます。Player Startから1200cmほど離し、最初は検知範囲の外 から近づけるようにします。

③ 1回分の見回りを作る

BP_Guardへ次の変数を追加します。

変数役割・初期値
ScanCountInteger見回った回数。既定値0
ScanHandleTimer Handle動かしたTimerを後で止めるために保持

Timer Handle は、どのTimerを操作するか指定するための値です。ストップウォッチをいくつか持つときの「この1個を止める」という目印に相当します。自分で番号を入れず、Timerを作ったときの戻り値を保存します。

Event GraphにCustom Event ScanStep を作ります。まずは、呼ばれたら1回だけ腕を回す処理です。

  1. RadarPivotをグラフへドラッグし、その参照からAdd Local Rotationを作る。
  2. ScanStepの白い実行出力をAdd Local Rotationへつなぐ。TargetはRadarPivot。
  3. Delta RotationをX(Roll)0、Y(Pitch)0、Z(Yaw)30にする。必要ならピンを右クリックしてSplit Struct Pinで展開する。
  4. SweepとTeleportはオフにする。

Yaw は、上下方向のZ軸を中心に回す角度です。Add Local Rotationは「この部品の今の向きへ、指定した回転を足す」ので、呼ぶたびに腕が30度ずつ進みます。

ScanStepからAdd Local Rotationを実行し、TargetにRadarPivot、Yawに30を指定する

続けてSet ScanCountをつなぎ、Integerの加算でGet ScanCount + 1を設定します。

回転処理の白線をSet ScanCountへつなぎ、現在値に1を足した結果を保存する

その後ろへPrint Stringをつなぎ、Durationを1秒にします。To String (Integer) は数値を表示用の文字へ変えるノード、Append は文字列をつなぐノードです。AppendのAに Scan: 、Bに更新後のScanCountを変換した文字列を渡し、Return ValueをPrint StringのIn Stringへつなぎます。

更新後のScanCountを文字列に変え、Scan: とつないでPrint Stringへ渡す

これで見回りのたびに「Scan: 1」「Scan: 2」と表示できます。図の「〜から」「〜へ」は、前後の図とのつなぎ目を示す注記です。ノードを追加する指示ではありません。

Compile・保存します。まだScanStepを呼ぶきっかけがないので、この段階では腕は回りません。

④ 入ってきたら、Timerを開始する

DetectionSphereのDetails → EventsからOn Component Begin Overlapを追加します。Other ActorからCast To BP_ThirdPersonCharacterを作り、Overlapの白い実行出力もCastへつなぎます。

Other Actorは、領域へ入ってきた相手です。ここではテンプレートの操作キャラクターとして扱えるときだけ続けます。Cast Failed側は何もしません。

Castの成功側から、Set ScanCountで0へ戻し、その後ろへSet Timer by Eventを置きます。

Begin OverlapのOther ActorをCastへ渡し、成功したときだけScanCountを0へ戻す
Set Timer by Event設定・接続
Time0.5
Loopingオン
EventScanStepの赤いEvent出力
Return ValueSet ScanHandleの値

ScanStepの 赤いEvent出力から、Timerの赤いEvent入力へ つなぎます。白い線はTimerを開始する順番、赤い線は時間が来たら呼ぶイベントの指定です。ScanStepの白い出力は、先ほど作った回転処理につないだままにします。

Set Timer by Eventの白い出力からSet ScanHandleへつなぎ、Return Valueもその値の入力へ渡します。Time以外の開始遅延などは既定値のままにします。

Set Timer by Eventへ既存のScanStepを赤線で指定し、Return ValueをScanHandleへ保存する

ここまでできたらPlayし、塔へ近づいてみてください。範囲へ入って約0.5秒後から、腕が30度ずつ回り、Scanの数字が増えればTimerが動いています。この段階では、離れても止まりません。 次に停止を作ります。

⑤ 離れたら、保存したHandleで止める

DetectionSphereのOn Component End Overlapも追加します。こちらもOther Actorと白い実行線をCast To BP_ThirdPersonCharacterへ渡し、成功したときだけ次へ進めます。

成功側へ Clear and Invalidate Timer by Handle をつなぎ、HandleにGet ScanHandleを渡します。これはTimerを解除し、保持していたHandleも無効にするノードです。最後にPrint Stringで Stopped を1秒表示します。

End Overlapでもプレイヤーか確かめ、保存済みのScanHandleでTimerを解除してStoppedと表示する

これで、検知範囲を出たときにScanStepの予約が止まります。腕の向きは戻さないので、最後に回った位置で停止します。

⑥ 出入りと間隔の変更を試す

Compile・保存して新しくPlayし、次を確かめます。

操作期待する結果
範囲の外にいる腕は止まり、Scanの表示は出ない
塔へ近づいて範囲へ入る約0.5秒ごとに腕が30度進み、Scanが1、2、3と増える
入った範囲から十分に離れるStoppedと出て、腕とScanの増加が止まる
もう一度近づくその向きから回り始め、Scanは1から数え直す
出入りを数回繰り返す範囲外では止まり、近くにいる間の間隔は変わらない

退出直前のPrintはDurationの間だけ画面に残ります。文字が少し残ることと、Timerが新しく処理を続けていることは区別してください。

次にTimeを1へ変えて、新しいPlayで試します。腕が進む間隔も数字が増える間隔も約1秒になれば、Timeの役割が分かります。1回の角度は30度のままなので、1秒あたりの回転量も半分になります。確認後は0.5へ戻します。

動かない・止まらないとき

症状確認するところ
近づいても何も起きないSphereとCapsule双方のGenerate Overlap Events、Pawnへの応答、CastのClass
Scanは増えるのに腕が動かないAdd Local RotationのTarget、ArmがRadarPivotの子か、MobilityがMovableか
1回しか動かないLoopingがオンか
離れても動き続けるEnd Overlapからの白線、ScanHandleに戻り値を保存したか、Clearへ同じHandleを渡したか
入った直後に止まる・何度も開始するプレイヤーのMeshなど、Capsule以外も重なりを通知していないか

Overlap直後へ一時的にPrintを置くと、「出入りを検知できていない」のか、「その後のTimer処理が動いていない」のかを分けて調べられます。今回の設定は、操作プレイヤー1人をCapsuleで検知する小さな実験です。

Sponsored

Tickを使うときは、頻度と動く期間を考える

見張り塔は一定角度ずつ回ればよいのでTimerにしました。一方、カメラを滑らかに追従させるなど、毎フレーム変化させたい処理にはTickが向いています。

Tick Intervalで、更新の間隔を選ぶ

「Class Defaults」→「Actor Tick」のTick Intervalは、そのActorのTickを実行する 最小間隔 です。0なら毎フレーム、0.1ならおおむね0.1秒以上の間隔を空けます。

更新が少し遅れてもよい処理には使えますが、値を大きくすると動きや反応も粗くなります。滑らかさが必要なカメラへ、そのまま0.5などを設定する使い方は向きません。

必要な間だけTickを有効にする

Set Actor Tick Enabled は、そのActorのTickをオン・オフにするノードです。Targetに操作するActor、EnabledにTrue/Falseを渡します。

ただし、Tickの中で「近くに来たらTickをオンにする」と書いても、Tickがオフの間はその判定も動きません。再開のきっかけには、Overlapなど Tickの外から呼ばれるイベント を使います。

Tick Intervalで更新の間隔を粗くする方法と、Tickの外のイベントから再開させる流れ

ActorのTickをオフにしても、TimerやComponentのTickまで一括で止まるわけではありません。今回の見張り塔もActorのTickは最初からオフですが、Timerは動きます。止めたい処理に合う停止方法を選んでください。

Sponsored

おまけ:先に知っておくと良いこと

Timerを設定し直すと、どうなる?

同じActorの同じイベントにSet Timer by Eventを設定し直すと、既存のTimerは新しい設定でリセットされます。「呼ぶたびに必ずTimerが増殖する」という動きではありません。ただし繰り返し設定し直すと、次に実行されるまでの待ち時間も変わります。

今回のように、開始は出入りのイベントで行います。Event Tickから0.5秒のTimerを毎フレーム設定し直すと、待ち時間が終わる前に予約を作り直し続け、ScanStepが呼ばれない原因になります。

短すぎるTimeで、滑らかさを作ろうとしない

Timerもエンジンのフレーム更新の中で処理されます。Timeを非常に短くしても、画面がその間隔で細かく描き直されるわけではありません。フレームが遅れたときは、ループTimerの複数回分が同じフレームに実行されることもあります。

滑らかな回転が欲しいなら、時間に応じて値を変えるTimelineや、Tickと経過時間を使う方法を検討します。一定間隔で1回ずつ行う処理と、滑らかな見た目の更新は別の目的 です。

Timeが0以下ではTimerは動かず、設定済みなら解除されます。「毎フレームのつもりで0を入れる」は、Tick Intervalの0とは意味が違います。

Event Tickを使わなくても、処理全体がゼロになるわけではない

範囲外ではScanStepを実行しませんが、塔の描画やOverlapの検出などは残ります。TimerやTimelineへ置き換えるときも、内部で必要な更新が行われます。敵を増やしても負荷が変わらない、という意味ではありません。

重さを比べるなら、同じレベル・Actor数・カメラ位置・実行環境でStatsコマンドUnreal Insightsを使います。Print自体にも負担があるので、性能を測るときは確認用のPrintを外してください。

AIの移動は、別の担当へ任せる

追跡を作る場合も、毎フレームAI Move Toを発行する必要があるか見直します。ただしTimerを止めることと、すでに出した移動要求を止めることは別です。

実際の追跡にはAIControllerやNavMeshなどの準備が必要なので、Behavior Treeで敵AIを作る記事へ進めます。今回覚えた「開始・継続・停止を分ける」考え方は、そのまま役立ちます。

ComponentのTickも個別に確認する

ComponentにはActorと別のTick設定があります。自作の部品で毎フレームの更新が不要なら、Start with Tick Enabledなどの設定を確認します。動作中の切り替えにはSet Component Tick Enabledを使います。詳しくはComponentの使い分けを参照してください。

まとめ

処理したいタイミング使う仕組み
毎フレーム、滑らかに更新するEvent Tick
一定時間後・一定間隔で行うTimer
HP変更など、別の担当が起こした出来事へ反応するEvent Dispatcher
当たり判定の領域へ入る・出るOverlapイベント

見張り塔では、Overlapが「いつ動くか」を決め、Timerが「どの間隔で動くか」を決めました。Timerを作ったらHandleを保存し、不要になったらそのHandleで止めます。

Tickへつなぐ前に、毎フレーム必要なのか、少し間隔を空けてよいのか、変わったときだけでよいのかを考えると、処理の役割を整理しやすくなります。

参考リンク

Unreal Engine このセクションのノート98