自動ドアが開いている途中で、プレイヤーが引き返した。そのとき、ドアがいったん全開になってから閉じるより、今の高さから戻り始める方が自然です。
こうした「時間をかけて動き、途中から逆にも進める」仕掛けに使えるのが、Timelineです。この記事では上へスライドするドアを作り、1秒で開く動きから、近づくと開き、離れると閉じる動きへ仕上げます。

この記事でわかること
- キーとカーブで、時間に合わせた値を作る方法
- Timeline・Lerp・Setがそれぞれ担当すること
- PlayとReverseで、途中の位置から開閉する仕組み
- カーブと再生速度を変え、動きの違いを確かめる実践
Timelineは、時間に合わせて値と合図を出す
Timelineには、「この時刻には、この値にする」という目印を置けます。この目印がキーです。たとえば、0秒で0、1秒で1という2つのキーを置くと、その間の値も計算して取り出せます。
キーと、その間をつなぐ変化の線をカーブと呼びます。横軸が時間、縦軸が値です。0から1までを直線でつなげば、0.5秒では0.5になります。

ここでの0〜1は、ドアの高さそのものではありません。「0なら閉じている」「1なら開き終わった」という進み具合として使います。後で Lerp を通し、実際の位置へ変換します。
また、Timelineには値の出力とは別に、白い実行ピンがあります。特に使うのが次の2つです。
| 出力 | 使い道 |
|---|---|
| Update | 値が更新されたら、その値を位置などへ反映する |
| Finished | 最後まで再生し終わったら、次の処理へ進む |
Timelineが値を出しても、それだけでドアは動きません。Updateから位置を設定する処理を呼び、計算した位置を渡すところまでつなぎます。
時間の管理をTimelineへ任せる
同じドアは、毎フレーム呼ばれる Event Tick でも作れます。その場合は「何秒たったか」「どこで止めるか」「逆方向へ戻すか」を、自分で管理します。
Timelineでは、再生位置と再生方向を持ち、カーブを読みながら進んでくれます。繰り返し再生をオフにしておけば、端まで進むと再生が終わります。ドア側は、開始・反転のきっかけと、値の反映に集中できます。

Event Tickに時間の足し算を書かなくてよいのが、今回の使いやすさです。Timelineも時間に合わせた更新を使うので、内部の更新処理までなくなるわけではありません。動く相手を追い続ける処理など、Tickが向く場面もあります。使い分けはEvent TickとTimerの記事でも扱っています。
PlayとReverseは、今の再生位置から進む
Timelineは「今、何秒の場所を再生しているか」を持っています。この時刻を再生位置と呼びます。ドアのワールド上の位置とは別のものです。
| 入力 | 再生位置をどう扱うか |
|---|---|
| Play | 今の時刻から前へ進む |
| Play from Start | 0秒へ戻してから前へ進む |
| Reverse | 今の時刻から後ろへ戻る |
| Reverse from End | 終端へ移ってから後ろへ戻る |
| Stop | 今の時刻を保持して止まる |
1秒のTimelineが0.5秒まで進んでいるときにReverseを呼ぶと、0.5秒から0秒へ戻ります。最初に1秒の場所へ飛ぶ必要はありません。これをドアの位置に使えば、開いている途中の高さから閉じられます。

逆に、閉じている途中にPlayを呼べば、そこからまた開く方向へ進みます。今の位置を引き継いで往復したいので、PlayとReverseを組み合わせます。
Finishedは、前方向なら終端、逆方向なら始端へ着いたときにも呼ばれます。「ドアが開き終わったときだけ」の処理へ使うなら、再生方向を出すDirectionがForward(前方向)かも調べます。Stopは途中で止める指示なので、止めただけで はFinishedを呼びません。
トラックは、変化させる値の種類で選ぶ
Timelineで1つの値の変化を編集する列が、トラックです。追加したトラックの名前が、イベントグラフにあるTimelineの出力ピン名になります。
| トラック | 出すもの | 使う例 |
|---|---|---|
| Float Track | 1つの数値 | 開き具合、音量、透明度 |
| Vector Track | X・Y・Zの3つの数値 | 位置やScale |
| Color Track | 色 | ライトの色や表示色 |
| Event Track | 指定した時刻の実行の合図 | 途中で音や表示を出す |

今回使うのは、Float Trackを1本だけです。名前は Alpha とし、0から1へ変えます。Alphaは、ここでは「どこまで開いたか」を表す数値です。
数値を出すトラックと違い、Event Trackは、その時刻を通ったときに処理を呼ぶためのものです。たとえば0.8秒にキーを置けば、開き終わる少し前に合図を出せます。逆再生でも通る時刻なので、開くときだけ鳴らしたい音などは再生方向も考えてつなぎます。
実践:まずは1秒で開くドアを作る
Third PersonのBlueprintプロジェクトを使います。新規作成時に「Variant」がある版では None を選びます。コンポーネントと変数を作り、Blueprintのピンをつなぐ操作を知っている人向けです。
1. ドアと、近づいたことを調べる範囲を作る
Actorを親にBlueprint Class BP_AutoDoor を作ります。DoorMesh というStatic Meshと、TriggerBox というBox Collisionを加え、両方をDefaultSceneRootの子にします。
DoorMeshには、Engine/BasicShapes の標準Cubeを割り当てます。見つからなければ、アセット選択欄でエンジンコンテンツを表示します。
| 項目 | DoorMesh | TriggerBox |
|---|---|---|
| Relative Location | X=0 / Y=0 / Z=150 | X=0 / Y=0 / Z=150 |
| Rotation | すべて0 | すべて0 |
| Scale | X=0.2 / Y=2 / Z=3 | すべて1 |
| Box Extent | — | X=200 / Y=200 / Z=200 |
Relative Locationは、親から測った位置です。高さ300cmのドアの中心をZ=150に置くので、ドアの底はRootの高さに揃います。
Box Extentは、箱の中心から各面までの距離です。200なら、端から端までは400cmになります。TriggerBoxはドアの前後も含む範囲を持ちます。DoorMeshの子にすると範囲まで上下してしまうので、同じRootの下へ分けます。

DoorMeshはMobilityをMovable、Simulate Physicsをオフ、Collision PresetsをBlockAllにします。これで、Blueprintから動かせる、プレイヤーを遮る板になります。
TriggerBoxは「ぶつかって止める壁」ではなく「入った・出たを調べる範囲」です。次の設定にします。
- Collision Presets:Custom
- Collision Enabled:Query Only
- Object Type:WorldDynamic
- Collision Responses:いったんすべてIgnoreにし、PawnだけOverlap
- Generate Overlap Events:オン
Query Onlyは、重なりなどを調べるために使う設定です。PawnだけOverlapにすることで、床やドア自身を検知しないようにします。今はまだ、重なったときのイベントはつなぎません。
2. 閉じた位置と、開いた位置を決める
Vector型の変数を2つ作り、コンパイルしてから既定値を入れます。
| 変数 | 既定値 | 意味 |
|---|---|---|
| ClosedLocation | X=0 / Y=0 / Z=150 | 閉じたドアの中心 |
| OpenLocation | X=0 / Y=0 / Z=370 | 開いたドアの中心 |
150から370へ動くので、移動量は220cmです。開いた ときのドアの底は220cmになり、下を通れる高さになります。
3. 1秒で0から1へ進むTimelineを作る
イベントグラフの何もないところを右クリックし、Add Timeline を選びます。名前を DoorTimeline にし、ダブルクリックして編集画面を開きます。
Float Trackを追加して Alpha と名付けます。グラフを右クリックしてキーを2つ追加し、選択したキーのTimeとValueを次に揃えます。
| キー | Time | Value |
|---|---|---|
| 始まり | 0 | 0 |
| 終わり | 1 | 1 |
2つのキーを選んで右クリックし、補間を Linear にします。これはキーの間を直線でつなぎ、値を一定のペースで変える設定です。
Lengthは 1、Use Last Keyframeはオフ、AutoPlayとLoopもオフにします。今回は、入力したLengthを終端として使います。Use Last Keyframeを使う場合は最後のキーを終端にできますが、まずは長さを明示して揃えましょう。
4. Lerpで位置を計算し、Updateから反映する
イベントグラフへ戻り、Lerp(Vector) を置きます。ClosedLocationをGetで取り出し、その黄色いピンからLerpを検索すると、Vectorを扱うものを選べます。
| Lerpの入力 | 接続元 |
|---|---|
| A | Get ClosedLocation |
| B | Get OpenLocation |
| Alpha | DoorTimelineのAlpha |

Lerpは、AとBの間のどこを使うかをAlphaで選びます。0ならA、1ならB、0.5なら中間です。
| Timelineの時刻 | Alpha | 計算されるドア中心のZ |
|---|---|---|
| 0秒 | 0 | 150 |
| 0.5秒 | 0.5 | 260 |
| 1秒 | 1 | 370 |
次に、コンポーネント一覧からDoorMeshをグラフへドラッグし、その青い出力から Set Relative Location を作ります。
- Target:DoorMesh
- New Location:LerpのReturn Value
- 白い実行入力:DoorTimelineのUpdate
- Sweep:オフ
Lerpには白い実行線を通しません。 値を計算する色付きの線と、位置の設定を呼ぶ白い線を分けてつなぎます。
ClosedLocationとOpenLocationは親基準の位置なので、反映先もSet Relative Locationへ揃えています。Actorをレベルの別の場所へ置いても、この2つの値をそのまま使えます。
5. Play開始時に、一度だけ開いてみる
確認用に、Event BeginPlay の白い出力をDoorTimelineのPlayへつなぎます。コンパイルして保存します。

この図では位置を反映する側を見せています。Alphaは先ほどのLerpへつなぎ、そのReturn Valueを、図の黄色い「Lerpの結果」の線としてNew Locationへ渡します。
BP_AutoDoorをレベルへ1つ置き、ActorのScaleを 1, 1, 1、回転を0、Rootの高さを床へ合わせます。プレイヤーの開始位置からドアを見られるように配置します。
Playすると、ドアが1秒かけて220cm上がり、そこで止まれば成功です。まだ近づく判定は使っていないので、離れた場所から見ていても開きます。
ここまでで、Timelineが時間を進め、Lerpが途中の位置を計算し、UpdateからSetで反映する部分を確認できました。
近づくと開き、離れると閉じるようにする
Playを止め、確認用のBeginPlayからPlayへの線を外します。今度は、TriggerBoxへ出入りしたときに再生方向を変えます。
1. プレイヤーの出入りを受け取る
コンポーネント一覧でTriggerBoxを選び、「詳細」のEventsから On Component Begin Overlap と On Component End Overlap を追加します。
Overlapは、ぶつかって押し返すのではなく、範囲が重なっている状態です。Beginは重なり始めた合図、Endは重なりがなくなった合図です。
イベントの Other Actor には、入ってきた、または出ていった相手が入ります。ここではプレイヤーだけに反応させたいので、両方のイベントで次の判定を作ります。
- Other Actorの青いピンから
==を検索し、Objectの等価比較を作 る - もう片方へ、
Get Player Pawn(Player Index=0)のReturn Valueを渡す - 比較結果をBranchのConditionへつなぐ
- イベントの白い実行出力を、そのBranchへつなぐ
== で調べるのは、相手が「1人目のプレイヤーが操作しているPawnと同じものか」です。形や名前を比べているわけではありません。
重なりイベントは、検知する側と相手側の両方で有効にする必要があります。テンプレートの BP_ThirdPersonCharacter を開き、Capsule ComponentはGenerate Overlap Eventsをオン、見た目のMesh側はオフにします。今回の判定は、体を囲む衝突判定のカプセル1つで行う形です。変更したらキャラクターもコンパイルして保存し、BP_AutoDoorへ戻ります。
2. 同じTimelineのPlayとReverseへつなぐ
作った2つのBranchのTrueを、次のようにつなぎます。Falseは空けます。
| イベント側のBranch | Trueの行き先 |
|---|---|
| Begin Overlap | DoorTimelineのPlay |
| End Overlap | DoorTimelineのReverse |

図はBegin側です。End側にも、Endイベント自身のOther Actorを比較する処理とBranchを作り、TrueをReverseへつなぎます。
Timelineは増やしません。最初に作ったDoorTimelineの入力側へ、2本をつなぎます。Updateから位置を設定する部分も、そのまま使います。
コンパイルしてPlayし、ゲーム画面をクリックします。最初は範囲の外から近づいてください。ドアの前で立ち止まると全開になり、範囲から離れると閉じれば、出入りの判定もできています。
3. 開ききる前に引き返す
次は、ドアが動き始めたらすぐに後ろへ下がってみてください。範囲へ少し入り、すぐ出るイメージです。上まで行かず、途中の高さから閉じ始めることを確認します。
途中までしか開いていなければ、閉じるのにも1秒全部はかかりません。たとえば再生位置0.4秒でReverseしたなら、通常の再生速度では、そこから約0.4秒で0へ戻ります。
閉じている途中に再び近づけば、その高さから開き直します。PlayとReverseが、今の再生位置を引き継いでいるためです。
Reverse from Endと比べる
Playを止め、End Overlap側のBranchのTrueを、Reverseから Reverse from End へ一時的につなぎ替えます。
同じように、開き始めてすぐ範囲から出てください。今度は終端から逆再生するため、いったん全開の高さへ飛んでから閉じる動きになります。今の高さから戻したいドアには、Reverseの方が合うと分かります。
確認後はPlayを止め、接続をReverseへ戻して、途中から閉じることを再確認します。開く側のPlayをPlay from Startへ替える場合も、閉じ途中に入り直すと、0秒へ戻ってから開き直す違いが出ます。
カーブと再生速度を変えてみる
同じ1秒の動きでも、途中でどの値を通るかによって印象が変わります。まずは、キーを1つ増やして比べてみ ましょう。
途中のキーで、前半と後半の速さを変える
Playを止め、DoorTimelineのAlphaへ、Time=0.5、Value=0.25 のキーを追加します。3つのキーをすべてLinearに揃え、Lengthは1のままにします。
以前は0.5秒で半分開いていましたが、今度は同じ時刻で4分の1だけ開きます。残りの半分の時間で、残り4分の3を進むので、前半はゆっくり、後半は速くなります。

これは直線2本をつなぐ例なので、中間で速さが切り替わります。滑らかな加速・減速へ整えたい場合は、Autoなどの曲線による補間や、Userで接線を調整する方法があります。接線は、キーの近くで線がどちらへどれくらい傾くかを決めるものです。
| 補間 | キーの間をどうつなぐか |
|---|---|
| Linear | 直線でつなぐ |
| Constant | 次のキーまで値を保ち、そこで切り替える |
| Auto | 周囲のキーに合わせて曲線を自動調整する |
| User / Break | 接線を自分で調整する。Breakでは前後を別々に調整できる |
Autoを選べば、どんなキーの配置でも同じ緩急になるわけではありません。カーブの形を見て、Playで動きも確かめてください。今回の比較 が終わったら、中間のキーを削除し、最初の2キー・Linearへ戻します。
Set Play Rateで、動き全体を速くする
「マイブループリント」には、DoorTimelineを指定するための同名の変数もあります。これをGetで取り出し、青いピンから Set Play Rate を作ります。TargetはDoorTimelineです。
先ほど接続を外したBeginPlayから、このSet Play Rateへ白い線をつなぎ、New Rateを 2 にします。Playすると、1秒ぶんのTimelineを2倍速で再生するため、全開まで約0.5秒になります。
| New Rate | 1秒のTimelineを最後まで再生する時間 |
|---|---|
| 0.5 | 約2秒 |
| 1 | 約1秒 |
| 2 | 約0.5秒 |

カーブは「途中の進み方」、Play Rateは「その時間軸を進む速さ」です。開く高さはOpenLocationが持っています。何を変えると何が変わるかを分けておくと、調整しやすくなります。
比較後はNew Rateを1へ戻します。BeginPlayからのSet Play Rateは、そのまま残して構いません。
うまく動かないときのチェック
| 症状 | 確認するところ |
|---|---|
| 最初のBeginPlay確認でも動かない | Playへ白い線があるか。Alphaに2つの異なる値のキーがあるか。UpdateからSetへつながっているか |
| 時間がたつと一瞬で開く | SetをUpdateではなくFinishedから呼んでいないか。補間がConstantになっていないか |
| 近づいても動かない | TriggerBoxのイベントか。PawnをOverlapにしたか。双方のGenerate Overlap EventsとOther Actorの比較を確認 |
| 開いたり閉じたりを繰り返す | TriggerBoxがDoorMeshの子になっていないか。プレイヤーの見た目のMeshまで重なりイベントを出していないか |
| ドアが別の場所へ飛ぶ | Set Relative Locationを使い、Closed/Openの値が親基準で揃っているか |
| 開いた後も再生を繰り返す | Loopがオフか |
| 開いたまま閉じない | End Overlap側のTrueがReverseへつながっているか。まだ範囲内にいないか |
| 最後の高さまで届かない | Lengthが最後のキーより短くないか。Alphaの終わりのValueが1か |
| 閉じたドアをすり抜ける | DoorMeshのCollision PresetsがBlockAllか。Simulate Physicsがオフか |
どこまで動いているか分からないときは、UpdateからPrint Stringを呼び、AlphaをIn Stringへ渡すと、値の変化を表示できます。数値から文字へ の変換が自動で入ります。確認後は元のSetへの接続へ戻します。表示の使い方はPrint Stringの記事も参考になります。
Timelineを追加できる場所
この記事のTimeline本体は、ActorのBlueprintのイベントグラフへ追加します。関数やマクロのグラフでは、同じAdd Timelineを使えません。Widget BlueprintやActor ComponentのBlueprintでも、そのまま同じ形には作れません。

一方、すでに作ったTimelineへ指示を出すことは別です。関数内でDoorTimelineの変数を取り出し、PlayやStopなど、Timeline Componentの操作ノードを呼べます。時間をかけて値を更新する本体と、それに再生を指示する部分を分けて考えてください。
UIの位置や透明度ならUMGのWidget Animation、カメラやキャラクターをまとめた演出ならSequencerも使えます。置けない場所で無理に同じノードを探し続けず、動かしたい対象に合う機能を選びましょう。
おまけ:先に知っておくと良いこと
- 同じ0〜1を、別の値へ使える:LerpのA/Bを回転にすれば向き、色にすれば色の変化へ使えます。ただしLerpの型と、最後に反映するノードも合わせて変えます。マテリアルを光らせたい場合は、Dynamic Material Instanceの記事へ進めます。
- 動く相手を追うなら、別の組み合わせもある:毎回変わる目標へ現在値を近づけ続ける用途には、Interp To系が使いやすい場合があります。回転と補間の記事では、砲塔が相手を追う例で比べています。
- カーブを共有できる:Curve Floatなどのアセットを作り、トラックのExternal Curveに指定すると、カーブの形を複数のBlueprintで使えます。これは第5のトラック型ではなく、カーブを外のアセットから読む方法です。
- 開いたことを外へ知らせる:FinishedからDirectionを調べ、ForwardのときだけEvent Dispatcherで通知すれば、閉じ終わったときの通知と分けられます。
- 検知する人数が増えたら、閉じる条件も変わる:今回は1人のプレイヤーをカプセル1つで検知しました。複数人が通るドアなら、1人出た瞬間に閉じるのではなく、まだ範囲に人が残っていないかも管理します。
まとめ
Timelineが時間と進み具合を持ち、Lerpが途中の位置を計算し、UpdateからSetでドアへ反映する。この分担を作ると、開く高さ、動きの緩急、再生速度を別々に調整できます。
ドアが最後まで開くことに加え、途中で引き返したときの動きも試してみてください。PlayとReverseが「今の再生位置から進む」という意味を、実際の開閉で確かめられます。