https://www.microsoft.com/japan/msdn/academic/Articles/DirectX/02/제2장 DirectX Graphics의 기초

~ DirectX를 이용한 게임프로그래밍 입문 ~

2.1 시작하며
최근에 컴퓨터의 보급으로 인하여 윈도 상에서 작동하는 게임이 많이 판매되고 있습니다. 또한 최근에는 기업에서 판매하는 게임 외에도 개인이 개발한 게임을 어렵지 않게 발견할 수 있게 되었습니다. 그런 가운데, 초보자에게도 간단하게 게임 프로그램을 구동시킬 수 있는 환경으로 DirectX가 주목받고 있습니다.

제 1 장에서는 3D게임 개발에 있어서 핵심이라 할 수 있는 객체의 조작에 대하여 설명하였습니다. 이번 장에서는 한걸음 나아가 게임 프로그램에 있어서 중요한 부분인 캐릭터에 텍스쳐 입히기, 문자열의 표시, 시점의 이동과 캐릭터 관리에 대하여 설명하도록 하겠습니다. 3D 슈팅게임 제작에 필요한 기술을 그림1에 나타냈습니다.

DirectX2-1.gif
[ 그림 1. 3D 슈팅게임 제작에 필요한 기술 ]


이번 장에서는 그림1의 STEP 1에 대하여 자세히 설명하겠습니다.

2.2 텍스쳐 입히기
3D 모델에 텍스쳐를 입히는 것은 게임 전체에 깔끔하고 아름다운 색과 형태를 부여하여 게임의 즐거움을 배가시킬 뿐 아니라, 게임의 캐릭터를 결정짓는데 있어서 커다란 도움이 될 것입니다.

텍스쳐는 X파일이나 그 외 3D 객체 등, 모든 객체에 입히는 것이 가능합니다. 게임 프로그램에서 캐릭터를 표현할 경우, X파일을 사용하는 것이 일반적입니다. 그렇기 때문에 이번 절에서는 X파일에 텍스쳐를 입히는 방법에 대하여 설명하도록 하겠습니다. X파일에 텍스쳐를 입히는 개념은 그림2에 나타나 있습니다.

DirectX2-2.gif
[ 그림 2. 텍스쳐의 개념 ]

2.2.1 X파일 읽어오기
X 파일에 텍스쳐를 입히기 위해서는 우선 X파일을 읽어올 때에 텍스쳐 정보를 얻어와야 합니다. 이번 항에서는 X파일을 읽을 때 D3DXLoadMeshFromX 함수를 사용하겠습니다. D3DXLoadMeshFromX 함수는 X파일의 구조정보 등을 D3DXMATERIAL 구조체 배열로 반환합니다. D3DXMATERIAL 구조체는 DirectX9에서 D3DMATERIAL9 구조체로 포함되어 있습니다. D3DMATERIAL9 구조체는 읽어들인 X파일의 여러가지 재질이나 텍스쳐의 정보 등을 갖고 있습니다. 재질을 예로 들면 X파일의 빛의 정도 같은 조명계산에 사용하는 파라메터가 있습니다. 개발자는 재질의 구조정보를 세밀하게 설정하여 그래픽이 풍부한 캐릭터를 만들어 낼 수 있습니다.

다음으로 X파일을 그리기 위한 텍스쳐 입히기 작업으로 텍스쳐 객체를 생성하는 것이 있습니다. DirectX9에서는 이미지 파일로부터 텍스쳐 객체를 생성하기 위한 편리한 함수가 준비되어 있습니다. 개발자는 D3DXCreateTextureFromFile 함수를 사용함으로써 간단히 텍스쳐 객체를 생성할 수 있습니다. D3DXCreateTextureFromFile 함수의 선언은 다음과 같습니다.

HRESULT D3DXCreateTextureFromFile(
   LPDIRECT3DDEVICE9 pDevice, // 디바이스 객체
   LPCTSTR pSrcFile, // 텍스쳐 이미지의 파일명
   LPDIRECT3DTEXTURE9 *ppTexutre // 텍스쳐 객체의 포인터를 저장하는 주소
   );

X파일을 읽을 때에 텍스쳐 정보를 읽는 코드는 다음과 같습니다.
[code] BOOL CDXSimpleObject::LoadX(char* fn, LPDIRECT3DDEVICE9 pD3DDevice) { LPD3DXBUFFER pD3DBufMtr; // D3Dbuffer 객체의 포인터 HRESULT hres; // COM에러코드 hres = D3DXLoadMeshFromX( fn, // 파일명 D3DXMESH_SYSTEMMEM, // 시스템 메모리 상에 로드 pD3DDevice, // Direct3Ddevice 객체 NULL, &pD3DBufMtr, // D3DXMATERIAL 구조체 배열 NULL, &m_dwNumMaterials, // 재질 그룹의 개수를 얻어올 주소 &m_pMesh // D3DXMESH 객체의 인터페이스를 얻어올 주소 ); // 메시 정보를 X파일로부터 로드 // D3DXMATERIAL 구조체 배열의 포인터를 얻어옴 D3DXMATERIAL* d3dxmatrs = (D3DXMATERIAL*)pD3DBufMtr->GetBufferPointer(); // LPDIRECT3DTEXTURE9 타입의 배열을 할당 m_ppTextures = (LPDIRECT3DTEXTURE9*)malloc(sizeof(LPDIRECT3DTEXTURE9) * m_dwNumMaterials); // D3DMATERIAL9 구조체 배열을 할당 m_pMatrs = (D3DMATERIAL9*)malloc(sizeof(D3DMATERIAL9) * m_dwNumMaterials); for (int i = 0; i < (int)m_dwNumMaterials; i++) { m_pMatrs[i] = d3dxmatrs[i].MatD3D; // 재질 정보를 복사 // D3DXCreateTextureFromFile 함수가 실패했을 경우 if (D3DXCreateTextureFromFile( pD3DDevice, d3dxmatrs[i].pTextureFilename, &m_ppTextures[i] ) != S_OK ) // 텍스쳐 이미지 파일명으로부터 텍스쳐 객체를 생성 m_ppTextures[i] = NULL; // D3DXCreateTextureFromFile 함수가 실패하면 텍스쳐는 없음 } pD3DBufMtr->Release(); // D3DXBUFFER 객체를 해제 return TRUE; // TRUE를 반환하고 종료 } [/code]
2.2.2 그리기 처리
X파일은 객체를 같은 재질의 면을 기준으로 그룹화하여 관리합니다. 동일한 재질별로 그리기 처리를 하기 때문에 그리기 퍼포먼스가 향상되어 게임 전체 처리속도를 대폭 향상시킬 수 있습니다. X파일의 그리기 처리의 흐름을 그림 3에 나타내었습니다.

DirectX2-3.gif
[ 그림 3. X파일의 그리기 처리의 흐름도 ]


같은 재질의 그룹별로 그리기를 하는 코드의 예는 다음과 같습니다.
[code] // 같은 재질의 그룹별로 그리기 for (unsigned int u = 0; u < m_dwNumMaterials; u++) { pD3DDevice->SetMaterial(&m_pMatrs[u]); // 디바이스에 재질을 설정 pD3DDevice->SetTexture(0, m_ppTextures[u]); // 디바이스에 텍스쳐를 설정 m_pMesh->DrawSubset(u); // 메시를 그림 } [/code]
2.3 문자열의 표시
게임에서 제한시간이나 점수 등의 문자정보는 플레이어에게 정보를 제공하는 수단으로 반드시 필요한 것입니다. 예를 들면, 점수는 슈팅게임에서 게임의 달성도나 승패를 판단하는 기준이 됩니다. 이번 절에서는 화면에 문자열을 표시하는 방법에 대해 설명하겠습니다.

2.3.1 문자열 표시의 개요
DirectX는 DirectX8을 지나면서 크게 사양이 변경되었습니다. 문자열의 표시방법도 크게 변경된 기능 중 하나입니다. DirectX8 이전 버전에서는 GDI(Graphics Device Interface)를 사용하여 문자열을 화면에 표시했습니다. 하지만 DirectX8 이후 버전에서는 X-box와의 호환성 문제로 GDI를 사용하여 문자열을 화면에 표시하지 않게 되었습니다. 그래서 DirectX8 이후 버전에서는 DirectX 문자관련 처리용 인터페이스를 사용하여 화면에 문자열을 표시하게 됩니다.

2.3.2 논리글꼴정보의 작성
윈도에는 논리글꼴정보를 작성하기 위한 API 함수로 CreateFont 함수가 준비되어 있습니다. CreateFont 함수를 사용여 논리글꼴정보를 작성할 수 있습니다. CreateFont 함수의 선언은 다음과 같습니다.

HFONT CreateFont(
   int nHeight, // 글꼴의 높이
   int nWidth, // 글꼴의 폭
   int nEscapement, // 기울기
   int nOrientation, // 각도
   int nWeight, // 글꼴의 두께
   DWORD dwItalic, // 이탤릭
   DWORD dwUnderline, // 밑줄
   DWORD dwStrikeOut, // 삭제선
   DWORD dwCharSet, // 문자 코드세트
   DWORD dwOutputPrecision, // 출력정도
   DWORD dwClipPrecision, // 클리핑정도
   DWORD dwQuality, // 품질
   DWORD dwPitchAndFamily, // 피치
   LPCTSTR lpszFace // 글꼴명
);
논리글꼴정보를 세밀하게 설정하여 게임 화면을 더 낫게 할 수 있습니다. CreateFont 함수를 사용하여 논리글꼴정보를 작성하는 코드의 예는 다음과 같습니다.
[code] HFONT hFont = ::CreateFont(16, 0, 0, 0, 0, 0, 0, 0, HANGUL_CHARSET, 0, 0, 0, 0, NULL); // 논리글꼴정보를 작성 [/code] CreateFont 함수는 파라메터에 0 또는 NULL을 지정하여 기본값을 설정할 수 있습니다. 위 예에서 작성된 논리글꼴의 정보는 문자의 높이를 16포인트로 설정하고 문자 코드세트를 한글로 설정하고 있습니다. 또한 글꼴 이름 파라메터에 NULL로 설정하면, 표준 설정인 경우 굴림이 자동적으로 선택됩니다.
(원문이 일본어인 관계로 원문에는 일본어 코드셋인 SHIFTJIS_CHARSET로 설정되어 있으며 일본어 윈도에서 기본 글꼴은 MS고딕이 설정됩니다. 이에 혼란을 느낄 수가 있어서, 문자코드와 글꼴을 HANGUL_CHARSET과 굴림으로 바꿔서 번역하였습니다. : 역자주)

2.3.3 문자열 그리기
문자열을 화면에 표시하려면 논리글꼴정보를 기반으로 출력할 문자열을 작성하여 화면에 표시해야 합니다. 문자열을 화면에 표시하는 흐름도를 그림 4에 나타냈습니다.

DirectX2-4.gif
[ 그림 4. 문자열을 화면에 표시하는 흐름도 ]


DirectX에서는 문자열을 화면에 표시하기 위해 ID3DXFont 인터페이스를 사용합니다. DirectX에는 ID3DXFont 인터페이스를 초기화하기 위한 함수로 D3DXCreateFont 함수가 준비되어 있습니다. D3DXCreateFont 함수의 선언은 다음과 같습니다.

INT DrawText(
   LPCSTR pString, // 출력할 문자열
   INT Count, // 출력할 문자열의 바이트 수
   LPRECT pRect, // 문자열을 출력할 영역
   DWORD Format, // 출력 문자열의 양식
   D3DCOLOR Color // 문자의 색
);

DrawText 메써드를 사용하여 화면에 지정한 문자열을 그리는 코드의 예는 다음과 같습니다. [code] pD3DXFont->Begin(); // 그리기 시작 pD3DXFont->DrawText(psz, strlen(psz), &rc, DT_SINGLELINE, color); // 문자열을 출력 pD3DXFont->End(); // 그리기 종료 [/code]
2.4 시점
게임에 박력이나 현실감을 주어 플레이어를 게임세계에 빠져들게 하기 위해서는 효과적으로 시점을 이동시켜야 합니다. 예를 들어 3D 게임에서 시점의 변경은 게임 전체에 임장감(臨場感)을 주어, 게임 캐릭터와 플레이어가 마치 하나가 된 것 같은 효과를 줄 수 있습니다. 이번 절에서는 시점을 효과적으로 이동시키는 방법에 대해 설명하겠습니다.

2.4.1 시점의 개념
2D 그래픽을 사용한 게임에서는 시점 이동은 화면전체를 스크롤하는 것과 같습니다. 예를 들면 화면전체를 왼쪽으로 스크롤하면 시점이 오른쪽으로 평행이동하는 것을 말합니다. 3D 그래픽을 사용한 게임의 시점이동의 개념은 화면의 스크롤에 의해 시점이동을 표현하기 때문에 2D 그래픽의 시점이동의 개념과 같습니다. 예를 들면 시점을 오른쪽으로 이동시키기 위해서는 3D 공간 전체를 왼쪽으로 이동시키게 됩니다. 또한 시점을 오른쪽으로 회전시키기 위해서는 3D 공간 전체를 왼쪽으로 회전시킵니다.

2.4.2 뷰(View) 변환
시점은 3D 공간에서 위치와 방향을 갖습니다. 시점의 위치는 3D 공간 전체의 이동변환에 의해 변경됩니다. 또한 시점의 방향은 3D 공간전체의 회전변환에 의해 표현됩니다. 그 때문에, 시점을 표현하기 위해서는 회전행렬과 이동행렬을 합성한 뷰 행렬(View matrix)을 생성하는 편리한 함수로 D3DXMatrixLookAtLH가 준비되어 있습니다. D3DXMatrixLookAtLH 함수의 선언은 다음과 같습니다.

D3DXMATRIX *D3DXMatrixLookAtLH(
D3DXMATRIX *pOut, // D3DXMATRIX 구조체의 주소
CONST D3DXVECTOR3 *pEye, // 시점의 위치
CONST D3DXVECTOR3 *pAt, // 시점의 방향
CONST D3DXVECTOR3 *pUp, // 시점의 방향
);
D3DXMatrixLookAtLH 함수를 사용하면, 시점의 위치나 방향을 표현하는 뷰 행렬을 생성할 수 있습니다. 시점의 위치나 방향의 개념을 그림 5에 나타냈습니다.
DirectX2-5.gif
[ 그림 5. 시점의 개념 ]


D3DXMatrixLookAtLH 함수를 사용하여 뷰 행렬을 생성하는 코드의 예는 다음과 같습니다.
[code] D3DXMATRIX d3dxmatView; // 뷰 행렬을 저장할 구조체 D3DXMatrixLookAtLH( &d3dxmatView, // D3DXMATRIX 구조체의 주소 &(D3DXVECTOR3((float)sin(vr * 0.017453f) * 20.0f, 0.0f, (float)cos(vr * 0.017453f) * 20.0f )), // 시점의 위치 &(D3DXVECTOR3(0.0f, 0.0f, 0.0f)), // 시점의 방향 &(D3DXVECTOR3(0.0f, 1.0f, 0.0f)) // 시점의 방향 ); // 시점의 위치와 방향을 지정하여 뷰 행렬을 생성 [/code]
2.5 캐릭터 관리
복수의 캐릭터를 동시에 다루는 것은 게임성을 높이기 위한 중요한 요소입니다. 게임에는 롤플레잉게임이나 슈팅게임 등 다양한 장르가 존재하는데, 복수의 캐릭터를 관리하는 것은 모든 게임 장르에 있어서 반드시 필요한 기술입니다. 복수의 캐릭터를 관리하는 방법에 대해 설명하겠습니다.

2.5.1 캐릭터 관리의 개념
게임성을 높이기 위해서는 복수의 캐릭터를 동시에 다룰 필요가 있습니다. 게임 프로그램에서는 플레이어가 있는 공간 상에 캐릭터를 자유로이 추가, 삭제하는 구조를 가져야 합니다. 게임 프로그램에서의 캐릭터 관리의 개념을 그림 6에 나타냈습니다.
DirectX2-6.gif
[ 그림 6. 캐릭터 관리의 개념 ]

게임 프로그램에서는 캐릭터를 그룹화하여 관리하는 방법이 일반적입니다. 캐릭터를 그룹화하여 관리하는 방법에는 크게 두가지 장점이 있습니다. 첫 번째로는 캐릭터의 일원관리가 가능하기 때문에 등록과 삭제를 용이하게 할 수 있습니다. 두번째로는 캐릭터의 추가나 삭제 코드를 모든 캐릭터를 통해서 공통화할 수 있기 때문에 개발자는 프로그램을 간결하게 표현할 수 있습니다.

2.5.2 캐릭터의 추가와 삭제
게임 프로그램에서는 복수의 종류의 캐릭터를 관리할 경우 캐릭터의 종류별로 정보를 가져야 합니다. 예를 들어 슈팅게임의 경우, 캐릭터의 위치나 캐릭터의 이동속도 등이 있습니다. 각 캐릭터는 위치나 이동속도 등의 정보를 가짐으로써 캐릭터 1개 1개가 자유로운 움직임을 보장받게 됩니다. 게임 프로그램에서는 각각의 캐릭터에 대한 정보를 클래스가 아닌 구조체로 관리하는 것이 일반적입니다. 캐릭터를 구조체로 관리함으로써, 객체의 생성이나 소멸 등의 처리가 가벼워져 처리속도의 향상을 꾀할 수 있습니다. 캐릭터의 정보를 관리하는 구조체의 선언의 예가 다음에 있습니다. [code] Typedef struct _tagNODEINFO { BOOL bActive; // 플래그 int x, y; // 위치 int vx, vy; // 속도 } NODEINFO; [/code]
게임 프로그램에서는 복수의 구조체변수를 관리함으로써 복수의 캐릭터를 관리할 수 있습니다. 복수의 구조체변수를 관리하는 방법으로는 구조체를 리스트 구조로 관리하는 방법과 구조체를 배열로 관리하는 방법 등 2가지가 있습니다. 구조체를 리스트 구조로 관리하는 방법은 다음 리스트의 첫번째 주소를 보관하는 등 복잡한 처리를 해야합니다. 그렇기 때문에 이번 항에서는 구조체를 배열로 관리하는 방법을 사용하겠습니다. 배열로 관리하는 방법은 구조체변수의 배열 하나에 캐릭터 그룹 하나의 정보를 할당하는 것입니다. 구조체배열에 의한 캐릭터 관리의 개념을 그림 7에 나타냈습니다.

DirectX2-7.gif
[ 그림 7. 구조체배열에 의한 캐릭터 관리의 개념 ]

구조체변수를 배열로 관리하는 방법에 대한 코드의 예는 다음과 같습니다.
[code] NODEINFO nodes[MAX_NODES]; [/code] MAX_NODE에는 캐릭터의 최대 개수를 지정합니다. 캐릭터 관리용 배열은 문자열정수로 정의합니다.

배열의 각 엔트리는, 엔트리가 미사용인지 아니면 사용중인지의 정보를 포함하고 있습니다. NODEINFO 구조체는 엔트리가 미사용인지 사용중인지의 정보를 멤버변수 bActive에 저장해두고 있습니다. 새로운 캐릭터를 추가할 경우 미사용 엔트리를 찾아서 멤버변수 bActive를 TRUE로 설정하여 사용중이라고 알립니다. 또한 캐릭터를 제거할 경우는 멤버변수 bActive를 FALSE라고 설정하여 미사용상태로 되돌립니다. 캐릭터 추가의 개념을 그림 8에 나타냈습니다.
DirectX2-8.gif
[ 그림 8. 캐릭터 추가의 개념 ]

캐릭터 추가는 멤버변수 bActive를 TRUE로 설정하는 것으로 나타냅니다. 캐릭터를 추가하는 코드의 예는 다음과 같습니다.
[code] BOOL CGameObjs::Add(float x, float y, float z, float vx, float vy, float vz) { int idx; // 배열의 전체 엔트리를 조사 for (idx = 0; idx < MAX_OBJS; idx++) { // 미사용상태의 엔트리인 경우 if (!m_objs[idx].bActive) { m_objs[idx].bActive = TRUE; // bActive 멤버를 TRUE로 설정하여 사용상태로 바꿈 m_objs[idx].m_fX = x; // 위치의 x 좌표를 설정 m_objs[idx].m_fY = y; // 위치의 y 좌표를 설정 m_objs[idx].m_fZ = z; // 위치의 z 좌표를 설정 m_objs[idx].m_fVX = vx; // 속도의 x 성분을 설정 m_objs[idx].m_fVY = vy; // 속도의 y 성분을 설정 m_objs[idx].m_fVZ = vz; // 속도의 z 성분을 설정 m_objs[idx].m_fR = 0; // 각도를 0으로 초기화 m_objs[idx].m_iParam1 = 0; // param1 멤버를 0으로 초기화 m_objs[idx].m_iKind = rand() % 3; // 랜덤하게 동작의 종류를 결정 return TRUE; // TRUE를 반환하고 종료 } } return FALSE; } [/code] 위 코드의 예에는 구조체배열을 처음부터 순차적으로 조사하여, 미사용상태의 배열을 검색합니다. 미사용상태의 배열을 발견한 경우 멤버변수 bActive를 TRUE로 설정하여 구조체배열을 사용중이라고 표시합니다.

2.5.3 캐릭터의 동작
제 2.5.2 항에서는 구조체배열을 이용하여 캐릭터를 그룹화하여 캐릭터를 자유로이 추가하고 삭제하는 처리에 대해 설명했습니다. 이번 항에서는 각 캐릭터에 동작을 부여하는 방법에 대해 설명하겠습니다. 캐릭터의 동작은 캐릭터의 종류에 따라 달라집니다. 예를 들면 적 캐릭터의 이동은 플레이어를 쫓아다닌다던가 플레이어로부터 도망가는 등입니다. 거기에 반해 플레이어의 캐릭터는 플레이어가 자유로이 조작할 수 있게 하기 위해 캐릭터의 동작을 설정하지 않습니다. [code] BOOL CGameObjs::Act(void) { int idx; // 배열 전체의 엔트리를 조사 for (idx = 0; idx < MAX_OBJS; idx++) { // 엔트리가 사용중 상태인 경우 if (m_objs[idx].bActive) { m_objs[idx].m_fX += m_objs[idx].m_fVX; // x좌표에 속도 x성분을 더함 m_objs[idx].m_fY += m_objs[idx].m_fVY; // y좌표에 속도 y성분을 더함 m_objs[idx].m_fZ += m_objs[idx].m_fVZ; // z좌표에 속도 z성분을 더함 // 캐릭터의 종류별로 동작 Behave(&m_objs[idx]); // 캐릭터의 높이가 -20 이하가 된 경우 if (m_objs[idx].m_fY < -20.0f) Delete(&m_objs[idx]); // 캐릭터를 삭제 m_objs[idx].m_fR += 0.1f; // 캐릭터의 각도에 0.1을 추가 } } return TRUE; } [/code] 위 코드의 예에서는 각 캐릭터를 바운드시키는 처리를 구현하였습니다. 캐릭터는 화면상에 등장하고 떨어지기 시작합니다. 그 후 캐릭터는 한 번 바운드하고 나서 화면 아래로 떨어집니다. 화면상에 표시되지 않는 위치까지 떨어지게 되면 캐릭터는 자기자신을 삭제시킵니다.

2.5.4 캐릭터 동작의 확장
게임에서는 각 캐릭터의 종류에 대응하여 동작이나 상태를 다르게 나타내야 합니다. 예를 들어 슈팅게임에서는 보스캐릭터와 졸병 캐릭터의 동작을 제각각 다르게 나타내야 합니다. 캐릭터의 종류에 따라 서로 다른 동작을 구현하는 방법은 두 가지가 있습니다. 첫번째는 각기 다른 동작을 하는 캐릭터의 종류별로 그룹을 만드는 것입니다. 하지만 이 방법은 프로그램을 복잡하게 만들고 처리가 장황하게 되어버리기 때문에 효과적이지 못합니다. 두번째로 각 캐릭터가 갖고 있는 정보에 동작의 종류를 나타내는 데이터를 추가하는 방법입니다. 전자에 비해 후자를 사용하는 것이 이 캐릭터의 호출을 일원관리할 수 있게 되고, 더욱 고도의 캐릭터 관리를 구현할 수 있게 됩니다. 각 캐릭터의 종류에 대응하여 동작이나 상태를 다르게 하는 코드의 예가 다음에 있습니다.
[code] void CGameObjs::Behave(GOBJ* pObj) { // 캐릭터 종류별로 동작을 다르게 함 switch(pObj->m_iKind) { case 0: pObj->m_fVY -= 0.02f; // 속도의 y성분에서 0.02를 뺌 break; case 1: pObj->m_fVY -= 0.013f; // 속도의 y성분에서 0.013을 뺌 break; case 2: pObj->m_fVY -= 0.03f; // 속도의 y성분에서 0.03을 뺌 break; } // 캐릭터 종류별로 동작을 다르게 함 switch(pObj->m_iKind) { case 0: case 1: if (pObj->m_fY < -8.0f && pObj->m_fVY<0 && pObj->m_iParam1 == 0) { pObj->m_fY = -8.0f; // 위치를 보정 pObj->m_fVY *= -0.4f; // 속도의 y성분에 -0.4을 곱함 (예전보다 늦게 반대방향으로 되돌아 옴) pObj->m_iParam1 = 1; // m_iParam1 멤버를 1로 세팅하여, 한 번 바운드 했다는 것을 나타냄 } break; case 2: if (pObj->m_fY < -8.0f && pObj->m_fVY<0 && pObj->m_iParam1 < 2) { pObj->m_fY = -8.0f; // 위치를 보정 pObj->m_fVY *= -0.7f; // 속도의 y성분에 -0.7을 곱함 (예전보다 늦게 반대방향으로 되돌아 옴) pObj->m_iParam1++; // m_iParam1 멤버를 증가시켜, 바운드했던 회수를 기록) } break; } } [/code] 위 코드의 예는 이번 장의 샘플 프로그램의 일부분입니다. 위 코드의 예에서는 GOBJ 구조체의 멤버변수 kind의 값에 따라서 객체의 낙하속도, 바운드의 높이나 바운드의 회수를 다르게 하고 있습니다. 샘플 프로그램을 실행시킨 예가 그림 9에 있습니다.

DirectX2-9.gif
[ 그림 9. 샘플 프로그램의 실행예 ]

2.6 마치며
이번 장에서는 3D 그래픽의 기초부터 한 발 나아가 문자열의 표시나 시점의 이동 등, 게임성을 높이기 위한 기술에 대해 설명했습니다. 또한 게임 프로그램 특유의 기술로써 캐릭터 관리에 대해 자세히 설명했습니다. 캐릭터 관리를 효과적으로 함으로써, 게임 루프를 간결하게 하여 처리속도의 향상을 가져올 수 있습니다.

다음 회에서는 렌즈플레어나 안개효과 등 DirectX Graphics의 특수효과에 대해 설명하겠습니다.

----------------------------------------

DirectX를 이용한 게임프로그래밍 입문
이 연재는 C++ 언어와 DirectX의 기초적인 지식이 있는 분을 대상으로 하고 있습니다.

제 1 장. 3D 게임 프로그래밍의 기초 (2003년 5월 1일)
제 2 장. DirectX Graphics의 기초 (2003년 8월 11일)
제 3 장. DirectX Graphics의 특수효과 (2003년 8월 11일)
제 4 장. 네트워크게임의 입문 (2003년 8월 11일)
제 5 장. 게임 개발 입문 (2003년 8월 21일)
제 6 장. 실전 게임 개발 (2003년 8월 29일)

----------------------------------------

저자약력

다나카 시게노리 (田中 成典)
1986년 칸사이대학 공학부 토목공학과 졸업
1988년 칸사이대학원 공학연구과 토목공학전공박사과정 전기과정 수료
1996년 박사(공학) 수여, 칸사이대학
1997년 칸사이대학 종합정보학부 조교수 (현재)
주요한 저서:
- 쉬운 C의 시작방법, 옴사(社), 1993년
- 건설기술자를 위한 지식정보처리의 실천, 칸사이대학출판부, 1999년
- DirectX8, 공학사, 2001년
- 스텝업 XML, 공학사, 2002년
- Linux 애플리케이션 입문, 모리키타(森北) 출판, 2002년 등

나카야마 코타로 (中山 浩太郎)
2001년 3월 칸사이대학 종합정보학과 졸업
2003년 3월 칸사이대학 대학원 종합정보학연구과 박사과정 전기과정 수료
2003년 4월 칸사이대학 대학원 종합정보학연구과 박사과정 후기과정 입학 (현재)
주요한 저서:
- Web 공방 시리즈 Perl의 달인, 모리키타(森北) 출판, 1999년
- 결정판 Visual Basic, 쿄리츠(共立) 출판, 2000년
- DirectX8, 공학사, 2001년
- Linux 애플리케이션 입문, 모리키타(森北) 출판, 2002년
- 스텝업 Visual C# .NET 입문, 공학사, 2002년 등

나카무라 켄지 (中村 健二)
2000년 4월 칸사이대학 종합정보학부 종합정보학과 입학 (현재)
주요한 저서: DirectX8 & VC++ 3D의 기초와 게임의 제작방법, 공학사, 2002년

키타가와 에츠지 (北川 悦司)
2000년 3월 칸사이대학 종합정보학부 종합정보학과 졸업
2002년 3월 칸사이대학 대학원 종합정보학연구과 박사과정 전기과정 수료
2002년 4월 칸사이대학 대학원 종합정보학연구과 박사과정 후기과정 입학 (현재)
주요한 저서:
- Web 공방 시리즈 Java의 달인, 모리키타(森北) 출판, 1999년
- 디지털 카메라 활용을 통한 디지털사진측량입문, 모리키타(森北) 출판, 2000년
- 스텝업 XML 활용법, 공학사, 2002년

우에야마 사토시 (上山 智士)
2002년 4월 칸사이대학 종합정보학부 종합정보학과 입학 (현재)

스기마치 토시유키 (杉町 敏之)
2003년 3월 칸사이대학 종합정보학부 종합정보학과 졸업
2003년 4월 칸사이대학 대학원 종합정보학연구과 입학 (현재)
주요한 저서: 스텝업 Visual C# .NET 입문, 공학사, 2002년

노나카 카즈키 (野中 一希)
2003년 3월 칸사이대학 종합정보학부 종합정보학과 졸업
2003년 4월 칸사이대학 대학원 종합정보학연구과 입학 (현재)
주요한 저서: 스텝업 Visual C# .NET 입문, 공학사, 2002년