Unity通过PlayerLoopSystem接口实现不通过Monobehavior让函数在FixedUpdate阶段被调用
本文参考了 https://www.cnblogs.com/Jean90/p/16193938.html
简介
PlayerLoop是Unity提供用于修改游戏循环中系统组成的接口。我们可以分别通过PlayerLoop.GetCurrentPlayerLoop
和PlayerLoop.SetPlayerLoop
获取和设置游戏循环。
using System.Collections;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.Drawing;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Linq;
using System;
using WildBoar.Base;
using UnityEngine.LowLevel;
using UnityEngine.PlayerLoop;
using NPOI.SS.Formula.Functions;
using System.Runtime.Remoting.Messaging;
public class PlayerLoopExample : EditorWindow
{
[MenuItem("Tools/Example/PlayerLoopWindow")]
private static void CreateWindow()
{
GetWindow<PlayerLoopExample>();
}
private void OnGUI()
{
if(GUILayout.Button("LogPlayerLoopInfo"))
{
LogPlayerLoopInfo();
}
if(GUILayout.Button("LogFixedUpdateSystem"))
{
GetAndLogFixedUpdateSystem();
}
if(GUILayout.Button("RemoveBehaviorFixedUpdate"))
{
RemoveBehaviorFixedUpdate();
}
if(GUILayout.Button("AddUserFixedUpdate"))
{
AddUserFixedUpdate();
}
}
public void LogPlayerLoopInfo()
{
var playerLoop = PlayerLoop.GetDefaultPlayerLoop();
int index = 0;
foreach (var header in playerLoop.subSystemList)
{
Debug.LogFormat($"-----{index}-{header.type.Name}------");
foreach (var subSystem in header.subSystemList)
{
Debug.LogFormat("{0}.{1}", header.type.Name, subSystem.type.Name);
}
index++;
}
}
private void GetAndLogFixedUpdateSystem()
{
var playerLoopMainSystem = PlayerLoop.GetDefaultPlayerLoop();
if(playerLoopMainSystem.TryGetSubSystem<FixedUpdate>( out var fixedUpdateSystem))
{
foreach (var subSystem in fixedUpdateSystem.subSystemList)
{
Debug.LogFormat($"{subSystem.type.Name}");
}
}
}
private void RemoveBehaviorFixedUpdate()
{
var main = PlayerLoop.GetDefaultPlayerLoop();
if(main.TryGetSubSystem<FixedUpdate>(out var fixedUpdateSystem))
{
var list = new List<PlayerLoopSystem>(fixedUpdateSystem.subSystemList);
list.RemoveAll(system => system.type == typeof(FixedUpdate.ScriptRunBehaviourFixedUpdate));
fixedUpdateSystem.subSystemList = list.ToArray();
main.ReplaceSubSystem(fixedUpdateSystem);
PlayerLoop.SetPlayerLoop(main);
}
}
private void AddUserFixedUpdate()
{
var main = PlayerLoop.GetDefaultPlayerLoop();
if (main.TryGetSubSystem<FixedUpdate>(out var fixedUpdateSystem))
{
var list = new List<PlayerLoopSystem>(fixedUpdateSystem.subSystemList);
var mySystem = new PlayerLoopSystem()
{
type = typeof(MyUserLogFixedUpdate),
updateDelegate = () =>
{
Debug.Log("User FixedUpdate Log");
}
};
list.Add(mySystem);
fixedUpdateSystem.subSystemList = list.ToArray();
main.ReplaceSubSystem(fixedUpdateSystem);
PlayerLoop.SetPlayerLoop(main);
}
}
struct MyUserLogFixedUpdate
{
}
}
public static class PlayerLoopSystemExtend
{
public static bool TryGetSubSystem<T>(this PlayerLoopSystem main, out PlayerLoopSystem subSystem)
where T: struct
{
foreach (var subsystem in main.subSystemList)
{
if (subsystem.type == typeof(T))
{
subSystem = subsystem;
return true;
}
}
subSystem = default;
return false;
}
public static void ReplaceSubSystem(this PlayerLoopSystem main, PlayerLoopSystem subSystem)
{
for(int i = 0; i < main.subSystemList.Count(); i++)
{
var sub = main.subSystemList[i];
if(sub.type == subSystem.type)
{
main.subSystemList[i] = subSystem;
}
}
}
}