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を残す場面と、回数だけでは性能を判断できない理由
Event Tickは、毎フレームの更新に使う
フレーム は、ゲームが状態を更新し、画面を描くときの1回分です。60FPSなら、1秒間におよそ60フレーム進みます。
Event Tickは、ActorのTickが有効で、Tick Intervalが0なら毎フレーム呼ばれます。たとえば60FPSで100体すべてがTick内の処理を実行すると、合計は 60 × 100 = 6000回/秒 です。
この数だけで「重い」とは決まりません。足し算1回と、周囲のActorを大量に探す処理では、1回の負担が違います。見るべきなのは 1回の処理内容、繰り返す頻度、実行するActor数 の組み合わせです。

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

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

一定間隔なら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度回る見張り塔 です。プレイヤーが検知範囲の外にいる間は止まり、範囲へ入ると回り始め、出るとその向きで止まります。
ステルスゲームの監視装置や、近くのときだけ働く迎撃塔へつながる仕組みです。今回は動く期間を分かりやすく見るため、腕を一定角度ずつ回します。滑らかな回転や敵への照準は、ここでは扱いません。

UE5のThird PersonテンプレートをBlueprintで作り、VariantがあればNoneを選びます。操作プレイヤーは1人とし、新しい練習フォルダで進めます。
① 見張り塔の部品を用意する
Actorを親に BP_Guard を作ります。DefaultSceneRootを残し、次の部品を追加します。位置・回転・Scaleは 親の部品から見た相対値 です。
| 名前 | 種類・親 | 設定 |
|---|---|---|
| Base | Static Mesh/DefaultSceneRootの子 | 標準Cylinder、位置(0, 0, 100)、Scale(1, 1, 2) |
| RadarPivot | Scene/DefaultSceneRootの子 | 位置(0, 0, 220)、Scale(1, 1, 1) |
| Arm | Static Mesh/RadarPivotの子 | 標準Cube、位置(100, 0, 0)、Scale(2, 0.2, 0.2) |
| DetectionSphere | Sphere 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を回すと塔の中心を軸に腕が回ります。

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 Presets | Custom |
| Collision Enabled | Query Only |
| Collision Responses | Pawnだけ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へ次の変数を追加します。
| 変数 | 型 | 役割・初期値 |
|---|---|---|
| ScanCount | Integer | 見回った回数。既定値0 |
| ScanHandle | Timer Handle | 動かしたTimerを後で止めるために保持 |
Timer Handle は、どのTimerを操作するか指定するための値です。ストップウォッチをいくつか持つときの「この1個を止める」という目印に相当します。自分で番号を入れず、Timerを作ったときの戻り値を保存します。
Event GraphにCustom Event ScanStep を作ります。まずは、呼ばれたら1回だけ腕を回す処理です。
- RadarPivotをグラフへドラッグし、その参照からAdd Local Rotationを作る。
- ScanStepの白い実行出力をAdd Local Rotationへつなぐ。TargetはRadarPivot。
- Delta RotationをX(Roll)0、Y(Pitch)0、Z(Yaw)30にする。必要ならピンを右クリックしてSplit Struct Pinで展開する。
- SweepとTeleportはオフにする。
Yaw は、上下方向のZ軸を中心に回す角度です。Add Local Rotationは「この部品の今の向きへ、指定した回転を足す」ので、呼ぶたびに腕が30度ずつ進みます。

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

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

| Set Timer by Event | 設定・接続 |
|---|---|
| Time | 0.5 |
| Looping | オン |
| Event | ScanStepの赤いEvent出力 |
| Return Value | Set ScanHandleの値 |
ScanStepの 赤いEvent出力から、Timerの赤いEvent入力へ つなぎます。白い線はTimerを開始する順番、赤い線は時間が来たら呼ぶイベントの指定です。ScanStepの白い出力は、先ほど作った回転処理につないだままにします。
Set Timer by Eventの白い出力からSet ScanHandleへつなぎ、Return Valueもその値の入力へ渡します。Time以外の開始遅延などは既定値のままにします。

ここまでできたら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秒表示します。

これで、検知範囲を出たときに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で検知する小さな実験です。
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の外から呼ばれるイベント を使います。

ActorのTickをオフにしても、TimerやComponentのTickまで一括で止まるわけではありません。今回の見張り塔もActorのTickは最初からオフですが、Timerは動きます。止めたい処理に合う停止方法を選んでください。
おまけ:先に知っておくと良いこと
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へつなぐ前に、毎フレーム必要なのか、少し間隔を空けてよいのか、変わったときだけでよいのかを考えると、処理の役割を整理しやすくなります。