728x90
저번에 일반적인 WindowAPI를 사용하여 사각형을 그려봤지만 이 방식은 매번 윈도우의 메세징 시스템을 이용하여 그려야 되며 InvalidateRect를 계속 호출해야 하는 상황이 발생하였다.
게임에서는 이러한 메세징 시스템을 이용하지 않고 비동기 방식의 키 입력을 사용하여 주로 이를 처리한다고 한다
1. 비동기 방식으로의 전환
이것을 구현하지 위해서는 SendMessage의 경우는 메세지가 있는 경우만 콜벡이 발생하므로 메세지 발생 이외의 작업을 처리하기가 어렵기 때문에 peekMessage를 사용하여 원할하게 프로그램이 진행되게 작업한다.
while (true)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (WM_QUIT == msg.message)
{
break;
}
if (!TranslateAccelerator(msg.hwnd/*메세지가 발생한 윈도우*/, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
// 게임 코드 실행
CCore::GetInstance()->progress();
}
}
2. 비동기 키 입력의 사용
GetAsyncKeState() 함수를 사용하면 키입력을 메세징 방식이 아니게 받아올 수 있다
GetAsyncKeyState(VK_LEFT) & 0x8000 // 눌렀을때
GetAsyncKeyState(VK_LEFT) & 0x0001 // 떼었을때
GetAsyncKeyState(VK_LEFT) & 0x8001 // 누르고 있는중일때
3. progress
왼쪽 오른쪽 키 입력을 이용하여 사각형을 그리는 것이며 DELTATIME은 유니티의 Time.deltaTime과 동일하다
void CCore::progress()
{
CTimeManager::GetInstance()->update();
update();
render();
}
void CCore::update()
{
Vector2 ptPos = g_obj.GetPos();
if (GetAsyncKeyState(VK_LEFT) & 0x8000) {
ptPos.x -= 100.f * DELTATIME;
}
if (GetAsyncKeyState(VK_RIGHT) & 0x8000) {
ptPos.x += 100.f * DELTATIME;
}
g_obj.SetPos(ptPos);
}
void CCore::render()
{
Vector2 ptPos = g_obj.GetPos();
Vector2 ptSize = g_obj.GetSize();
// 랜더링
Rectangle(m_hdc,
ptPos.x - ptSize.x / 2, ptPos.y - ptSize.y / 2,
ptPos.x + ptSize.x / 2, ptPos.y + ptSize.y / 2);
}
4. C++에서의 싱글톤화
c#의 경우는 아래와 같은 방식을 주로 사용하였다
class singleton
{
private static singleton _instance;
public static singleton Instance
{
get{
if(_instance == null){
_instance == new singleton();
}
return _instance;
}
}
}
하지만 c++은 data영역에만 싱글톤을 올려두는 것이 가능하였다
static classname* GetInstance()
{
static classname instance;
return &instance;
}
c++로 c#방식으로 표현이 가능하며 둘다 장단점이 있기때문에 상황에 따라 사용하면 좋을거 같다
(data영역은 해제하지는 못하지만 heap은 해제가 가능하기때문에)
5. 몇가지 추가로 알게된 함수들
// 윈도우 버전마다 메뉴바의 크기가 다르므로 아래 함수를 사용한다
AdjustWindowRect(&rt, WS_OVERLAPPEDWINDOW, true); // 랜더링할 부분의 크기를 얻어온다.
SetWindowPos(m_hWnd, nullptr, 100, 100, rt.right - rt.left,
rt.bottom - rt.top, 0);
//DELTATIME구현방법
QueryPerformanceCounter(); // 현재 타임스탬프를 나타낸다
QueryPerformanceFrequency(); // 초당 연산횟수를 나타낸다
//위 두함수를 사용하여 1프레임에 몇초 걸렸는지 확인한다
void CTimeManager::init()
{
// 현재 카운팅
QueryPerformanceCounter(&m_prevCounter);
// 초당 연산 가능한 횟수
QueryPerformanceFrequency(&m_frequency);
}
void CTimeManager::update()
{
// 현재카운팅을 가져온다
QueryPerformanceCounter(&m_curCounter);
// 1프레임에 걸리는 시간을 계산하다
m_deltaTime = (m_curCounter.QuadPart - m_prevCounter.QuadPart)
/ (double)m_frequency.QuadPart;
// 이전 시간을 현재 시간으로 갱신한다
m_prevCounter = m_curCounter;
++m_callCount;
m_accumTime += m_deltaTime;
if (m_accumTime >= 1.0)
{
m_fps = m_callCount;
m_accumTime = 0.0;
m_callCount = 0;
}
}
728x90
'windowAPI' 카테고리의 다른 글
WindowApi 6강 - range기반 for문의 주의점 (0) | 2024.11.23 |
---|---|
WindowAPi 5강 - SceneManager (0) | 2024.11.19 |
WinAPI 4강 - KeyManager (0) | 2024.11.19 |
windowAPI - 3일차 double buffering (0) | 2024.11.18 |
WindowAPI 1일차 - 사각형 그리기 (0) | 2024.11.17 |