일단 해당 매니저도 프로그램내에서 단 하나만의 객체를 가지고 작동해야하므로, 이전과 동일하게 싱글톤을 이용하여
구현해주도록 하자.
구현을 하기전에 어떻게 시간을 측정할 것인지 생각해보자.
다행스럽게도 Win32 api에서는 현재 시간을 측정하는 함수와, 초당 몇번 카운트가 발생하는지를 알려주는 함수가 존재한다.
QueryPerformanceCounter()
시간 측정용 함수로 64비트 정수로 시간을 저장한다. 반환 값은 LARGE_INTEGER
QueryPerformanceFrequency()
QueryPerformanceCounter의 주파수를 반환해준다. 이 또한 LARGE_INTEGER로 값을 반환해준다.
이를 이용하여 현재 불러오는 카운터 값을 m_llCurCount, 이전 루프에서 불러오는 카운터 값을 m_llPrevCount
그리고 매초 불러오는 초당 카운트 횟수를 m_llFrequency로 명명하자.
Win32 api에서 프레임 값의 시간 간격인 델타 타임을 구현하기 위한 모든 것을 알려주었다.
우리는 현재 값인 m_llCurCount에서 m_llPrevCount를 뺀 뒤, 이것을 주파수인 m_llFrequency로 나눠주게 되면
시간 간격을 알 수 있게 된다.
델타 타임을 m_dDT로 선언하고 이를 코드상에서 구현해보자.
사용하는 멤버 변수와 함수를 선언해주자.
프로그램이 실행되고 Core가 각 매니저들을 초기화하는 과정에서 init()을 호출하게 되고 자연스럽게 초기 값이 세팅이 될 것이다.
init() 구현
Core::init()
초기 값을 세팅해주었으니 이제 매 루프마다 호출되는 CTimeMgr::update()를 구현해보자.
위와 같은 코드를 이용하여 델타 타임인 m_dDT를 구할 수 있게 된다.
~.QuadPart는 무엇인가요?
QueryPerformanceCount의 반환 값인 구조체 LARGE_INTEGER는 다음과 같이 정의되어 있다. 여기서 "LowPart" 는 32비트 정수로, 값의 낮은 32비트를 저장한다. "HighPart" 는 32비트 정수로, 값의 높은 32비트를 저장한다. "QuadPart" 는 64비트 정수로, 값의 전체 64비트를 저장한다.
따라서 우리는 타이머의 전체 값을 필요로 하기 때문에 QuadPart를 불러와 사용하면 된다.
이제 매 호출시마다 m_dDT를 계산하고, 실시간으로 반영하고 있으므로 이를 사용하기 위해 반환함수 GetDT를 구현한 뒤
직접 사용해보자.
두가지 타입의 GetDT()를 구현해주었다.
값을 얻어올 수 있는 함수를 구현했으므로 이제 화면에 사각형을 그리는 CCore::render()로 돌아오자.
이전의 render()는 다음과 같이 구현되어 있어 초당 어느 정도로 사각형이 움직이는지 파악하기 어려웠다.
이전의 CCore::render()
이제는 델타 타임을 이용하여 초당 100.f의 속도로 이동하도록 구현할 수 있게 되었다.
이전의 이동속도와 현재의 이동속도를 비교해보도록 하자.
델타 타임을 적용하기 전
델타 타임을 적용한 후. 초당 100.f의 이동속도를 가지게 되었다.
지금까지 엔진에서 가장 기본인 "Singleton", "Manager", "Double Buffering", "Delta Time"에 대해서 알아보았다.
이후에는 유용한 빌드 방식인 "unity build"나 싱글톤 이외의 여러 디자인 패턴에 대해 알아보도록 하자.