관리 메뉴

개발블로그

[유니티 C#] Time.deltaTime, Application.targetFrameRate을 통한 프레임 제어 본문

Unity/스크립팅

[유니티 C#] Time.deltaTime, Application.targetFrameRate을 통한 프레임 제어

dvmoo 2021. 8. 4. 22:36

💪GOAL

 1) Time.deltaTime의 정의와 응용 예제

 2) Application.targetFrameRate을 통한 프레임 제어

 


 

Time 클래스는 유니티로 부터 시간 정보를 받을 때 사용하는 인터페이스를 나타낸다.

프로젝트에서 시간 관련 값으로 작업할 수 있는 중요한 기본 속성을 제공한다.

 

Time 클래스에서 가장 일반적으로 많이 사용하는 프로퍼티 중 Time.deltaTime 이 있다.

 

🔶Time.deltaTime

 마지막 프레임이 완료된 후 경과된 시간을 반환한다.

 

 

게임 내에서 방향키를 눌러서 캐릭터를 이동해야 하는 경우가 있다.

예제 코드를 보자.

using UnityEngine;

public class StudyTime : MonoBehaviour
{
    [SerializeField] float _speed = 0f;
    Vector2 _vec = Vector2.zero;

    void Start()
    {
        _vec = transform.position;
    }

    void Update()
    {
        _vec.x += _speed * Input.GetAxisRaw("Horizontal");

        transform.position = _vec;
    }
}

 

키보드의 방향키 왼쪽/오른쪽을 누르면 해당 방향으로 _speed 만큼 프레임마다 이동하도록 코드를 작성했다.

 

그림 2

 

씬에 스프라이트2D 프리미티브 오브젝트를 생성 후 Sprite는 Circle, Color는 주황색으로, 

그리고 StudyTime 스크립트를 넣은 후 Speed는 0.1로 설정해주었다.

 

GIF 1

Update함수는 컴퓨터마다 프레임률이 일정하지 않고, Update함수 호출 사이의 시간도 일정하지 않다.

프레임 시간이 일정하지 않으면 움직일 오브젝트는 불규칙한 속도로 이동하게 된다.

 

GIF 1도 0.1f만큼 움직이게 했음에도 불구하고 프레임마다 움직이므로

불규칙적인 속도로 프레임마다 호출되기 때문에 상당히 빠르게 움직인다.

 

 

✔ 이제 프레임당 거리 이동이 아닌 초당 거리 이동을 할 수 있도록 코드를 수정해보자.

using UnityEngine;

public class StudyTime : MonoBehaviour
{
    [SerializeField] float _speed = 0f;
    Vector2 _vec = Vector2.zero;

    void Start()
    {
        _vec = transform.position;
    }

    void Update()
    {
    	// Time.deltaTime 
        _vec.x += _speed * Input.GetAxisRaw("Horizontal") * Time.deltaTime;

        transform.position = _vec;
    }
}

 

아까 코드에서 크게 달라진 것은 없다. 

이동 속도 * 이동 방향에 * Time.deltaTime 을 곱해주었다.

 

GIF 2

 

Time.deltaTime은 이전 프레임이 완료되기 까지 걸린 시간을 반환한다.

즉, 유니티에서 이전 프레임 시작 시간부터 현재 시작 시간까지의 차이(이전 프레임의 동작 시간) 이 Time.deltaTime 이다.

 

Time.deltaTime을 곱하게 되면 오브젝트를 매 프레임당 0.1유닛 움직이는게 아닌 초당 0.1유닛씩 움직이게 된다. GIF 2

 


🔶 게임의 프레임과 FPS(Frame Per Second)

게임 프레임은 게임이 화면에 그려주는 각각의 그림 한 장을 의미한다.

FPS 란 1초에 몇 장의 프레임을 보여줄 수 있는지 나타낸다.

FPS가 높을 수록 영상은 자연스러운 느낌을 주지만 그만큼 연산 부하가 많이 생긴다. 

 

유니티에서는 Application.targetFrameRate 를 활용해서 게임의 FPS를 조절할 수 있다.

 

 

🔶 Application.targetFrameRate

게임이 명시된 프레임 속도로 렌더링 하게 된다.

tagetFrameRate 는 기본값이 -1로, 게임이 플랫폼에 따라 달라지는 기본 프레임 속도로 렌더링 된다.

PC 플랫폼에서 기본 프레임 속도는 현재 퍼포먼스에서 달성 가능한 최대 프레임 속도이다.

 

일반적으로 모바일 플랫폼에서 기본 프레임 속도는 배터리 전원을 절약하기 위한 이유로 달성 가능한 최대 프레임 속도보다 낮다.

일반적으로 모바일 플랫폼에서 기본 프레임 속도는 30FPS 이다.

 

 

현재 코드의 프레임을 화면에 출력하는 코드를 작성했다.

using UnityEngine;
using UnityEngine.UI;

public class StudyTime : MonoBehaviour
{
    [SerializeField] Text _textFPS = null;
    float deltaTime = 0f;

    void Update()
    {
        FPSUpdate();
    }

    void FPSUpdate()
    {
        deltaTime += (Time.unscaledDeltaTime - deltaTime) * 0.1f;
        float fps = 1f / deltaTime;
        _textFPS.text = "FPS : " + fps.ToString("N1");
    }
}

FPSUpdate() 함수에서 현재 코드의 Frame을 계산하는 코드를 작성 후 Update문에서 호출했다.

그 외의 코드는 위와 동일하므로 생략했다.

 

GIF 3

현재 FPS 가 화면에 출력되는 것을 확인할 수 있다.

 

✔ targetFrameRate를 제어하고 오브젝트의 이동이 어떻게 변화하는지 확인해보자.

using UnityEngine;
using UnityEngine.UI;

public class StudyTime : MonoBehaviour
{
    [SerializeField] Text _textFPS = null;
    float deltaTime = 0f;

    [SerializeField] int _targetFrameRate = 0;

    [SerializeField] float _speed = 0f;

    Vector2 _vec = Vector2.zero;

    void Start()
    {
        Application.targetFrameRate = _targetFrameRate;

        _vec = transform.position;
    }

    void Update()
    {
        FPSUpdate();

        _vec.x += _speed * Input.GetAxisRaw("Horizontal") * Time.deltaTime;
        transform.position = _vec;
    }

    void FPSUpdate()
    {
        deltaTime += (Time.unscaledDeltaTime - deltaTime) * 0.1f;
        float fps = 1f / deltaTime;
        _textFPS.text = "FPS : " + fps.ToString("N1");
    }
}

 

GIF 4 60FPS

위의 코드에서 Speed 값을 인스펙터에서 5로 변경 하고, _targetFrameRate 의 값을 60으로 제한 후 실행한 모습이다.

프레임을 60으로 제한했기 때문에 최대 프레임이 60을 넘지 않는다. 

 

 

✔ 만약 프레임을 낮게 설정하면 어떻게 될까 ?

GIF 5 15FPS 

인스펙터에서 _targetFrameRate 의 값을 15로 낮춘 후 실행해보면 2D 오브젝트가 뚝뚝 끊기듯이 실행되는 것을 확인할 수 있다.

 

이로써 Application.targetFrameRate로 최대 프레임을 제한할 수 있는 것을 확인 했다.

 

 

✔ targetFrame을 30으로 설정하고, Time.deltaTime 대신 0.033f 를 곱해보자

_vec.x += _speed * Input.GetAxisRaw("Horizontal") * 0.033f;

Update() 에서 Time.deltaTime 대신 1/30 (0.033..)을 곱해보았다.

이동거리에 고정값으로 1/30 을 곱해주면 이동거리가 비슷하게 나올 것이다.

 

GIF 6 Time.deltaTime대신 0.033f 를 곱해줌

 

고정값이지만 이동거리가 비슷하게 나온다.

 

 

이번엔 Time.deltaTime을 곱해준다.

_vec.x += _speed * Input.GetAxisRaw("Horizontal") * Time.deltaTime;

 

GIF 7 Time.deltaTime 을 곱해줌

 

0.033f 를 곱해준 것과 Time.deltaTime을 곱해준 것을 확인해보면 큰 차이가 나지 않는다.

 

targetFrameRate를 30으로 고정해주었기 때문에 이러한 결과가 나타난다.

 


그리고 Time.deltaTime은 일정시간을 지연 시킨 후 동작을 수행하게 할 때도 사용한다.

 

스크립트가 실행되면 로그를 찍고, 3초 뒤에 로그를 찍는 예제 코드를 작성했다.

using UnityEngine;

public class StudyTime : MonoBehaviour
{
    float _deltaTime = 3f;
    bool  _isGoal    = false;

    void Start()
    {
        _isGoal = true;

        StartLog();
    }

    void Update()
    {
        if(_isGoal)
        {
            if(_deltaTime > 0f)
            {
                _deltaTime -= Time.deltaTime;
            }
            else if(_deltaTime <= 0f)
            {
                EndLog();
                _isGoal = false;
            }
        }
    }

    void StartLog()
    {
        Debug.Log("Start Log");
    }

    void EndLog()
    {
        Debug.Log("End Log");
    }
}

 

스크립트가 실행되면 Start()함수에서 StartLog() 함수를 실행시키고, bool 변수 _isGoal을 true로 변경해준다.

유니티의 라이프 사이클에 따라 Update() 문이 실행되면 _isGoal 의 상태를 검사한다.

 

_isGoal 이 true상태이므로 _deltaTime 이 0보다 큰지 작은지 조건을 검사한다.

만약 _deltaTime이 0보다 크다면 _deltaTime 을 매 프레임마다 Time.deltaTime을 빼준다.

 

매 프레임마다 시간을 빼다보면 _deltaTime이 0보다 작아지게 된다.

0보다 작아지면 EndLog() 함수를 실행시키고 _isGoal을 false로 바꿔주며 조건문을 빠져나온다.

 

그림 3

스크립트가 실행됐을 때 Start Log 가 출력 되고, 3초(_deltaTime) 뒤에 End Log가 출력됐다. 그림 3

 

 

매 프레임마다 호출되는 Update에서 이전 프레임 이후의 시간을 알려주는 Time.deltaTime을 이용하면

이를 누적해서 시간을 체크 하고 종료시점을 확인해서 동작을 수행할 수 있다.

 

 


 

 


 

* 공부하는 단계입니다. 잘못된 정보가 있다면 피드백 부탁드립니다 😊

* e-mail : heehee970@naver.com

 

 

Ref.

https://docs.unity3d.com/Manual/TimeFrameManagement.html

https://docs.unity3d.com/ScriptReference/Time.html

https://docs.unity3d.com/kr/530/ScriptReference/Application-targetFrameRate.html