
유니티에서 게임의 프레임(FPS)을 60 으로 고정하려면 Application.targetFrameRate 에 60 을 넣습니다. PC 에서는 수직 동기화(vSyncCount)가 켜져 있으면 이 값이 무시되므로, 숫자를 60 이나 30 으로 정확히 묶고 싶을 때는 vSyncCount 를 0 으로 먼저 끕니다.
QualitySettings.vSyncCount = 0; // PC 에서는 이것부터
Application.targetFrameRate = 60; // 60 FPS 로
에디터에서는 부드럽던 게임이 휴대폰에 올리니 뚝뚝 끊겨 보이는 경우가 있습니다. Unity 문서에 따르면 안드로이드와 iOS 는 targetFrameRate 를 따로 정하지 않으면(-1) 배터리를 아끼려고 30 FPS 로 고정해서 그립니다. 그래서 움직임이 많은 게임은 앱이 시작할 때 60 으로 올려 두고, 반대로 배터리가 중요한 게임은 설정 화면에서 30 을 고를 수 있게 합니다. 이번 글에서는 설정의 「60 FPS」 토글로 60 과 30 을 바꾸고, 고른 값을 저장했다가 다음 실행 때 다시 적용하며, 지금 나오는 FPS 를 글자로 보여 주겠습니다. 특정 창이 떠 있는 동안만 잠깐 낮췄다가 되돌리는 방법도 함께 보겠습니다.
C# (UNITY 3D)
처음에는 60 FPS 라서 0.4초 동안 공을 그린 자리(점)가 촘촘합니다. 토글을 끄면 30 FPS 가 되어 같은 시간에 점이 절반으로 줄고, 다시 실행해도 저장된 30 으로 시작합니다. 공이 움직이는 거리는 같고, 그 사이를 몇 번 나눠 그리느냐가 달라집니다.
1. 준비 — 토글 하나와 글자 하나
Hierarchy 에서 UI (Canvas) > Toggle 로 「60 FPS」 토글을, UI (Canvas) > Text - TextMeshPro 로 FPS 를 보여 줄 글자를 만듭니다. targetFrameRate 는 앱 전체에 걸리는 값이라 첫 씬의 Awake 에서 한 번 적용하면 되므로, FrameRateSetting 은 첫 씬의 설정 창이나 빈 오브젝트에 붙이고, toggle_60fps 칸에 토글을, text_fps 칸에 글자를 끌어다 넣습니다.
using UnityEngine;
using UnityEngine.UI;
using TMPro;
Toggle 을 쓰기 위해 UnityEngine.UI 를, TMP_Text 를 쓰기 위해 TMPro 를 사용합니다.
2. 프레임 설정 코드
using UnityEngine;
using UnityEngine.UI;
using TMPro;
//CodeFinder 코드파인더
//From https://codefinder.janndk.com/
public class FrameRateSetting : MonoBehaviour
{
public Toggle toggle_60fps; // 켜면 60, 끄면 30 (배터리 절약)
public TMP_Text text_fps; // 실제로 나오는 FPS
const string KEY_FPS = "settings.fps";
float time_sum; // FPS 를 재는 동안 지난 시간
int frame_count; // 그동안 그린 프레임 수
void Awake()
{
QualitySettings.vSyncCount = 0; // PC 에서도 targetFrameRate 가 먹게
Apply_FrameRate(PlayerPrefs.GetInt(KEY_FPS, 60)); // 저장된 값(처음이면 60)
}
void Start()
{
if (toggle_60fps == null)
return;
toggle_60fps.SetIsOnWithoutNotify(Application.targetFrameRate == 60);
toggle_60fps.onValueChanged.RemoveAllListeners();
toggle_60fps.onValueChanged.AddListener(Change_FrameRate);
}
void Change_FrameRate(bool is_on)
{
int fps = is_on ? 60 : 30;
Apply_FrameRate(fps);
PlayerPrefs.SetInt(KEY_FPS, fps);
}
void Apply_FrameRate(int fps)
{
Application.targetFrameRate = fps;
}
void Update()
{
time_sum += Time.unscaledDeltaTime;
frame_count++;
if (time_sum < 0.5f) // 0.5초마다 한 번 표시
return;
if (text_fps != null)
text_fps.text = Mathf.RoundToInt(frame_count / time_sum) + " FPS";
time_sum = 0f;
frame_count = 0;
}
}
Awake 에서 저장된 값을 바로 적용하므로 첫 화면부터 그 프레임으로 그립니다. FPS 글자는 0.5초 동안 그린 프레임 수를 지난 시간으로 나눈 값이라 1프레임 시간만 보는 것보다 숫자가 덜 흔들립니다. targetFrameRate 는 목표일 뿐이라 기기가 버거우면 실제 FPS 는 그보다 낮게 나옵니다.
이 스크립트는 Unity 6000.6.3f1 에서 컴파일 오류 없이 들어갔고, 배치 모드에서 붙여 보니 처음 Awake 뒤 targetFrameRate 60 · vSyncCount 0, 토글을 끄면 30 과 저장값 30, 새로 만든 오브젝트는 Awake 에서 30 을 다시 적용했습니다. 실제 기기에서 FPS 를 재 본 것은 아닙니다.
변수(variable)
toggle_60fps(Toggle) : 켜면 60, 끄면 30
text_fps(TMP_Text) : 지금 FPS 를 보여 줄 글자
KEY_FPS(string) : PlayerPrefs 에 저장할 이름
time_sum(float) : FPS 를 재는 동안 지난 시간
frame_count(int) : 그동안 그린 프레임 수
함수(function)
Awake : vSync 를 끄고 저장된 프레임을 적용합니다.
Change_FrameRate : 토글이 바뀌면 60 이나 30 을 적용하고 저장합니다.
Apply_FrameRate : targetFrameRate 에 값을 넣습니다.
Update : 0.5초마다 실제 FPS 를 계산해 보여 줍니다.
3. 창이 떠 있는 동안만 낮추기
using UnityEngine;
//CodeFinder 코드파인더
//From https://codefinder.janndk.com/
public class LowPowerPanel : MonoBehaviour
{
public int fps_low = 30; // 이 창이 떠 있는 동안의 프레임
void OnEnable()
{
Application.targetFrameRate = fps_low;
}
void OnDisable()
{
Application.targetFrameRate = PlayerPrefs.GetInt("settings.fps", 60); // 설정에서 고른 값으로
}
}
오래 켜 두는 대기 화면이나 일시정지 메뉴처럼 움직임이 거의 없는 창에 붙이면, 창이 켜질 때 30 으로 낮추고, 꺼질 때는 2절 FrameRateSetting 이 저장한 settings.fps(없으면 60)로 돌려놓습니다. 열기 전 값을 기억해 두었다가 되돌리면, 일시정지 메뉴 안에서 60 FPS 토글을 바꿨을 때 창을 닫는 순간 옛 값으로 덮이므로 저장값을 읽게 했습니다. 직접 불러 보니 저장값이 없을 때 열면 30, 닫으면 60 이었고, 창이 떠 있는 동안 토글을 30 으로 바꾸면 닫은 뒤에도 30 이었습니다.
4. 60 이 안 나올 때 — 자주 하는 실수

PC 에서 targetFrameRate 가 안 먹는다
vSyncCount 가 0 이 아니면 targetFrameRate 는 무시됩니다. 직접 넣어 보니 vSyncCount 가 2 일 때 targetFrameRate 를 읽으면 넣은 144 가 그대로 나오지만, 문서 기준으로 이 값은 적용되지 않습니다. 값만 보고 적용됐다고 생각하기 쉬우니 숫자를 정확히 묶으려면 2절처럼 vSyncCount 를 0 으로 끕니다. 다만 Unity 문서는 PC 에서는 targetFrameRate 보다 vSyncCount 를 권합니다. targetFrameRate 는 소프트웨어로 시간을 맞추는 방식이라 미세하게 끊길 수 있기 때문입니다. PC 빌드에서 부드러움이 더 중요하다면 PC 에서는 2절의 vSyncCount = 0 줄을 빼고 vSync 를 켜 둡니다. vSyncCount 는 0~4 만 받아서 7 을 넣으면 4 가 되었습니다. 휴대폰은 반대로 vSyncCount 를 늘 무시하고 targetFrameRate 로만 정합니다.
0 을 넣었다
문서상 targetFrameRate 에 쓸 수 있는 값은 1 이상이나 -1 입니다. 0 이나 -5 를 넣어도 오류 없이 그 값이 그대로 읽혀서 실수를 알아채기 어렵습니다. PC 에서 제한 없이 그리려면 -1 을 넣습니다. 휴대폰은 -1 이면 30 고정이라는 점은 첫머리와 같습니다.
에디터에서 확인하기
에디터에서는 targetFrameRate 가 Game 뷰에만 적용됩니다. Scene 뷰 등 다른 창은 따르지 않으니 FPS 는 Game 뷰나 실제 기기에서 봅니다.
double hz = Screen.currentResolution.refreshRateRatio.value;
Debug.Log("화면 " + hz.ToString("0") + "Hz · 목표 " + Application.targetFrameRate);
설정 화면에 기기 화면의 주사율(Hz)을 함께 보여 주고 싶다면 Screen.currentResolution.refreshRateRatio 를 읽습니다. 60Hz 모니터에서는 60 이 나옵니다.
함께 보기: 프레임이 바뀌어도 같은 속도로 시간을 재는 방법은 유니티 타이머 카운트다운 · 스톱워치 · 일시정지 에 있습니다.
targetFrameRate 와 vSyncCount 동작은 Unity 공식 문서 Application.targetFrameRate · QualitySettings.vSyncCount 와 Unity 6000.6.3f1 에디터(Windows)에서 직접 넣어 본 값을 기준으로 적었습니다.
2절처럼 앱이 켜질 때 60 으로 올리는 줄은 제가 잰드케이로 낸 전광판 앱 BeamSay 에서 흐르는 글자가 끊겨 보이지 않게 실제로 쓰고 있습니다(스토어 개발사 표시는 Jakadela Games).