我想知道是否有任何方法可以减少 Unity 在表面上不执行任何操作(例如坐在非动画菜单中)时使用的资源量。在现代游戏中,这是总是让我烦恼的事情,而且我知道这也会让其他人烦恼,闲置的游戏使用的资源几乎与实际运行时一样多。
在低级应用程序中,您可以暂停帧更新,直到 Windows 事件触发它们,但这在 Unity 中是不可能的,因为更新循环是在内部触发的。
您可以将目标帧速率设置得较低,但这会使菜单在您单击某些内容时没有响应,即使您在单击时立即将帧速率调高,而且无论如何也不会降低 CPU 使用率。
Unity 是一个实时游戏引擎。这意味着它旨在使用尽可能多的资源。所以一般来说,Unity 这样做是正常。
它是如何做到的?系统中运行的每个应用程序都在循环中运行。但经典的 UI 应用程序使用操作系统提供的库来获取用户输入。
在 Windows 上,这是底层的 WinAPI。如果您创建 UI 应用程序,您将使用
GetMessage
函数,例如:
while (GetMessage(...) != 0) {
...
}
GetMessage
阻止执行,直到收到消息
PeekMessage
函数来处理系统消息:
while (true) {
if(PeekMessage(&msg,0,0,0,PM_REMOVE) {
...
}
...
}
PeekMessage
不会阻止执行,从而允许循环尽可能频繁地执行。
以这种方式执行循环将导致 CPU 核心 100% 负载。这不是一个好的做法,因此通常使用
std::this_thread::yield();
(C++) 或系统提供的等效项 让其他应用程序在同一核心上执行。换句话说,即使任务管理器显示 100% 使用率,游戏也不会真正利用所有可用的 CPU 时间。
现在,Unity 中的所有内容(包括输入系统)都在该循环中运行,而不接触操作系统。这就是为什么当您降低游戏运行的 FPS 时无法获得正确的输入。
如何处理这个问题:
和Application.targetFrameRate。 您无法将 FPS 数字减少到 0 或 1,这是不可能的,您可以使用值 60、30 或 15。
还有一种通过代码手动限制帧速率的方法,用户无法关闭该方法,例如:
const int _fpsLimit = 60;
const double _desiredSecondsPerFrame = 1.0 / _fpsLimit;
void Update() {
var startOfFrameTicks = DateTime.Now.Ticks;
while (true) {
Thread.Yield(); // Let's the system to execute something else waiting for CPU time
// Then we return back and check whether we need to wait more or exit the loop
var currentTicks = DateTime.Now.Ticks;
var elapsedTime = TimeSpan.FromTicks(currentTicks - startOfFrameTicks).TotalSeconds;
if(elapsedTime >= _desiredSecondsPerFrame)
break;
}
}
通过使用
GetMessage