Unity 中的 PlayerLoop
在Unity 2018的PlayerLoop中,禁用Unity调用每一帧的处理或在Update之前添加您自己的处理
这次,使用从Unity 2018添加的PlayerLoop,您可以添加或自定义您自己的事件,例如Unity事件(Update,FixedUpdate)等
Unity 2018.1 引入了一个名为PlayerLoop 的功能。这是Unity引擎重新更新过程的顺序,或停止特定的事件,或插入自己的处理似乎是有可能这样。
获取标准事件列表
using UnityEngine; using UnityEngine.Experimental.LowLevel; public class ShowPlayerLoop { [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void Init() { var playerLoop = PlayerLoop.GetDefaultPlayerLoop(); foreach (var header in playerLoop.subSystemList) { Debug.LogFormat("------{0}------", header.type.Name); foreach (var subSystem in header.subSystemList) { Debug.LogFormat("{0}.{1}", header.type.Name, subSystem.type.Name); } } } }
首先var playerLoop = PlayerLoop.GetDefaultPlayerLoop();获得所有标准事件。
重要的是playerLoop.subSystemList,存储在此列表中的方法是递归调用的。如果要自定义调用,则将编辑此subSystemList的各个部分。
此外,此部分中要获取的方法列表似乎与UnityEngine.Experimental.PlayLoop中可以检查的方法相匹配。
------Initialization------ Initialization.PlayerUpdateTime Initialization.AsyncUploadTimeSlicedUpdate Initialization.SynchronizeInputs Initialization.SynchronizeState Initialization.XREarlyUpdate ------EarlyUpdate------ EarlyUpdate.PollPlayerConnection EarlyUpdate.ProfilerStartFrame EarlyUpdate.GpuTimestamp EarlyUpdate.UnityConnectClientUpdate EarlyUpdate.CloudWebServicesUpdate EarlyUpdate.UnityWebRequestUpdate EarlyUpdate.ExecuteMainThreadJobs EarlyUpdate.ProcessMouseInWindow EarlyUpdate.ClearIntermediateRenderers EarlyUpdate.ClearLines EarlyUpdate.PresentBeforeUpdate EarlyUpdate.ResetFrameStatsAfterPresent EarlyUpdate.UpdateAllUnityWebStreams EarlyUpdate.UpdateAsyncReadbackManager EarlyUpdate.UpdateTextureStreamingManager EarlyUpdate.UpdatePreloading EarlyUpdate.RendererNotifyInvisible EarlyUpdate.PlayerCleanupCachedData EarlyUpdate.UpdateMainGameViewRect EarlyUpdate.UpdateCanvasRectTransform EarlyUpdate.UpdateInputManager EarlyUpdate.ProcessRemoteInput EarlyUpdate.XRUpdate EarlyUpdate.TangoUpdate EarlyUpdate.ScriptRunDelayedStartupFrame EarlyUpdate.UpdateKinect EarlyUpdate.DeliverIosPlatformEvents EarlyUpdate.DispatchEventQueueEvents EarlyUpdate.DirectorSampleTime EarlyUpdate.PhysicsResetInterpolatedTransformPosition EarlyUpdate.NewInputBeginFrame EarlyUpdate.SpriteAtlasManagerUpdate EarlyUpdate.PerformanceAnalyticsUpdate ------FixedUpdate------ FixedUpdate.ClearLines FixedUpdate.NewInputEndFixedUpdate FixedUpdate.DirectorFixedSampleTime FixedUpdate.AudioFixedUpdate FixedUpdate.ScriptRunBehaviourFixedUpdate FixedUpdate.DirectorFixedUpdate FixedUpdate.LegacyFixedAnimationUpdate FixedUpdate.XRFixedUpdate FixedUpdate.PhysicsFixedUpdate FixedUpdate.Physics2DFixedUpdate FixedUpdate.DirectorFixedUpdatePostPhysics FixedUpdate.ScriptRunDelayedFixedFrameRate FixedUpdate.ScriptRunDelayedTasks FixedUpdate.NewInputBeginFixedUpdate ------PreUpdate------ PreUpdate.PhysicsUpdate PreUpdate.Physics2DUpdate PreUpdate.CheckTexFieldInput PreUpdate.IMGUISendQueuedEvents PreUpdate.NewInputUpdate PreUpdate.SendMouseEvents PreUpdate.AIUpdate PreUpdate.WindUpdate PreUpdate.UpdateVideo ------Update------ Update.ScriptRunBehaviourUpdate Update.ScriptRunDelayedDynamicFrameRate Update.DirectorUpdate ------PreLateUpdate------ PreLateUpdate.AIUpdatePostScript PreLateUpdate.DirectorUpdateAnimationBegin PreLateUpdate.LegacyAnimationUpdate PreLateUpdate.DirectorUpdateAnimationEnd PreLateUpdate.DirectorDeferredEvaluate PreLateUpdate.UpdateNetworkManager PreLateUpdate.UpdateMasterServerInterface PreLateUpdate.UNetUpdate PreLateUpdate.EndGraphicsJobsLate PreLateUpdate.ParticleSystemBeginUpdateAll PreLateUpdate.ScriptRunBehaviourLateUpdate PreLateUpdate.ConstraintManagerUpdate ------PostLateUpdate------ PostLateUpdate.PlayerSendFrameStarted PostLateUpdate.DirectorLateUpdate PostLateUpdate.ScriptRunDelayedDynamicFrameRate PostLateUpdate.PhysicsSkinnedClothBeginUpdate PostLateUpdate.UpdateCanvasRectTransform PostLateUpdate.PlayerUpdateCanvases PostLateUpdate.UpdateAudio PostLateUpdate.ParticlesLegacyUpdateAllParticleSystems PostLateUpdate.ParticleSystemEndUpdateAll PostLateUpdate.UpdateCustomRenderTextures PostLateUpdate.UpdateAllRenderers PostLateUpdate.EnlightenRuntimeUpdate PostLateUpdate.UpdateAllSkinnedMeshes PostLateUpdate.ProcessWebSendMessages PostLateUpdate.SortingGroupsUpdate PostLateUpdate.UpdateVideoTextures PostLateUpdate.UpdateVideo PostLateUpdate.DirectorRenderImage PostLateUpdate.PlayerEmitCanvasGeometry PostLateUpdate.PhysicsSkinnedClothFinishUpdate PostLateUpdate.FinishFrameRendering PostLateUpdate.BatchModeUpdate PostLateUpdate.PlayerSendFrameComplete PostLateUpdate.UpdateCaptureScreenshot PostLateUpdate.PresentAfterDraw PostLateUpdate.ClearImmediateRenderers PostLateUpdate.PlayerSendFramePostPresent PostLateUpdate.UpdateResolution PostLateUpdate.InputEndFrame PostLateUpdate.TriggerEndOfFrameCallbacks PostLateUpdate.GUIClearEvents PostLateUpdate.ShaderHandleErrors PostLateUpdate.ResetInputAxis PostLateUpdate.ThreadedLoadingDebug PostLateUpdate.ProfilerSynchronizeStats PostLateUpdate.MemoryFrameMaintenance PostLateUpdate.ExecuteGameCenterCallbacks PostLateUpdate.ProfilerEndFrame
覆盖PlayerLoop本身
我将用我认为最强大的进程取代PlayerLoop 。
正确地说,一旦你没有调用Unity的基本功能的各种处理,请将处理插入其中。
这本身很容易实现。但是,如果您不调用进程== Unity循环被完全销毁,Unity使用的大多数函数都将停止。 物理操作,输入和UI 的所有操作都死掉了。
using UnityEngine; using UnityEngine.Experimental.LowLevel; public class SpawnSystem { [RuntimeInitializeOnLoadMethod()] static void Init() { var mySystem = new PlayerLoopSystem() { type = typeof(MyLoopSystemUpdate), updateDelegate = () => { Debug.Log("DO IT!!!"); } }; var playerLoop = new PlayerLoopSystem(); playerLoop.subSystemList = new PlayerLoopSystem[] { mySystem }; PlayerLoop.SetPlayerLoop(playerLoop); } public struct MyLoopSystemUpdate { } }
这次,我会尝试在更新之前执行类似...的 函数你可以看到每帧都在打印Log, 但是画面都是静止的, 因为之前的正常循环都被覆盖没有了。
using UnityEngine; using UnityEngine.Experimental.LowLevel; using System.Collections.Generic; public class PreUpdateSystem { [RuntimeInitializeOnLoadMethod()] static void Init() { var mySystem = new PlayerLoopSystem() { type = typeof(MyLoopSystemUpdate), updateDelegate = () => { Debug.Log("DO IT!!!"); } }; var playerLoop = PlayerLoop.GetDefaultPlayerLoop(); var updateSystem = playerLoop.subSystemList[4]; // Update var subSystem = new List<PlayerLoopSystem>(updateSystem.subSystemList); subSystem.Insert(0, mySystem); updateSystem.subSystemList = subSystem.ToArray(); playerLoop.subSystemList[4] = updateSystem; PlayerLoop.SetPlayerLoop(playerLoop); } public struct MyLoopSystemUpdate { } }
我正在做的就是重写subSystemList的内容并反映它。playerLoop.subSystemList[4];从更新过程中取出,在顶部添加您自己的进程并返回。现在整个显示如果有动画的话, 又动起来了~~~
下面的列表是Unity调用的事件获取的事件列表。
结果如下,我在FixedUpdate和Update之间插入了自己的事件。
禁用特定事件
最后,尝试禁用某些事件。这也很简单,只需准备一个已删除特定事件的PlayerLoop版本,然后执PlayerLoop.SetPlayerLoop。
这次,我将尝试禁用FixedUpdate.PhysicsFixedUpdate。
using UnityEngine; using UnityEngine.Experimental.LowLevel; using UnityEngine.Experimental.PlayerLoop; using System.Collections.Generic; public class StopPhysicsFixedUpdate { static PlayerLoopSystem[] originalPlayerLoop, updatedPlayerLoop; [RuntimeInitializeOnLoadMethod()] static void Init() { var playerLoop = PlayerLoop.GetDefaultPlayerLoop(); originalPlayerLoop = playerLoop.subSystemList[2].subSystemList; // Update var subSystem = new List<PlayerLoopSystem>(originalPlayerLoop); subSystem.RemoveAll(c => c.type == typeof(FixedUpdate.PhysicsFixedUpdate)); updatedPlayerLoop = subSystem.ToArray(); PhysicsOFF(); } public static void PhysicsOFF() { var playerLoop = PlayerLoop.GetDefaultPlayerLoop(); var sub = playerLoop.subSystemList[2]; sub.subSystemList = updatedPlayerLoop; playerLoop.subSystemList[2] = sub; PlayerLoop.SetPlayerLoop(playerLoop); } public static void PhysicsON() { var playerLoop = PlayerLoop.GetDefaultPlayerLoop(); var sub = playerLoop.subSystemList[2]; sub.subSystemList = originalPlayerLoop; playerLoop.subSystemList[2] = sub; PlayerLoop.SetPlayerLoop(playerLoop); } }
就个人而言,我认识到在Update之前添加初始化处理以及在帧结束时收集信息是一个很好的用法。