目前常規的PC游戲顯示模式有幾種模式如下,
一、視窗模式(FullScreenMode.Windowed)
二、獨占模式(FullScreenMode.ExclusiveFullScreen)
FPS游戲多數使用獨占模式,也是最早的全屏幕模式,性能較好,但使用
Alt+Tab時切換會出現閃頻
三、無邊框模式 (FullScreenMode.FullScreenWindow)
目前游戲多數使用這個模式,開啓後切換不會出現閃屏
問題1、切換解析度時屏幕出現黑屏無訊號
Exclusive Fullscreen 必須使用顯示卡的「原生支援模式」(Display Modes),Windows 桌面「縮放 / 插值後」能顯示許多非原生模式,但 Unity 的 Exclusive Fullscreen 只能切換到顯示卡真正支援的模式,不能靠 OS 自動補正。
所以:
你以為進入了 1280×800,但實際上顯卡沒有成功切換到這個 mode。
問題2、兩個屏幕,一個 1080p,一個2k,切換2k解析度時出現錯誤,游戲無法調整到對應的2k解析度
目前沒有處理這個問題。
問題3、無邊框模式切換獨占模式無效
在主要解析度,譬如設備解析度為 1920 X 1080,情況下從無邊框模式切換到獨占模式,雖然切換成功,但實際上卻是無邊框模式,這是 windows 全螢幕最佳化處理的結果,unity無法干涉。
原因是 Windows 10/11 強制 Fullscreen Optimizations(全螢幕最佳化),導致獨占模式被轉成 Borderless Fullscreen
Windows 會把要求 Exclusive Fullscreen 的遊戲「包裝成」
➡ Borderless Fullscreen + 可變刷新率 + 全螢幕優化圖層
這樣能快速切換視窗、疊加 UI(Xbox Bar)、降低 alt-tab 黑屏,但缺點就是:
看起來像無邊框, 還是會回報給 Unity 「正在使用 Exclusive Fullscreen」, 顯示卡 API 也會回報獨佔模式成功,所以 Unity 的 log 會印出 ExclusiveFullScreen,但你看到的是 Borderless 外觀。
需要處理【關閉全螢幕最佳化】
有兩種做法:
方法一、設定 exe 檔案,關閉全螢幕最佳化。
方法二、游戲啓動后新增注冊表關閉最佳化,如下: public static void SetDisableFullscreenOptimization()
{
string exePath = string.Empty;
// 獲取當前執行檔路徑 (包含執行檔名稱)
// 獲取執行檔所在目錄的路徑
// 獲取可讀寫的持久化資料夾路徑
try
{
string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
string exeName = Application.productName + ".exe";
exePath = Path.Combine(baseDirectory, exeName);
}
catch (System.Exception e)
{
Debug.LogError($"使用 BaseDirectory 獲取執行檔路徑時發生錯誤: {e.Message}");
return;
}
if (string.IsNullOrEmpty(exePath))
{
Debug.LogError("無法推導執行檔路徑,操作取消。");
return;
}
// 檢查檔案是否存在(額外的安全檢查)
if (!File.Exists(exePath))
{
Debug.LogError($"推導的路徑找不到執行檔。路徑: {exePath}");
return;
}
// Windows 註冊表路徑
string registryPath = @"Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers";
try
{
using (
RegistryKey key = Registry.
CurrentUser.
CreateSubKey(
registryPath))
{
if (key != null)
{
object existingValue = key.GetValue(exePath);
// 我們要寫入的值是 "~ DISABLEDXMAXIMIZEDWINDOWEDMODE"
const string compatibilityFlag = "~ DISABLEDXMAXIMIZEDWINDOWEDMODE";
if (existingValue == null || !existingValue.ToString().Contains("DISABLEDXMAXIMIZEDWINDOWEDMODE"))
{
Debug.Log("已成功設定相容性:停用全螢幕最佳化。路徑: " + exePath);
}
else
{
Debug.Log("相容性設定已存在,無需重複設定。");
}
}
else
{
Debug.LogError("無法開啟或建立註冊表路徑:" + registryPath);
}
}
}
catch (System.Security.SecurityException e)
{
Debug.LogError($"設定註冊表失敗,可能是權限不足或其他系統錯誤: {e.Message}");
}
catch (System.Exception e)
{
Debug.LogError($"設定註冊表時發生未知錯誤: {e.Message}");
}
}
問題4、獨占模式切換無邊框模式時,解析度無效問題
這個情況比較特殊,操作的流程如下:
先設定游戲變成全屏幕 800x600,再設定 無邊框模式 1920x1080,爲什麽顯示出來的解析度竟然是 800x600 無邊框模式
Exclusive Fullscreen 模式會改變桌面解析度,而 Windows(FSO)不會在你切到無邊框時自動切回。最後的做法是將 exe 的全螢幕最佳化關閉。
另外再補上一個流程就是切換解析度時執行兩次,如下:
Screen.SetResolution(width, height, fullScreenMode);
await UniTask.DelayFrame(1);
Screen.SetResolution(width, height, fullScreenMode);
問題5、獨占模式滑鼠可以超出游戲範圍
下面給了解決辦法,測試了其他方法無效,最後的做法是在切換到獨占模式時設定限制 Cursor 可移動範圍,詳細做法如下:
void OnApplicationFocus(bool focus)
{
Cursor.visible = !focus;
#if UNITY_STANDALONE_WIN && !UNITY_EDITOR
PlatformUtils.ClipCursorToScreen(Screen.fullScreenMode == FullScreenMode.ExclusiveFullScreen);
#endif
}
public static async UniTask<bool> SetupResolution(int solutionIdx, int fullMode)
{
//...
await SetResolutionAsync(width, height, displayModeValue);
PlatformUtils.ClipCursorToScreen(displayModeValue == FullScreenMode.ExclusiveFullScreen);
}
private static async UniTask SetResolutionAsync(int width, int height, FullScreenMode fullScreenMode)
{
Screen.SetResolution(width, height, fullScreenMode);
await UniTask.DelayFrame(1);
Screen.SetResolution(width, height, fullScreenMode);
//加入超時處理,避免無限等待
//這裡設定1秒超時
int timeoutFrames = 60; // Assuming 60 frames per second
int waitedFrames = 0;
while (Screen.width != width || Screen.height != height)
{
await UniTask.Yield(); // 等下一幀
waitedFrames++;
if (waitedFrames > timeoutFrames)
{
Log.Warning("設定解析度超時");
break;
}
}
}
public static void ClipCursorToScreen(bool clip)
{
if (clip)
{
{
Left = 0,
Top = 0,
Right = Screen.width,
Bottom = Screen.height
};
}
else
{
ClipCursor(System.IntPtr.Zero);
}
}
問題6、游戲在熒幕2游玩,設定全螢幕后因爲要鎖定滑鼠在游戲範圍内,結果滑鼠被鎖定在熒幕1
需要根據目前在那個熒幕獲取對應 Rect 做設定,不然就會出錯,修改 code 如下:
public static RECT GetCurrentMonitorRect()
{
IntPtr hwnd = GetActiveWindow();
if (hwnd == IntPtr.Zero)
throw new Exception("Cannot get Unity HWND");
IntPtr hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
if(hMonitor == IntPtr.Zero)
throw new Exception("MonitorFromWindow failed");
MONITORINFO mi = new MONITORINFO();
mi.cbSize = Marshal.SizeOf(typeof(MONITORINFO));
if (!GetMonitorInfo(hMonitor, ref mi))
throw new Exception("GetMonitorInfo failed");
return mi.rcMonitor;
}
public static void ClipCursorToCurrentMonitor(bool enable)
{
if (!enable)
{
ClipCursor(IntPtr.Zero);
return;
}
RECT rect = GetCurrentMonitorRect();
ClipCursor(ref rect);
}
問題7、游戲啓動的解析度會莫名其妙被設定成其他的解析度
我的游戲,解析度保留在視窗化,切換到無邊框,直接 alt+F4 關閉游戲(沒有保存設定,應該啓動回事視窗話),啓動后會先是無邊框(啓動讀取設定根據設定顯示對應解析度),又切換成視窗化
但如果切換無邊框并保存設定都不會有問題,唯獨游戲中切換無邊框立即關閉游戲,啓動會是無邊框,爲什麽?
Unity 在切換全螢幕模式(含無邊框)時,會立即刷新一組“硬體層級解析度記錄”
這個狀態會被同步到:
要修改這個問題,就是在套用解析度時就應該寫入設定檔,這也是爲什麽歐美FPS游戲的保存機制中,圖形的保存是修改當下就保存,而游戲功能選項卻是退回去才會提示保存。
問題8、在筆記本接外顯示器時切換全螢幕(獨占模式)直接卡死畫面但游戲流程還在執行
問題9、在4k顯示熒幕上出現周期性卡頓
可能原因分析
1. 刷新率不匹配問題(最可能)
你的4K螢幕支援多種刷新率,但在無邊框模式下可能沒有正確選擇:
- 獨占模式:遊戲可以強制使用 60Hz,與你的目標FPS完美匹配
- 無邊框模式:可能被強制使用 120Hz/180Hz/240Hz,但遊戲只能輸出60FPS
- 結果:螢幕每秒刷新120次,但遊戲只更新60幀 → 卡頓感
- 或者VSync與高刷新率衝突 → 幀時間不穩定
2. 桌面合成器(Desktop Window Manager)開銷
- 無邊框模式下,Windows DWM會介入進行視窗合成
- 4K解析度的合成開銷很大,尤其是高刷新率時
3. VSync行為差異
- 獨占模式:VSync直接控制顯示器
- 無邊框模式:VSync通過DWM,可能有額外延遲或幀時間波動
問題10、4k 桌面解析度切换到無邊框或是視窗模式,開啓 vsync 后選擇 60hz 卡頓情況比不開 vsync 嚴重,不開vsync,fps會跑到130-140。
Windows DWM(Desktop Window Manager) 合成 + 嚴格 16.67ms 幀同步,一旦錯過就掉到 33ms(30fps)或產生節奏性卡頓
1)關閉vsync
2)fps不要卡 60
QualitySettings.vSyncCount = 0;
Application.targetFrameRate = 58;
留言
張貼留言