プレイヤーループのカスタマイズ
プレイヤーループをカスタマイズして、ループの各イテレーションで Unity がシステムを更新する順序を変更します。
読み終わるまでの所要時間 13 分最終更新 3日前
Unity ランタイムアプリケーションは、プレイヤーループと呼ばれる連続ループで実行されます。プレイヤーループの各イテレーション中に、Unity はレンダリング、物理演算シミュレーション、入力処理などのタスクを実行するためにさまざまなシステムを呼び出します。
プレイヤーループ中に更新されたさまざまなシステムとサブシステムは、定義されたデフォルトの順序で呼び出されます。この順序は、 API の静的メソッドを使用して表示およびカスタマイズできます。デフォルトまたは現在のプレイヤーループを取得して、独自のカスタムプレイヤーループシステムを挿入したり、既存のプレイヤーループシステムを削除、並べ替え、または置き換えたりすることができます。
PlayerLoopプレイヤーループをカスタマイズする必要がある理由はいくつかあります。
- カスタム更新マネージャーの一部として独自のマネージ更新を作成すると、Unity のネイティブイベント機能の代わりによりパフォーマンスの高い機能を使用できます。詳細については、Unity ブログの「10000 更新コール」を参照してください。
- プレイヤー ループを特定のプラットフォームに合わせて最適化したい場合があります。例えば、モバイル ゲームの物理演算、AI、XR のアップデートを削除する場合などです。
- 編集モードまたは再生モードで更新ループを視覚化して、デバッグのヘルプに使用できます。
プレイヤーループへのアクセス
プレイヤーループは、一連のネストされたプレイヤーループシステムで構成され、それぞれが構造体です。ルートまたは最も外側のプレイヤー ループ システムは、プレイヤー ループ全体を表し、その下に他のプレイヤー ループ システムがネスト状になっています。
PlayerLoopSystemこの場合のプレイヤーループシステムとは、プレイヤーループ中に更新が必要なものを抽象化したにすぎません。デフォルトシステムは、オーディオや入力などのネイティブ Unity システムを表しますが、C# コードから独自のカスタムシステムを作成することもできます。
Unity のデフォルト プレイヤー ループにアクセスするには、 を使用します。現在エフェクト中のプレイヤー ループにアクセスするには、 を使用します。 で新しいカスタムプレイヤーループを適用しない限り、デフォルトと現在のプレイヤーループは同じになります。
PlayerLoop.GetDefaultPlayerLoopPlayerLoop.GetCurrentPlayerLoopPlayerLoop.SetPlayerLoopプレイヤーループ内の各システムには、それを識別する プロパティがあります。プレイヤーループシステム構造体を再帰的に反復し、各 プロパティのを出力して、プレイヤーループ構造体をコンソールにディスプレイできます。以下の例に示すように、 プロパティを使用して、追加、削除、または置換するプレイヤーループサブシステムを特定することもできます。デフォルト システムに有効なタイプは、 名前空間で使用できます。
PlayerLoopSystem.typetypeNametypeUnityEngine.PlayerLoopAPI リファレンスには、デフォルトのプレイヤーループを取得し、ネストされたプレイヤーループシステムを反復し、プロパティのを出力する方法の例が含まれています。コードは以下のコンソール出力を生成します。
PlayerLoop.GetDefaultPlayerLooptypeNameルートノード TimeUpdate WaitForLastPresentationAndUpdateTime 初期化 ProfilerStartFrame UpdateCameraMotionVectors DirectorSampleTime AsyncUploadTimeSlicedUpdate SynchronizeInputs SynchronizeState XREarlyUpdate EarlyUpdate PollPlayerConnection GpuTimestamp AnalyticsCoreStatsUpdate UnityWebRequestUpdate ExecuteMainThreadJobs ProcessMouseInWindow ClearIntermediateRenderers ClearLines PresentBeforeUpdate ResetFrameStatsAfterPresent UpdateAsyncInstantiate UpdateAsyncReadbackManager UpdateStreamingManager UpdateTextureStreamingManager UpdatePreloading UpdateContentLoading RendererNotifyInvisible PlayerCleanupCachedData UpdateMainGameViewRect UpdateCanvasRectTransform XRUpdate UpdateInputManager ProcessRemoteInput ScriptRunDelayedStartupFrame UpdateKinect DeliverIosPlatformEvents ARCoreUpdate DispatchEventQueueEvents Physics2DEarlyUpdate PhysicsResetInterpolatedTransformPosition SpriteAtlasManagerUpdate PerformanceAnalyticsUpdate FixedUpdate ClearLines NewInputFixedUpdate DirectorFixedSampleTime AudioFixedUpdate ScriptRunBehaviourFixedUpdate DirectorFixedUpdate LegacyFixedAnimationUpdate XRFixedUpdate PhysicsFixedUpdate Physics2DFixedUpdate PhysicsClothFixedUpdate DirectorFixedUpdatePostPhysics ScriptRunDelayedFixedFrameRate PreUpdate PhysicsUpdate Physics2DUpdate PhysicsClothUpdate CheckTexFieldInput IMGUISendQueuedEvents NewInputUpdate InputForUIUpdate SendMouseEvents AIUpdate WindUpdate UpdateVideo Update ScriptRunBehaviourUpdate ScriptRunDelayedDynamicFrameRate ScriptRunDelayedTasks DirectorUpdate PreLateUpdate AIUpdatePostScript DirectorUpdateAnimationBegin LegacyAnimationUpdate DirectorUpdateAnimationEnd DirectorDeferredEvaluate AccessibilityUpdate UIElementsUpdatePanels EndGraphicsJobsAfterScriptUpdate ConstraintManagerUpdate ParticleSystemBeginUpdateAll Physics2DLateUpdate PhysicsLateUpdate ScriptRunBehaviourLateUpdate PostLateUpdate PlayerSendFrameStarted DirectorLateUpdate ScriptRunDelayedDynamicFrameRate PhysicsSkinnedClothBeginUpdate UpdateRectTransform PlayerUpdateCanvases UIElementsRepaintPanels UpdateAudio VFXUpdate ParticleSystemEndUpdateAll EndGraphicsJobsAfterScriptLateUpdate UpdateCustomRenderTextures XRPostLateUpdate UpdateAllRenderers UpdateLightProbeProxyVolumes EnlightenRuntimeUpdate UpdateAllSkinnedMeshes ProcessWebSendMessages SortingGroupsUpdate UpdateVideoTextures UpdateVideo DirectorRenderImage PlayerEmitCanvasGeometry UIElementsRenderBatchModeOffscreen PhysicsSkinnedClothFinishUpdate FinishFrameRendering BatchModeUpdate PlayerSendFrameComplete UpdateCaptureScreenshot PresentAfterDraw ClearImmediateRenderers PlayerSendFramePostPresent UpdateResolution InputEndFrame TriggerEndOfFrameCallbacks GUIClearEvents ShaderHandleErrors ResetInputAxis ThreadedLoadingDebug ProfilerSynchronizeStats MemoryFrameMaintenance ExecuteGameCenterCallbacks XRPreEndFrame ProfilerEndFrame GraphicsWarmupPreloadedShaders ObjectDispatcherPostLateUpdate
デフォルトプレイヤーループへのカスタム更新の挿入
プレイヤーループをカスタマイズする推奨かつリスクの低い方法は、カスタムプレイヤーループシステムをデフォルトのプレイヤーループに挿入することです。こうすることで、Unityのビルトイン システムを停止することなく、独自のカスタム更新ロジックを追加できます。
PlayerLoop.SetPlayerLoopCustomUpdateInsertSystemCustomUpdate- イベントを クラスの public 静的フィールドとして宣言します。
InsertSystem
public static event Action AddCustomUpdate;
- このイベントを呼び出すように メソッドの定義を変更します。
CustomUpdate
private static void CustomUpdate() => AddCustomUpdate?.Invoke();
その後、任意の MonoBehaviour スクリプトから次のようにカスタム更新をサブスクライブできます。
using UnityEngine;public class CustomUpdateFromEvent :MonoBehaviour{ private void OnEnable() { InsertSystem.AddCustomUpdate += MyCustomUpdate; } private void Update() { Debug.Log("Update"); } private void LateUpdate() { Debug.Log("Late Update"); } private void OnDisable() { InsertSystem.AddCustomUpdate -= MyCustomUpdate; } private void MyCustomUpdate() { Debug.Log("Custom update from an event that your MonoBehaviour scripts can subscribe to."); }}
プレイヤーループ内のデフォルトシステムを置き換える
以下の例では、プレイヤーループ内のデフォルトシステムをカスタム更新に置き換えます。この例ではシステムを置き換えますが、PlayerLoopSystem.type 識別子を指定することでプレイヤーループ内のすべてのシステムを置き換えることができます。デフォルト システムの有効タイプは、前のセクションで示したデフォルト プレイヤー ループを使用するか、名前空間から取得できます。
PreUpdate.AIUpdateUnityEngine.PlayerLoopusing UnityEngine.LowLevel;using UnityEngine.PlayerLoop;using UnityEngine;// Replace an existing system in the Unity Player Loop with a custom update.public class MyReplacementCustomUpdate { } // Empty class to use as a type identifier for the custom updatepublic class SystemReplacement{ //Run this method on runtime initialization [RuntimeInitializeOnLoadMethod] private static void AppStart() { // Retrieve the default Player loop system.デフォルトがすでに以前変更されている場合は、代わりに現在のループを取得します。 var defaultSystems = PlayerLoop.GetDefaultPlayerLoop(); // Create a custom update system to replace an existing one var customUpdate = new PlayerLoopSystem() { updateDelegate = CustomUpdate, type = typeof(MyReplacementCustomUpdate) }; // Specify the system to replace as the type parameter, in this case PreUpdate.AIUpdate ReplaceSystem<PreUpdate.AIUpdate>(ref defaultSystems, customUpdate); PlayerLoop.SetPlayerLoop(defaultSystems); } // Custom update method that will be called in the Player Loop private 静的 void CustomUpdate() { Debug.Log("Custom update from a replacement system."); } //Recursively replace a system of type T with a replacement system in the Player Loop private static bool ReplaceSystem<T>(ref PlayerLoopSystem system, PlayerLoopSystem replacement) { if (system.type == typeof(T)) { system = replacement; return true; } if (system.subSystemList != null) { for (var i = 0; i < system.subSystemList.Length; i++) { if (ReplaceSystem<T>(ref system.subSystemList[i], replacement)) { return true; } } } return false; }}
その他のリソースと例
- 📚 ドキュメント: イベント機能実行順序
- API リファレンス
- 📚 ドキュメント: 10000 更新コール
- Unity Discussions での👥 コミュニティ:トピック
LowLevel.PlayerLoop