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之前添加初始化处理以及在帧结束时收集信息是一个很好的用法。

 

posted @ 2022-04-26 11:05  Jeanc  阅读(4836)  评论(0编辑  收藏  举报