ティック
「ティック」とは、通常は 1 フレームに一回という一定間隔でコードまたはブループリント スクリプトをアクタやコンポーネントで実行することです。ゲームのアクタやコンポートがティックする順序やエンジンがフレーム毎に行う他のタスクの順序を理解することは、1 フレームのずれを回避するうえで重要です。また、ゲームが実行する方法の一貫性を保つためにも重要です。アクタとコンポーネントはフレーム毎にティック、設定された最小の時間間隔でティック、またはティックしないように設定できます。さらに、エンジンのフレーム毎の更新ループで様々なフェーズをまとめてグループ化して、特定のティックの完了を待ってから開始するように個別に指示することができます。
ティック グループ
アクタとコンポーネントは、最小ティック間隔を指定しない限り、 1 フレーム毎に 1 回ティックします。ティックはコードまたはブループリントで割り当てることができるティック グループに従い行われます。アクタまたはコンポーネントのティック グループを使って、フレームの中でいつティックするか、他のエンジン内のフレーム プロセス、主に物理シミュレーションに相対的にいつティックするかを判断します。各ティック グループに割り当てられているすべてのアクタ、コンポーネントのティックが終了してから、次のティック グループが開始します。ティック グループ以外に、アクタやコンポーネントでティックの依存関係を設定することができます。つまり、指定した他のアクタのティック、またはコンポーネントのティックの関数が終了するまでティックしないようにします。ティック グループとティックの依存関係を使用することは、複数のアクタやコンポーネントを伴う物理に依存する挙動やシーケンシャルなゲームプレイの挙動などに関してゲームを適切に動作させるために不可欠です。
以下はゲームプレイ用途で利用可能なティック グループを、フレーム中の実行順序で、各グループの内容を合わせて示したものです。
ティック グループの順序
ティック グループ | エンジンのアクティビティ |
---|---|
TG_PrePhysics | フレームの始まり。 |
TG_DuringPhysics | このステップに到達するまでに物理シミュレーションが開始します。このグループのティック中に、または、すべてのグループのメンバーをティック後にシミュレーションが終了し、エンジンの物理データを更新します。 |
TG_PostPhysics | このステップが始まるまでには、物理シミュレーションが完了し、エンジンが現在のフレーム データを使用します。 |
n/a | Latent アクションを処理し、ワールド タイマー マネージャをティックし、カメラを更新し、レベル ストリーミングのボリュームとストリーミング オペレーションを更新します。 |
TG_PostUpdateWork | n/a |
n/a | フレームの前の方で作成されたアクタのスポーンを遅らせる処理をします。そのフレームとレンダリングを終了します。 |
TG_PrePhysics
- アクタが物理ベースのアタッチメントを含む物理オブジェクトと相互作用する場合に使用するティック グループです。使用することで、アクタの移動が完了し、物理シミュレーションに加えることができます。
- このティック中の物理シミュレーション データは 1 フレーム分古くなります。すなわち、前回のフレームで画面にレンダリングされたデータになります。
TG_DuringPhysics
- これは物理シミュレーションと同時に実行するため、ティック中の物理データが前のフレームのものか、現在のフレームのものであるかが不明です。物理シミュレーションはこのティック グループ中にいつでも終了することができます。これを示す情報はどこにも示されません。
- 物理シミュレーション データは、現在のフレームまたはひとつ前のフレームになるため、このティック グループは物理データが関係ないロジックや、1 フレームずれても問題ないものに限り使用することをお勧めします。一般的なケースでは、インベントリ画面やミニマップ表示の更新などが考えられます。この場合、物理データは全く関連がないか、1 フレームの遅れがあっても問題にならない程度に粗く表示されます。
TG_PostPhysics
- フレームの物理シミュレーションの結果は、このティック グループ実行までに得られます。* このグループは、武器または移動のトレースに使うとよいでしょう。 このフレームがレンダリングされるときのように、すべての物理オブジェクトが最終的な位置にあることがわかるようにします。これは、シューティング ゲームのレーザーの照準のようなものの場合に特に役立ちます。この場合、レーザー ビームは最終位置でプレイヤーの銃から出てるように見えなければなりません。たとえ、1 フレーム遅れても非常に目立つでしょう。
TG_PostUpdateWork
- TG_PostPhysics の後に実行します。これまで主な機能は、最後と考えられる瞬間の情報をパーティクル システムに入力することでした。
- TG_PostUpdateWork はカメラの更新後に実行されます。カメラがどこをポイントしているかを正確に把握することに依存するエフェクトがある場合、こうしたエフェクトを制御するアクタを入れるのに良い場所です。
- これは、フレームで他のどれよりも後に実行することを意図したゲーム ロジックでも使用できます。ファイティング ゲームで同じフレームで互いにつかみあいの喧嘩をしている 2 キャラクターに対応するなどです。
ティックの依存関係
AddTickPrerequisiteActor
関数と AddTickPrerequisiteComponent
関数はアクタとコンポーネントに存在し、指定した他のアクタやコンポーネントがティックを終了するまで、こうした関数が呼び出されたアクタまたはコンポーネントがティックを待つように設定します。フレームでほぼ同じ時間に起こるが、あるアクタやコンポーネントが他のものが必要とするデータをセットアップする場合に特に役立ちます。ティック グループではなくこれを使う理由は、同じグループ内では多くのアクタが並列して更新される可能性があるからです。グループ全体が終了するまで待ってティックするのではなく、アクタがひとつ以上の他のアクタに個別に依存しているだけの場合、あるアクタのグループを全く新しいグループに移動する必要はないでしょう。
例
Tick Group/Tick Dependency の使用例
上記の各ティック グループの使用例として、プレイヤーがレーザーの狙いを定めるアニメートしたアクタを制御するゲームを思い描いてみてください。レーザーは衝撃点に照準を合わせる特殊な十字線のアクタを配置します。特定のターゲット オブジェクトにレーザーの照準があっていればメーターがいっぱいになり、HUD アクタがこのメーターを画面に表示します。
プレイヤーのアニメートしたアクタは、TG_PrePhysics で動き、アニメートします。物理シミュレーションしたオブジェクトが、アクタに従い正しく相互作用するためには、物理の前にアクタをアニメートする必要があります。
HUD はどのティック グループでも更新できますが、以下の 2 つの理由から、TG_DuringPhysics が適切です。ひとつめは、ゲームの物理シミュレーションと直接相互作用したり、そのデータを使用したりしないため、TG_DuringPhysics の使用が可能です。ふたつめは、HUD が更新を終えるまで物理シミュレーションを強制的に待たせたり、物理シミュレーションが終わるまで HUD を強制的に待たせる理由がないからです。HUD はゲームで 1 フレーム分遅れることに注意してください。すなわち、あるフレームでターゲット オブジェクトをポイントしても、次のフレームまでメーターに反映されません。
十字線のアクタは TG_PostPhysics で更新されます。このようにして、フレームの最後でレンダリングされるため、十字線側では、シーンに対してトレースしていることを認識し、意図したとおりにオブジェクトのサーフェスに正確に表示されることがわかります。ターゲット オブジェクトの正確な位置に基づきメーターの値が調整されることもわかります。
最後に、TG_PostUpdateWork ではレーザーのパーティクル エフェクトは照準アクタと十字線の両方の最終位置で更新されます。
ティックの依存関係を使って、TG_PostUpdateWork の必要性をなくすことができます。レーザー パーティクルを十字線アクタと一緒に TG_PostPhysics に配置することができます。ティックの依存関係を使って十字線のティック後にのみレーザーが十字線の位置で更新されるようにします。レーザーのティックの依存関係を十字線に設定することで、レーザーの更新が早すぎないようにすることができますが、関係ない他の post-physics のティックは待ちません。これはレーザーを別のティック グループに移動するよりも効率的です。
ティックの依存関係のメリットがない例として、次のようなものがあります。十字線自体が照準アクタに依存してティックする必要はありませんが、照準アクタがティックを終了してから十字線はティックを開始することができます。ティックの依存関係が不要な理由は、照準アクタは pre-physics ですが、十字線が post-physics であるからです。別のティック グループに入っているため、グループ自体の順序で常に実行させることができます。各ティック グループのすべてのアクタやコンポーネントのティックを終了してから、次のティック グループが開始できるようになるからです。
アクタのスポーン
BeginPlay
では、アクタはそのプライマリ ティック関数とそのコンポーネントのティック関数をエンジンに登録します。アクタのティック関数は PrimaryActorTick
メンバーを介して特定のティック グループで実行するように設定したり、完全に無効にすることができます。これは一般的にコンストラクタで行い、BeginPlay
が呼び出される前にデータが正確に設定されるようにします。以下は一般的に使用されるコードの例です。
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bTickEvenWhenPaused = true;
PrimaryActorTick.TickGroup = TG_PrePhysics;
コンポーネントのティック
アクタと同様、コンポーネントも別々のティック グループに配置することができます。これまでは、アクタのすべてのコンポーネントは、アクタのティック中にティックされていました。これは現在でも行われますが、別のグループに入れる必要のあるコンポーネントは、いつティックするかを管理するリストに追加されます。コンポーネントのティック グループへの配置は、アクタと同様の基準を使って行います。コンポーネントのティック構造体は、アクタが使用するものとは異なる名前が付けられますが、同じように機能します。
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.bTickEvenWhenPaused = true;
PrimaryComponentTick.TickGroup = TG_PrePhysics;
PrimaryActorTick
は、アクタの Tick()
関数を使用していますが、PrimaryComponentTick は Actor コンポーネントの TickComponent()
を使用することを覚えておいてください。
ティック機能の詳細
アクタまたはコンポーネントのデフォルトのティック関数は、ゲーム中に AActor::SetActorTickEnabled
関数とUActorComponent::SetComponentTickEnabled
関数を使ってそれぞれ有効または無効にすることができます。さらにアクタやコンポーネントは複数のティック関数を持つことができます。これは FTickFunction
から継承し、ExecuteTick
関数と DiagnosticMessage
関数をオーバーライドする構造体を作成して行います。デフォルトのアクタとコンポーネントのティック関数の構造体は、独自のものを作る方法を示す良い例であり、EngineBaseTypes.h のFActorTickFunction
と FComponentTickFunction
という名前の場所にあります。
ご自身のティック関数構造体をアクタまたはコンポーネントに追加後、通常は所有しているクラスのコンストラクタで初期化することができます。ティック関数を有効にして登録する一般的なやり方は、AActor::RegisterActorTickFunctions
をオーバーライドしてティック関数の構造体の SetTickFunctionEnable
に対する呼び出しを追加し、その後に所有するアクタのレベルを引数として RegisterTickFunction
の呼び出しを追加します。このプロセスの最終結果として、作成したアクタやコンポーネントが複数回ティック可能になります。これには、異なるグループでのティックやティック関数毎に個々の依存関係でのティックを含みます。手動でティックの依存関係を設定するには、別のものに依存させたいティック関数の構造体上でAddPrerequisite
を呼び出し、依存関係として使用したいティック関数の構造体に渡します。