MFC 게임구조 공부

게임과 MFC
 

일반적으로 게임을 제작할 때 MFC는 적당하지 않다는 의견이 지배적입니다.
그 이유를 알아 보면,


1) 구조가 복잡하다 

2) MFC 자체의 덩치가 너무 크다 

3) 속도가 느리다 


등이 있겠습니다.
그렇지만 MFC가 그렇게 나쁜 것만은 아닙니다.

MFC를 자세히 모를때에는 복잡하고 난해해 보이지만 익숙해 지면 구조가 잘 체계화되어 있어 쉽게 프로그램을 
제작할 수 있도록 도움을 줍니다. 
(실제로 전 File관련 클래스를 만들 때 MFC의 CFile클래스의 소스들을 보면서 구조를 정리했습니다)


다만, 너무나 많은 예외처리와 규칙 검사로 인해 속도가 느리고 세부적으로 제어하기 
힘든 면이 있는 것도 사실입니다.

그래서 게임을 제작할 때, 메인은 API로 제작하고 툴등은 MFC로 제작하는 것이 일반적 
이라 볼수 있죠.


하지만 MFC로 메인을 제작하는 게임도 있습니다. 에어리언 슬레이어라는 게임도 메인을 
MFC로 제작한 것 같구요. 그리고 간단한 게임들도 쉽게 MFC로 제작할 수 있습니다.

그래서, 저는 여기서 MFC를 이용하여 게임을 제작하는 방법에 대해서 이야기 해 보려고 
합니다. (VC 6.0기준)

처음에 프로젝트를 구성합니다.

그다음 Application Type을 설정합니다.



MFC는 doc/view구조를 가지기 때문에 이대로 게임 메인을 구성하면 복잡해 집니다.  
Single document에 doc/view란을 끈채 설정하세요. 
(VC5.0에는 이러한 것이 없으나 VC5.0도 doc/view구조를 사용자가 직접 없앨 수 있습니다) 

그다음 몇가지는 중요하지 않고 다음 화면에서 필요없는 부분을 설정하지 않은채 넘어 가면 됩니다.
 

이렇게 하여 프로젝트가 생성되었을 겁니다.

이제 프로젝트 파일을 보면 프로젝트를 생성할 때 doc/view란을 off하였지만, 완전히 그 구조가 
사라진 것은 아닙니다.
여전히 MainFrm에서 ChildView를 생성하고 있죠.
ChildView를 없애기 위해서는 MainFrm.cpp에서 m_wndView라는 것을 찾아 주석처리 하면 됩니다.


int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 

        if (CFrameWnd::OnCreate(lpCreateStruct) == -1) 
                return -1; 
/* 
        // create a view to occupy the client area of the frame 
        if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, 
                CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL)) 
        { 
                TRACE0("Failed to create view window\n"); 
                return -1; 
        } 
*/ 

        return 0; 
}


MainFrame에서 OnSetFocus, OnCmdMsg라는 이벤트 부분은 삭제를 하시고요.

App에서 OnAppAbout도 없애시고..


이제 한번 컴파일시켜 실행시켜 보세요. 그런 다음에 메뉴를 없애 보도록 하죠.
 

void GetWindowSizeFromClientSize(DWORD dwStyle, BOOL bMenuFlag, int cx, int cy, int& wx, int& wy) { 
    RECT rc; 
    SetRect(&rc, 0, 0, cx, cy);

        if(dwStyle & WS_OVERLAPPED == WS_OVERLAPPED) dwStyle := WS_CAPTION;

    AdjustWindowRect(&rc, dwStyle, bMenuFlag);

        if(dwStyle & WS_VSCROLL) { 
                rc.right += GetSystemMetrics(SM_CXVSCROLL); 
        } 
        if(dwStyle & WS_HSCROLL) { 
                rc.bottom += GetSystemMetrics(SM_CYHSCROLL); 
        } 
    wx = rc.right - rc.left; 
    wy = rc.bottom - rc.top; 
}
 

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) 

        if( !CFrameWnd::PreCreateWindow(cs) ) 
                return FALSE; 
        // TODO: Modify the Window class or styles here by modifying 
        //  the CREATESTRUCT cs

        cs.dwExStyle &= ~WS_EX_CLIENTEDGE; 
        //cs.lpszClass = AfxRegisterWndClass(0); 
        cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
                ::LoadCursor(NULL, IDC_ARROW), HBRUSH(GetStockObject(BLACK_BRUSH)), NULL);

        int cx, cy;

        GetWindowSizeFromClientSize(cs.style, FALSE, 640, 480, cx, cy);

        cs.cx = cx; 
        cs.cy = cy;    

        CMenu* pMenu = new CMenu; 
        pMenu->Attach(cs.hMenu); 
        pMenu->DestroyMenu();

        cs.hMenu = NULL;

        delete pMenu;

        return TRUE; 
}


그리고 여기서 주의하실 것은 윈도우의 크기입니다. 640x480화면을 기대하신다면 위의 소스처럼 
해 주셔야 합니다. 왜냐하면 윈도우는 클라이언트영역과 비클라이언트영역으로 나누어지기 
때문에 640x480의 클라이언트화면을 원하단면 거기에 어울리는 윈도우크기를 지정해야 합니다. 
여기서 GetWindowSizeFromClientSize라는 함수가 그 역활을 하고 있습니다.
 

이렇게 하였다면, 이제부터는 사용자가 하고자하는 대로 설정하시면 됩니다.

timer를 돌려서 게임을 진행하시려면 이벤트만 첨가하시면 되는 거구요. 아니면 일반적인 
게임 구성법을 따르고 싶으시다면 App에 Run이라는 이벤트를 첨가하신 뒤에 다음과 
같이 작성하시면 됩니다.


int CCbApp::Run() 

        // TODO: Add your specialized code here and/or call the base class 
        MSG msg;

        while(TRUE) { 
              if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { 
                        if(!GetMessage(&msg, NULL, 0, 0)) { 
                                ExitInstance(); 
                                return msg.wParam;                      // WM_QUIT 
                        } 
                        TranslateMessage(&msg); 
                        DispatchMessage(&msg); 
              } else { 
                        if(게임이 활성화되었다면) { 

                                // 게임 
                        } else WaitMessage(); 
              } 

        } 
         
        return CWinApp::Run(); 
}
 

위와 같은 형태라면 api로 작성하는 거나 mfc로 작성하는 거나 비슷한 구조를 
가지게 될 것입니다.



출저:: 게임 개발자 네트워크 (jzsdn) :: 네이버 카페

이 글을 공유하기

댓글

Designed by JB FACTORY