工作中遇到的需求 记录一下实现方法:
UI页面:
unity设置:
一共设置了三个脚本:
FPS和性能管理类:
using System;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.UI;
public class DebugUIManager : MonoBehaviour
{
[SerializeField] private Text fpsText;//fps
[SerializeField] private Text heapSizeText;//堆内存
[SerializeField] private Text usedSizeText;//使用大小
[SerializeField] private Text allocatedMemoryText;//Unity分配
[SerializeField] private Text reservedMemoryText;//总内存
[SerializeField] private Text unusedReservedMemoryText;//未使用内存
private int _index = 1;
private int _indexCount = 100;//更新间隔
private const long Kb = 1024;
private const long Mb = 1024 * 1024;
private float updateInterval = 1f;//更新间隔
private int frames;
private float fps;
private float lastInterval;
private float timeNow;
private void Start()
{
Init();
}
private void Init()
{
lastInterval = Time.realtimeSinceStartup;
frames = 0;
fps = 0.0f;
}
private void Update()
{
if (!gameObject.activeSelf) return;
_index++;
if (_index == _indexCount)
{
ShowProfilerMsg();
}
frames++;
timeNow = Time.realtimeSinceStartup;
if (timeNow > lastInterval + updateInterval)
{
ShowFPSMsg();
}
}
private void ShowProfilerMsg()
{
_index = 0;
//堆内存
if (heapSizeText)
{
heapSizeText.text = "堆内存 : " + Profiler.GetMonoHeapSizeLong() / Mb + " Mb";
}
//使用的
if (usedSizeText)
{
usedSizeText.text = "使用大小 : " + Profiler.GetMonoUsedSizeLong() / Mb + " Mb";
}
// unity分配
if (allocatedMemoryText)
{
allocatedMemoryText.text = "Unity分配 : " + Profiler.GetTotalAllocatedMemoryLong() / Mb + " Mb";
}
// 总内存
if (reservedMemoryText)
{
reservedMemoryText.text = "总内存 : " + Profiler.GetTotalReservedMemoryLong() / Mb + " Mb";
}
// 未使用内存
if (unusedReservedMemoryText)
{
unusedReservedMemoryText.text = "未使用内存 : " + Profiler.GetTotalUnusedReservedMemoryLong() / Mb + " Mb";
}
}
/// <summary>
/// 显示FPS信息
/// </summary>
private void ShowFPSMsg()
{
if (!fpsText) return;
fps = frames / (timeNow - lastInterval);
fpsText.text = fps.ToString("F2");
frames = 0;
lastInterval = timeNow;
}
/// <summary>
/// 页面开关
/// </summary>
public void ShowAndHide()
{
gameObject.SetActive(!gameObject.activeSelf);
}
}
CPU显示类:
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class CPUMessage : MonoBehaviour
{
[Header("Components")]
[SerializeField] private Text cpuCounterText;
[Header("Settings")]
[Tooltip("In which interval should the CPU usage be updated?")]
[SerializeField] private float updateInterval = 1;
[Tooltip("The amount of physical CPU cores")]
[SerializeField] private int processorCount;
[Header("Output")]
public float CpuUsage;
private Thread _cpuThread;
private float _lasCpuUsage;
private void Start()
{
Application.runInBackground = true;
cpuCounterText.text = "0% CPU";
// setup the thread
_cpuThread = new Thread(UpdateCPUUsage)
{
IsBackground = true,
// we don't want that our measurement thread
// steals performance
Priority = System.Threading.ThreadPriority.BelowNormal
};
// start the cpu usage thread
_cpuThread.Start();
}
private void OnValidate()
{
// We want only the physical cores but usually
// this returns the twice as many virtual core count
//
// if this returns a wrong value for you comment this method out
// and set the value manually
processorCount = SystemInfo.processorCount / 2;
}
private void OnDestroy()
{
// Just to be sure kill the thread if this object is destroyed
_cpuThread?.Abort();
}
private void Update()
{
// for more efficiency skip if nothing has changed
if (Mathf.Approximately(_lasCpuUsage, CpuUsage)) return;
// the first two values will always be "wrong"
// until _lastCpuTime is initialized correctly
// so simply ignore values that are out of the possible range
if (CpuUsage < 0 || CpuUsage > 100) return;
// I used a float instead of int for the % so use the ToString you like for displaying it
cpuCounterText.text = CpuUsage.ToString("F1") + "% CPU";
// Update the value of _lasCpuUsage
_lasCpuUsage = CpuUsage;
}
/// <summary>
/// Runs in Thread
/// </summary>
private void UpdateCPUUsage()
{
var lastCpuTime = new TimeSpan(0);
// This is ok since this is executed in a background thread
while (true)
{
var cpuTime = new TimeSpan(0);
// Get a list of all running processes in this PC
var AllProcesses = Process.GetProcesses();
// Sum up the total processor time of all running processes
cpuTime = AllProcesses.Aggregate(cpuTime, (current, process) => current + process.TotalProcessorTime);
// get the difference between the total sum of processor times
// and the last time we called this
var newCPUTime = cpuTime - lastCpuTime;
// update the value of _lastCpuTime
lastCpuTime = cpuTime;
// The value we look for is the difference, so the processor time all processes together used
// since the last time we called this divided by the time we waited
// Then since the performance was optionally spread equally over all physical CPUs
// we also divide by the physical CPU count
CpuUsage = 100f * (float)newCPUTime.TotalSeconds / updateInterval / processorCount;
// Wait for UpdateInterval
Thread.Sleep(Mathf.RoundToInt(updateInterval * 1000));
}
}
}
最后是Debug的窗口:
Debug窗口整体是一个ScrollView,设置如图
给Content挂上Vertical Layout Group和Content Size Fitter组件,这样Contene会根据内容自动扩容。加一个Scrollbar Vertical是为了后面方便让debug信息自动滚动到底部显示(见代码)。
LogText也挂上Content Size Fitter,让LogText也自动扩容和换行。
Debug管理类:
using UnityEngine;
using UnityEngine.UI;
using System.Text;
using DG.Tweening;
public class DebugMsge : MonoBehaviour
{
public Text logText;
public RectTransform content;
public Scrollbar bar;//竖向滚动条
private int count = 0;
StringBuilder MyStrBulder;
private bool isUpdate = false;
public void AddText(string str)
{
isUpdate = true;
MyStrBulder.AppendFormat("{0}:{1}\n", count, str);
count++;
isUpdate = false;
}
void Awake()
{
MyStrBulder = new StringBuilder();
//核心方法就是Application.logMessageReceived这个事件
Application.logMessageReceived += HandleLog;
}
void HandleLog(string message, string stackTrace, LogType type)
{
switch (type)
{
case LogType.Error:
message = "<color=#FF0000>" + message + "</color>";
break;
case LogType.Assert:
message = "<color=#0000ff>" + message + "</color>";
break;
case LogType.Warning:
message = "<color=#EEEE00>" + message + "</color>";
break;
case LogType.Log:
message = "<color=#000000>" + message + "</color>";
break;
case LogType.Exception:
break;
default:
break;
}
AddText(message);
onSkipToBottomShow();
}
// Update is called once per frame
void Update()
{
logText.text = MyStrBulder.ToString();
}
/// <summary>
/// 跳转至底部显示(使竖向滚动条的value保持为0即可)
/// </summary>
private void onSkipToBottomShow()
{
DOTween.To(() => bar.value = 0, v => bar.value = v, 0, 0.1f).SetEase(Ease.InElastic);
}
}
因篇幅问题不能全部显示,请点此查看更多更全内容