Direct X Demo 따라하기 Direct X Wizard를 이용하여 프로젝트를 생성한다 File -> New -> Project ->DirectX 9 AppWizard 프로젝트 경로 및 프로젝트 이름 설정 후 OK -> Direct Music 제거 후 Next -> Triangle 선택 후 Next -> DirectInput Keyboard device 선택 후 Finish multimedia.bmp, multi2.wav, multi3.wav 화일을 프로젝트 디렉토리에 복사한다.
Direct X Demo 따라하기 우선 배경공간을 만든다 텍스쳐를 사용하기 위하여 텍스쳐 구조체를 선언한다. 프로젝트이름.h 에 버텍스 정보(위치, 법선, 텍스쳐 좌표)를 만든다. 코드 struct CUSTOMVERTEX { D3DXVECTOR3 position; // vertex position D3DXVECTOR3 normal; // vertex normal float tu,tv; }; #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1) 텍스쳐를 사용하기 위하여 텍스쳐 구조체를 선언한다. 프로젝트이름.h 에 CMyD3DApplication의 멤버변수로 다음을 추가한다. LPDIRECT3DTEXTURE9 g_pTexture1;
Direct X Demo 따라하기 텍스쳐와 버텍스를 생성한다. 프로젝트이름.cpp에 InitDeviceObjects()함수의 내용을 다음과 같이 변경한다. 배경을 그리기 위하여 사각형 4개( 삼각형 8개 – 점 24개)를 생성하며 multimedia.bmp화일을 텍스쳐로 생성한다. 코드 HRESULT hr; // Init the font m_pFont->InitDeviceObjects( m_pd3dDevice ); if( FAILED( D3DXCreateTextureFromFile( m_pd3dDevice, "multimedia.bmp", &g_pTexture1 ) ) ) { return E_FAIL; } // Create the vertex buffer if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( 24*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_MANAGED, &m_pVB, NULL ) ) ) return DXTRACE_ERR( "CreateVertexBuffer", hr ); // Fill the vertex buffer with 2 triangles CUSTOMVERTEX* pVertices; //버텍스를 통하여 벽생성 사각형 4개를 생성 if( FAILED( hr = m_pVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) ) return DXTRACE_ERR( "Lock", hr );
텍스쳐와 버텍스를 생성한다. 프로젝트이름.cpp에 InitDeviceObjects()함수의 내용을 다음과 같이 변경한다. 배경을 그리기 위하여 사각형 4개( 삼각형 8개 – 점 24개)를 생성하며 multimedia.bmp화일을 텍스쳐로 생성한다. 코드 HRESULT hr; // Init the font m_pFont->InitDeviceObjects( m_pd3dDevice ); if( FAILED( D3DXCreateTextureFromFile( m_pd3dDevice, "multimedia.bmp", &g_pTexture1 ) ) ) { return E_FAIL; } // Create the vertex buffer if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( 24*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_MANAGED, &m_pVB, NULL ) ) ) return DXTRACE_ERR( "CreateVertexBuffer", hr ); // Fill the vertex buffer with 2 triangles CUSTOMVERTEX* pVertices; //버텍스를 통하여 벽생성 사각형 4개를 생성 if( FAILED( hr = m_pVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) ) return DXTRACE_ERR( "Lock", hr ); pVertices[0].position = D3DXVECTOR3( -10.0f, -2.0f, 80.0f ); pVertices[0].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[0].tu = 0.0f; pVertices[0].tv = 0.0f; pVertices[1].position = D3DXVECTOR3( 10.0f, -2.0f, 80.0f ); pVertices[1].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[1].tu = 1.0f; pVertices[1].tv = 0.0f;
pVertices[2].position = D3DXVECTOR3( 10.0f, -2.0f, -10.0f ); pVertices[2].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[2].tu = 1.0f; pVertices[2].tv = 1.0f; pVertices[3].position = D3DXVECTOR3( -10.0f, -2.0f, 80.0f ); pVertices[3].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[3].tu = 0.0f; pVertices[3].tv = 0.0f; pVertices[4].position = D3DXVECTOR3( 10.0f, -2.0f, -10.0f ); pVertices[4].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[4].tu = 1.0f; pVertices[4].tv = 1.0f; pVertices[5].position = D3DXVECTOR3( -10.0f, -2.0f, -10.0f ); pVertices[5].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[5].tu = 0.0f; pVertices[5].tv = 1.0f; pVertices[6].position = D3DXVECTOR3( -10.0f, 5.0f, -10.0f ); pVertices[6].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[6].tu = 0.0f; pVertices[6].tv = 0.0f; pVertices[7].position = D3DXVECTOR3( -10.0f, -2.0f, 80.0f ); pVertices[7].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[7].tu = 1.0f; pVertices[7].tv = 1.0f; pVertices[8].position = D3DXVECTOR3( -10.0f, -2.0f, -10.0f ); pVertices[8].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[8].tu = 0.0f; pVertices[8].tv = 1.0f; pVertices[9].position = D3DXVECTOR3( -10.0f, 5.0f, -10.0f ); pVertices[9].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[9].tu = 0.0f; pVertices[9].tv = 0.0f; pVertices[10].position = D3DXVECTOR3( -10.0f, 5.0f, 80.0f ); pVertices[10].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[10].tu = 1.0f; pVertices[10].tv = 0.0f; pVertices[11].position = D3DXVECTOR3( -10.0f, -2.0f, 80.0f );
pVertices[11].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[11].tu = 1.0f; pVertices[11].tv = 1.0f; pVertices[12].position = D3DXVECTOR3( -10.0f, 5.0f, 80.0f ); pVertices[12].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[12].tu = 0.0f; pVertices[12].tv = 0.0f; pVertices[13].position = D3DXVECTOR3( 10.0f, -2.0f, 80.0f ); pVertices[13].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[13].tu = 1.0f; pVertices[13].tv = 1.0f; pVertices[14].position = D3DXVECTOR3( -10.0f, -2.0f, 80.0f ); pVertices[14].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[14].tu = 0.0f; pVertices[14].tv = 1.0f; pVertices[15].position = D3DXVECTOR3( -10.0f, 5.0f, 80.0f ); pVertices[15].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[15].tu = 0.0f; pVertices[15].tv = 0.0f; pVertices[16].position = D3DXVECTOR3( 10.0f, 5.0f, 80.0f ); pVertices[16].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[16].tu = 1.0f; pVertices[16].tv = 0.0f; pVertices[17].position = D3DXVECTOR3( 10.0f, -2.0f, 80.0f ); pVertices[17].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[17].tu = 1.0f; pVertices[17].tv = 1.0f; pVertices[18].position = D3DXVECTOR3( 10.0f, 5.0f, 80.0f ); pVertices[18].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[18].tu = 0.0f; pVertices[18].tv = 0.0f; pVertices[19].position = D3DXVECTOR3( 10.0f, -2.0f, -10.0f ); pVertices[19].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[19].tu = 1.0f; pVertices[19].tv = 1.0f; pVertices[20].position = D3DXVECTOR3( 10.0f, -2.0f, 80.0f );
pVertices[20].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[20].tu = 0.0f; pVertices[20].tv = 1.0f; pVertices[21].position = D3DXVECTOR3( 10.0f, 5.0f, 80.0f ); pVertices[21].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[21].tu = 0.0f; pVertices[21].tv = 0.0f; pVertices[22].position = D3DXVECTOR3( 10.0f, 5.0f, -10.0f ); pVertices[22].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[22].tu = 1.0f; pVertices[22].tv = 0.0f; pVertices[23].position = D3DXVECTOR3( 10.0f, -2.0f, -10.0f ); pVertices[23].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[23].tu = 1.0f; pVertices[23].tv = 1.0f; m_pVB->Unlock(); return S_OK;
Direct X Demo 따라하기 3차원 환경을 변경한다. 프로젝트이름.cpp의 RestoreDeviceObjects()함수안의 내용에 다음과 같이 수정한다 코드 // 모든 빛을 반사한다. D3DMATERIAL9 mtrl; D3DUtil_InitMaterial( mtrl, 1.0f, 1.0f, 1.0f ); m_pd3dDevice->SetMaterial( &mtrl ); //전체적인 밝기를 밝게 한다. m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x001F1F1F ); //바라보는 위치를 좀더 뒤로 하고 위쪽에서 바라보도록 한다. D3DXVECTOR3 vFromPt = D3DXVECTOR3( 0.0f, 10.0f, -20.0f );
Direct X Demo 따라하기 온라인상 움직임의 동기화를 위하여 FrameMove를 사용하지 않겠다. 렌더링하기 프로젝트이름.cpp 의 FrameMove()의 내용을 return S_OK; 를 제외하고 모두 제거한다. 렌더링하기 프로젝트이름.cpp의 Render()의 내용을 다음의 코드와 교체한다. 코드
// Clear the viewport m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0x000000ff, 1.0f, 0L ); //공간의 메테리얼 설정 D3DMATERIAL9 mtrl; D3DUtil_InitMaterial( mtrl, 0.9f, 0.9f, 0.9f ); m_pd3dDevice->SetMaterial( &mtrl ); if( SUCCEEDED( m_pd3dDevice->BeginScene() ) ) { //공간 렌더링을 위하여 월드 메트릭스 원점으로 이동 D3DXMATRIX matWorld; D3DXMATRIX matRotX; D3DXMATRIX matRotY; D3DXMatrixRotationX( &matRotX, m_fWorldRotX ); D3DXMatrixRotationY( &matRotY, m_fWorldRotY ); D3DXMatrixMultiply( &matWorld, &matRotX, &matRotY); m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); m_pd3dDevice->SetTexture( 0, g_pTexture1 ); // Render the vertex buffer contents m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(CUSTOMVERTEX) ); m_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 8 ); RenderText(); // End the scene. m_pd3dDevice->EndScene(); } return S_OK;
Direct X Demo 따라하기 자원을 해제한다.. 이상으로 배경을 모두 만들었다. 사용자를 만들어보도록 하겠다. 프로젝트이름.cpp의 DeleteDeviceObjects()함수안의 내용에 다음과 같이 추가한다 코드 if( g_pTexture1 != NULL ) g_pTexture1->Release(); 이상으로 배경을 모두 만들었다. 사용자를 만들어보도록 하겠다.
Direct X Demo 따라하기 새로운 클래스를 생성한다. VC++ 메뉴에 Project -> Add to Project -> New 선택 C++ Header 선택 화일이름 = XUser로 하여 파일을 만든다 같은 방법으로 C++ Source File 화일이름 = XUser로 하여 파일을 만든다.
Direct X Demo 따라하기 XUser.h에 다음과 같이 추가한다. 코드 (자세한 내용은 주석을 참조) #include <d3dx9.h> //삼각형의 법선벡터 추출.. void Get_Normal(const D3DXVECTOR3 *p1 ,const D3DXVECTOR3 *p2 ,const D3DXVECTOR3 *p3 , D3DXVECTOR3 *normal); typedef struct _tagMapVertex { D3DXVECTOR3 p; D3DXVECTOR3 n; float tu,tv; }UCUSTOMVERTEX; //커스텀 버텍스 유형 설정 #define D3DFVF_UCUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1) //오브젝트 내용 위치 회전값 칼라 물체 위치 저장.. struct UserStatus D3DXVECTOR3 vLoc; D3DXVECTOR3 vR; FLOAT fR,fG,fB; D3DMATRIX matLocal; };
class XUser { private: //디바이스 포인터를 넘겨받아 저장 LPDIRECT3DDEVICE9 m_pd3dDevice; //사용자 정점버퍼 LPDIRECT3DVERTEXBUFFER9 m_pUserVB; //사용자 인덱스 버퍼 LPDIRECT3DINDEXBUFFER9 m_pUserIB; //상태 저장 구조체 사용 UserStatus userstatus; //사용자 이름 삽입. char name[256]; public: XUser(); ~XUser(); //공동 프레임워크. HRESULT InitDeviceObjects(LPDIRECT3DDEVICE9 pDevice); HRESULT DeleteDeviceObjects(); HRESULT RestoreDeviceObjects(); HRESULT Render(); //사용자의 움직임에 따른 회전량 계산을 위함 HRESULT UserRotate(float Rot); //사용자 움직임에 따른 좌표 변환을 위함. HRESULT set_Move(float x, float y, float z); //사용자의 이름을 저장하기 위함 HRESULT set_Name(char* name); //사용자의 이름을 얻어오기 위함 char* get_Name(); //디바이스를 수동으로 연결하기 위함 사용하지 않음 HRESULT setDevice(LPDIRECT3DDEVICE9 pDevice); //사용자의 색을 선택하기 위함 HRESULT setColor(float r, float g, float b); //사용자의 움직임을 절대적으로 이동 HRESULT set_InitMove(float x, float y, float z); //사용자의 움직인 좌표를 얻어 옴.. float get_x(); float get_y(); float get_z(); };
Direct X Demo 따라하기 XUser.cpp에 다음과 같이 추가한다. 생성자 / 소멸자 코드 (자세한 내용은 주석을 참조) #include "XUser.h" #include <dxerr9.h> #include "dxutil.h" #include "D3DUtil.h" //생성자 XUser::XUser() { userstatus.vLoc = D3DXVECTOR3(0.0f, 0.0f, 0.0f); userstatus.vR.x = 0.0f; userstatus.vR.y = 0.0f; userstatus.vR.z = 0.0f; //색 선정. userstatus.fR = 1.0f; userstatus.fG = 0.92f; userstatus.fB = 0.0f; //사용자의 위치(정가운데) 를 설정. D3DXMATRIX matWorld; D3DXMatrixTranslation(&matWorld, 0.0f, 0.0f, 0.0f); userstatus.matLocal = matWorld; } XUser::~XUser()
Direct X Demo 따라하기 XUser.cpp에 다음과 같이 추가한다. 코드 (자세한 내용은 주석을 참조) HRESULT XUser::setDevice(LPDIRECT3DDEVICE9 pDevice) { //디바이스를 전달받음 this->m_pd3dDevice = pDevice; return 1; } HRESULT XUser::InitDeviceObjects(LPDIRECT3DDEVICE9 pDevice) //사용자의 3차원 객체를 세팅 //버텍스를 통하여 점을 찍고 인덱스 버퍼를 통하여 그림 m_pUserVB = NULL; m_pUserIB = NULL; //디바이스 포인터를 저장. HRESULT hr; //버텍스 생성 6개의 점을 생성 if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( 6*sizeof(UCUSTOMVERTEX), 0, D3DFVF_UCUSTOMVERTEX, D3DPOOL_MANAGED, &m_pUserVB, NULL ) ) ) return DXTRACE_ERR( "CreateVertexBuffer", hr );
UCUSTOMVERTEX* pVertices; D3DXVECTOR3 normal; if( FAILED( hr = m_pUserVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) ) return DXTRACE_ERR( "VertexLock", hr ); //todo : 여따가 그림 그리기.. pVertices[0].p = D3DXVECTOR3(0.0f, 2.0f, 0.0f); pVertices[0].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[0].tu = 0; pVertices[0].tv = 0; pVertices[1].p = D3DXVECTOR3(0.0f, -2.0f, 0.0f); pVertices[1].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[1].tu = 0; pVertices[1].tv = 0; pVertices[2].p = D3DXVECTOR3(-1.0f, 0.0f, 0.0f); pVertices[2].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[2].tu = 0; pVertices[2].tv = 0; pVertices[3].p = D3DXVECTOR3(1.0f, 0.0f, 0.0f); pVertices[3].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[3].tu = 0; pVertices[3].tv = 0; pVertices[4].p = D3DXVECTOR3(0.0f, 0.0f, -1.0f); pVertices[4].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[4].tu = 0; pVertices[4].tv = 0; pVertices[5].p = D3DXVECTOR3(0.0f, 0.0f, 1.0f); pVertices[5].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[5].tu = 0; pVertices[5].tv = 0;
//삼각형의 노벌값을 계산하여 삽입. Get_Normal(&pVertices[0].p, &pVertices[3].p, &pVertices[4].p, &normal); pVertices[0].n += normal; pVertices[3].n += normal; pVertices[4].n += normal; Get_Normal(&pVertices[0].p, &pVertices[5].p, &pVertices[3].p, &normal); pVertices[5].n += normal; Get_Normal(&pVertices[0].p, &pVertices[2].p, &pVertices[5].p, &normal); pVertices[2].n += normal; Get_Normal(&pVertices[0].p, &pVertices[4].p, &pVertices[2].p, &normal); Get_Normal(&pVertices[1].p, &pVertices[4].p, &pVertices[3].p, &normal); pVertices[1].n += normal; Get_Normal(&pVertices[1].p, &pVertices[3].p, &pVertices[5].p, &normal); Get_Normal(&pVertices[1].p, &pVertices[5].p, &pVertices[2].p, &normal); Get_Normal(&pVertices[1].p, &pVertices[2].p, &pVertices[4].p, &normal); m_pUserVB->Unlock();
//인덱스를 삽입 //인덱스는 인덱스 순서대로 버텍스를 삽입한것과 같다. WORD Userindex[24] = {0}; Userindex[0] = 0; Userindex[1] = 3; Userindex[2] = 4; Userindex[3] = 0; Userindex[4] = 5; Userindex[5] = 3; Userindex[6] = 0; Userindex[7] = 2; Userindex[8] = 5; Userindex[9] = 0; Userindex[10] = 4; Userindex[11] = 2; Userindex[12] = 1; Userindex[13] = 4; Userindex[14] = 3; Userindex[15] = 1; Userindex[16] = 3; Userindex[17] = 5; Userindex[18] = 1; Userindex[19] = 5; Userindex[20] = 2; Userindex[21] = 1; Userindex[22] = 2; Userindex[23] = 4; DWORD pSizeUserIndex = sizeof(Userindex); if( FAILED(hr = m_pd3dDevice->CreateIndexBuffer(pSizeUserIndex, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_pUserIB, NULL))) return DXTRACE_ERR( "CreateIndexBuffer", hr ); WORD* pIndices; if (FAILED( m_pUserIB->Lock(0, pSizeUserIndex, (VOID**)&pIndices, 0))) return DXTRACE_ERR( "IndexLock", hr ); memcpy(pIndices, Userindex, pSizeUserIndex); m_pUserIB->Unlock(); return 1; }
Direct X Demo 따라하기 XUser.cpp에 다음과 같이 추가한다. 코드 (자세한 내용은 주석을 참조) HRESULT XUser::DeleteDeviceObjects() { //버텍스와 인덱스의 자원을 해제한다. SAFE_RELEASE(m_pUserVB); SAFE_RELEASE(m_pUserIB); return 1; } HRESULT XUser::RestoreDeviceObjects() HRESULT XUser::Render() //자신의 메테리얼로 설정후 좌표이동 및 렌더링 D3DMATERIAL9 mtrl; D3DUtil_InitMaterial( mtrl, userstatus.fR, userstatus.fG, userstatus.fB ); m_pd3dDevice->SetMaterial( &mtrl ); //현재 유저의 위치로 변경. m_pd3dDevice->SetTransform(D3DTS_WORLD, &userstatus.matLocal); //그림. m_pd3dDevice->SetStreamSource( 0, m_pUserVB, 0, sizeof(UCUSTOMVERTEX) ); m_pd3dDevice->SetFVF(D3DFVF_UCUSTOMVERTEX); m_pd3dDevice->SetIndices(m_pUserIB); m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 6, 0, 24/3);
Direct X Demo 따라하기 XUser.cpp에 다음과 같이 추가한다. //사용자 움직임에 따라 화전 코드 (자세한 내용은 주석을 참조) //사용자 움직임에 따라 화전 HRESULT XUser::UserRotate(float Rot) { userstatus.vR.x += Rot*0.5; D3DXMATRIX matTemp; D3DXMATRIX matWorld = userstatus.matLocal; D3DXMatrixRotationY(&matTemp, userstatus.vR.x); D3DXMatrixMultiply(&matWorld,&matTemp,&matWorld); userstatus.matLocal=matWorld; return 1; } //사용자의 움직임 HRESULT XUser::set_Move(float x, float y, float z) userstatus.vLoc.x += x*0.5; userstatus.vLoc.y += y*0.5; userstatus.vLoc.z += z*0.5; D3DXMATRIX matWorld; D3DXMatrixTranslation(&matWorld, userstatus.vLoc.x, userstatus.vLoc.y, userstatus.vLoc.z); userstatus.matLocal = matWorld;
return 1; } //사용자의 이름 세팅 HRESULT XUser::set_Name(char* name) { strcpy(this->name, name); return S_OK; //사용자의 이름 얻기 char* XUser::get_Name() return name; //색갈 세팅 HRESULT XUser::setColor(float r, float g, float b) userstatus.fR = r; userstatus.fG = g; userstatus.fB = b; //초기값으로 받은 경우 월드 메트릭스 계산 HRESULT XUser::set_InitMove(float x, float y, float z) userstatus.vLoc.x = x; userstatus.vLoc.y = y; userstatus.vLoc.z = z; D3DXMATRIX matWorld; D3DXMatrixTranslation(&matWorld, userstatus.vLoc.x, userstatus.vLoc.y, userstatus.vLoc.z); userstatus.matLocal = matWorld;
//위치 X좌표 float XUser::get_x() { return userstatus.vLoc.x; } //위치 Y좌표 float XUser::get_y() return userstatus.vLoc.y; //위치 Z좌표 float XUser::get_z() return userstatus.vLoc.z; //법선벡터값 계산을 위한 함수 void Get_Normal(const D3DXVECTOR3 *p1 ,const D3DXVECTOR3 *p2 ,const D3DXVECTOR3 *p3 , D3DXVECTOR3 *normal) D3DXVECTOR3 temp1, temp2; temp1.x = p1->x - p2->x; temp1.y = p1->y - p2->y; temp1.z = p1->z - p2->z; temp2.x = p2->x - p3->x; temp2.y = p2->y - p3->y; temp2.z = p2->z - p3->z; D3DXVec3Cross(normal , &temp1, &temp2); D3DXVec3Normalize(normal,normal);
Direct X Demo 따라하기 새로운 클래스를 생성한다. 이상으로 사용자를 만들었으며 여러 사용자를 위하여 사용자 매니저를 만들도록 하겠다. 새로운 클래스를 생성한다. VC++ 메뉴에 Project -> Add to Project -> New 선택 C++ Header 선택 화일이름 = ListManager로 하여 파일을 만든다 같은방법으로 C++ Sourse File 화일이름 = ListManager로 하여 파일을 만든다.
Direct X Demo 따라하기 ListManager.h에 다음과 같이 추가한다. 코드 (자세한 내용은 주석참조) #include "XUser.h" //자신포함 최대 8명이 접속할수 있으며 자신을 제외하고 7명을 관리하게 된다. #define MAXUSER 7 class ListManager { private: XUser userlist[MAXUSER]; int usercount[MAXUSER]; public: ListManager(); ~ListManager(); HRESULT userAdd(char *name); HRESULT userRemove(char *name); HRESULT allRander(); HRESULT initListmanager(LPDIRECT3DDEVICE9 pDevice); HRESULT DeleteDeviceObjects(); HRESULT userMove(char *act, char *name); HRESULT setInitMove(float x, float y, float z, char *name); };
Direct X Demo 따라하기 ListManager.cpp에 다음과 같이 추가한다. 코드 (자세한 내용은 주석참조) #include "ListManager.h" ListManager::ListManager() { } ListManager::~ListManager() //생성시 3개의 사용자 3차원 객체 초기화 HRESULT ListManager::initListmanager(LPDIRECT3DDEVICE9 pDevice) int a=0; for (a=0 ; a<MAXUSER ; a++) userlist[a].InitDeviceObjects(pDevice); userlist[a].set_Name(""); //사용자마다 다른 색을 선정. userlist[0].setColor(1.0f, 0.0f, 0.0f); userlist[1].setColor(0.0f, 1.0f, 0.0f); userlist[2].setColor(0.0f, 0.0f, 1.0f); userlist[3].setColor(0.5f, 1.0f, 0.0f); userlist[4].setColor(0.0f, 0.5f, 1.0f); userlist[5].setColor(1.0f, 0.0f, 0.5f); userlist[6].setColor(0.5f, 0.1f, 0.5f); return 1;
//사용자 추가 아이디가 "" 공백을 통하여 사용자 검색 //공백은 사용자가 없는것으로 인식. HRESULT ListManager::userAdd(char *name) { int a=0; for (a=0 ; a<MAXUSER ; a++) if (strcmp(userlist[a].get_Name(), "") == 0) userlist[a].set_Name(name); break; } return 0; //사용자 제거 HRESULT ListManager::userRemove(char *name) if ( strcmp(userlist[a].get_Name(), name) == 0) userlist[a].set_Name(""); return 1; //모든 3차원 객체 렌더링 //접속죽인 사용자만 렌더링. HRESULT ListManager::allRander() if ( strcmp(userlist[a].get_Name(), "") != 0) userlist[a].Render(); //소멸시 모든 3차원 객체 해제 HRESULT ListManager::DeleteDeviceObjects() userlist[a].DeleteDeviceObjects(); //사용자 움직임 에 따른 검색및 이동 HRESULT ListManager::userMove(char *name, char *act) if (strcmp(name,userlist[a].get_Name())==0) if (strcmp(act, "UP")==0) userlist[a].set_Move(0.0f, 0.0f, 1.0f); userlist[a].UserRotate(-1.0f); else if (strcmp(act, "DOWN")==0) userlist[a].set_Move(0.0f, 0.0f, -1.0f); userlist[a].UserRotate(1.0f); else if (strcmp(act, "LEFT")==0) userlist[a].set_Move(-1.0f, 0.0f, 0.0f); else if (strcmp(act, "RIGHT")==0) userlist[a].set_Move(1.0f, 0.0f, 0.0f); //초기값 설정을 위한 벡터값 세팅 HRESULT ListManager::setInitMove(float x, float y, float z, char *name) userlist[a].set_InitMove(x, y, z);
Direct X Demo 따라하기 이상으로 사용자 매니저를 만들었으며 메뉴에 호스트 및 접속 메뉴를 추가하고 접속을 위한 다이얼로그를 생성한다. Resource view창을 통하여 메뉴에 Host 와 connect를 추가하고 각각의 ID를 INET_HOST와 INET_CONNECT 라고 적어준다. 두개의 다이얼로그를 생성한다. Host다이얼로그 -> 에디트 상자를 삽입하여 ID를 IDC_CHATID라고 적어준다. 또 다이얼로그의 Properties 선택하여 IDD_HOST로 이름 붙인다. Connect다이얼로그 -> 에디트 상자 2개를 삽입하여 다음과 같이 ID를 IDC_IPADDR, IDC_CHATID와 INET_CONNECT로 적어준다. 또 다이얼로그의 Properties 선택하여 IDD_CONNECT로 이름 붙인다.
Direct X Demo 따라하기 채팅을 위하여 채팅창을 만든다. 새로운 클래스를 생성한다. VC++ 메뉴에 Project -> Add to Project -> New 선택 C++ Header 선택 화일이름 = Chating로 하여 파일을 만든다 같은방법으로 C++ Sourse File 화일이름 = Chating로 하여 파일을 만든다.
Direct X Demo 따라하기 Chating.h에 다음과 같이 추가한다. 코드 (자세한 내용은 주석 참조) #include <windows.h> #define ID_EDIT 100 #define ID_LISTBOX 101 //채팅내용을 보내는 메시지 선언 #define WM_UCHATSEND WM_USER+6 class Chating { private: char str[256]; public: Chating(); ~Chating(); HRESULT chat_SetText(char *p); HRESULT init_Chating(HWND hWnd, HINSTANCE g_hInst); HRESULT set_Focus(); };
Direct X Demo 따라하기 Chating.cpp에 다음과 같이 추가한다. #include "Chating.h" 코드 (자세한 내용은 주석 참조) #include "Chating.h" //메시지 가로채기 복구를 위한 프로시져 WNDPROC OldEditProc; //리스트와 에디트 헨들 HWND hlist; HWND hEdit_input; //에디트의 메시지 가로채기 LRESULT CALLBACK EditSubProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { char str[256]; switch (iMessage) case WM_KEYDOWN: if (wParam==VK_RETURN) //에디트 포커스 상태에서 엔터 입력시 WM_UCHATSEND 이벤트 발생 후 포커스 부모에게 넘김 GetWindowText(hWnd, str, 256); SetWindowText(hWnd, ""); if (strlen(str) != 0) SendMessage(GetParent(hWnd), WM_UCHATSEND, 0, (LPARAM)str); } SetFocus(GetParent(hWnd));
} return CallWindowProc(OldEditProc, hWnd, iMessage, wParam, lParam); Chating::Chating() { //소멸시 가로챈 메시지 복구 Chating::~Chating() SetWindowLong(hEdit_input, GWL_WNDPROC, (LONG)OldEditProc); //생성시 리스트와 에디트 생성 HRESULT Chating::init_Chating(HWND hWnd, HINSTANCE g_hInst) hEdit_input=CreateWindow("edit", "대화내용 입력", WS_CHILD | WS_VISIBLE | WS_CAPTION, 0, 200, 300, 50, hWnd, (HMENU)ID_EDIT, g_hInst, NULL); OldEditProc = (WNDPROC)SetWindowLong(hEdit_input, GWL_WNDPROC, (LONG)EditSubProc); hlist=CreateWindow("listBox", "채팅 창", WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_CAPTION, 0, 0, 300, 200, hWnd, (HMENU)ID_EDIT, g_hInst, NULL); return 1; //리스트에 내용 삽입 HRESULT Chating::chat_SetText(char *p) int a; a = SendMessage(hlist, LB_ADDSTRING, 0, (LPARAM)p); SendMessage(hlist, LB_SETCURSEL, (WPARAM)a, (LPARAM)a); HRESULT Chating::set_Focus() SetFocus(hEdit_input); return 0;
Direct X Demo 따라하기 이상으로 채팅관련 클래스를 만들었으며 따로 만들어 놓은 사운드와 플레이 클래스를 로드 한다. 새로운 클래스를 생성한다. VC++ 메뉴에 Project -> Add to Project -> File 선택 dsdemo.cpp, dsdemo.h dsutil.cpp, dsutil.h DPSocket.cpp. DPSockt.h 를 로드 한다.
Direct X Demo 따라하기 DPSocket은 메시지(채팅, 움직임)처리를 위하여 수정하였으므로 다음의 코드를 덮는다. 코드 (DPSocket.h) /******************************************************************** created:2003/05/10 created:10:5:2003 0:55 filename: M:\MYSTUDY\DIRECTPLAY\DPSOCKET\DPSocket.h file path:M:\MYSTUDY\DIRECTPLAY\DPSOCKET file base:DPSocket file ext:h author:JAXAL purpose:DirectPlay를 캡슐화한 클래스 *********************************************************************/ #ifndef _DPSOCKET_H #define _DPSOCKET_H #include<windows.h> #include<dplay8.h> #include"dxutil.h" //각각의 메시지에 해당하는 메시지를 정의한다. #define WM_UCHAT WM_USER+1 #define WM_UMOVE WM_USER+2 #define WM_UCONNECT WM_USER+3 #define WM_UDISCON WM_USER+4 #define WM_USTARTM WM_USER+5 // {DA342589-D8A5-46af-866E-5D1C8F1375AF} static const GUID DP_SOCKET = { 0xda342589, 0xd8a5, 0x46af, { 0x86, 0x6e, 0x5d, 0x1c, 0x8f, 0x13, 0x75, 0xaf } };
#define MAX_PLAYERS 8 #define CHAT_MESSAGE 1000 #define MOVE_MESSAGE 1001 #define START_MESSAGE 1002 struct PACKET_OBJECT { UINTprotocol; charszMsg[256]; charszName[32]; }; class CDPSocket protected: CDPSocket(); static CDPSocket* pDPSocket; public: virtual ~CDPSocket(); static CDPSocket* getInstance() if(pDPSocket == NULL) return new CDPSocket(); return pDPSocket; } private: DPNHANDLEm_hConnectAsyncOp; HWNDm_hWnd; charm_szPeerName[256]; void SetHWnd(HWND hWnd);
HRESULT InitializeDirectPlay(); void SetMessageHandler(const PFNDPNMESSAGEHANDLER pfn); virtual HRESULT Host(char* strPeerName, DWORD dwPort); virtual HRESULT Connect(char* strIP, DWORD dwPort, char* strPeerName); virtual HRESULT SendMessage(UINT nProtocol, int player, char* message); private: static HRESULT WINAPI DirectPlayMessageHandler(PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer); static HRESULT CreatePlayer(PVOID pvUserContenxt, PVOID pMsgBuffer); static HRESULT DestoryPlayer(PVOID pvUserContext, PVOID pMsgBuffer); }; #endif
Direct X Demo 따라하기 DPSocket은 메시지(채팅, 움직임)처리를 위하여 수정하였음으로 다음의 코드를 덮는다. 코드 (DPSocket.cpp) /******************************************************************** created:2003/05/10 created:10:5:2003 1:14 filename: M:\MYSTUDY\DIRECTPLAY\DPSOCKET\DPSocket.cpp file path:M:\MYSTUDY\DIRECTPLAY\DPSOCKET file base:DPSocket file ext:cpp author:JAXAL purpose:DPSocket 구현 *********************************************************************/ //#include"stdafx.h" #include<stdio.h> #include"DPSocket.h" IDirectPlay8Peer*g_pDP; IDirectPlay8Address*g_pDeviceAddress; IDirectPlay8Address*g_pHostAddress; DPNIDg_dpnidLocalPlayer = 0; boolbHost = 0; struct PLAYER_INFORMATION { boolbActive; DPNIDdpnidPlayer; charszPlayerName[32]; };
struct PLAYER_INFORMATIONPlayerInfo[MAX_PLAYERS]; CDPSocket* CDPSocket::pDPSocket = new CDPSocket(); CDPSocket::CDPSocket() { g_pDP = NULL; g_pDeviceAddress = NULL; g_pHostAddress = NULL; } CDPSocket::~CDPSocket() if(g_pHostAddress) g_pHostAddress->Release(); if(g_pDeviceAddress) g_pDeviceAddress->Release(); if(g_pDP) g_pDP->Release(); void CDPSocket::SetHWnd(HWND hWnd) m_hWnd = hWnd; HRESULT CDPSocket::InitializeDirectPlay() HRESULT ret; ret = CoInitialize(NULL); if(FAILED(ret)) MessageBox(m_hWnd, "Error Initializing COM", "DirectPlayError", MB_ICONERROR); return ret;
ret = CoCreateInstance(CLSID_DirectPlay8Peer, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Peer, (LPVOID*)&g_pDP); if(FAILED(ret)) { MessageBox(m_hWnd, "Error Can't Create DirectPlay8Peer", "DirectPlayError", MB_ICONERROR); return ret; } ret = CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*)&g_pDeviceAddress); MessageBox(m_hWnd, "Error Can't Create DeviceAddress", "DirectPlayError", MB_ICONERROR); ret = g_pDP->Initialize(NULL, DirectPlayMessageHandler, 0); MessageBox(m_hWnd, "Error Initialize MessageHandler", "DirectPlayError", MB_ICONERROR); ret = g_pDeviceAddress->SetSP(&CLSID_DP8SP_TCPIP); MessageBox(m_hWnd, "Error Device Service Provider", "DirectPlayError", MB_ICONERROR); ret = CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*)&g_pHostAddress);
ret = g_pHostAddress->SetSP(&CLSID_DP8SP_TCPIP); if(FAILED(ret)) { MessageBox(m_hWnd, "Error Host Service Provider", "DirectPlayError", MB_ICONERROR); return ret; } return S_OK; HRESULT CDPSocket::Host(char* strPeerName, DWORD dwPort) charstrSessionName[256]; WCHARwszPeerName[256]; WCHARwszSessionName[256]; DPN_APPLICATION_DESCdnAppDesc; DPN_PLAYER_INFOdpPlayerInfo; HRESULTret; strcpy(m_szPeerName, strPeerName); DXUtil_ConvertGenericStringToWideCch(wszPeerName, strPeerName, 256); ZeroMemory(&dpPlayerInfo, sizeof(DPN_PLAYER_INFO)); dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO); dpPlayerInfo.dwInfoFlags = DPNINFO_NAME; dpPlayerInfo.pwszName = wszPeerName; ret = g_pDP->SetPeerInfo(&dpPlayerInfo, NULL, NULL, DPNSETPEERINFO_SYNC); MessageBox(m_hWnd, "Error SetPeerInfo", "DirectPlayError", MB_ICONERROR); sprintf(strSessionName, "%s's room", strPeerName); DXUtil_ConvertGenericStringToWideCch(wszSessionName, strSessionName, 256); ZeroMemory(&dnAppDesc, sizeof(DPN_APPLICATION_DESC)); dnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC); dnAppDesc.guidApplication = DP_SOCKET; dnAppDesc.pwszSessionName = wszSessionName; dnAppDesc.dwMaxPlayers = MAX_PLAYERS; dnAppDesc.dwFlags = DPNSESSION_MIGRATE_HOST;
ret = g_pDeviceAddress->AddComponent(DPNA_KEY_PORT, &dwPort, sizeof(DWORD), DPNA_DATATYPE_DWORD); if(FAILED(ret)) { MessageBox(m_hWnd, "Error DeviceAddress AddComponent", "DirectPlayError", MB_ICONERROR); return ret; } ret = g_pDP->Host(&dnAppDesc, &g_pDeviceAddress, 1, NULL, NULL, NULL, NULL); MessageBox(m_hWnd, "Error Can't Host", "DirectPlayError", MB_ICONERROR); bHost = 1; return S_OK; HRESULT CDPSocket::Connect(char* strIP, DWORD dwPort, char* strPeerName) HRESULTret = S_OK; WCHARwszHostName[256]; WCHARwszPeerName[256]; DPN_APPLICATION_DESCdpnAppDesc; DPN_PLAYER_INFOdpPlayerInfo; strcpy(m_szPeerName, strPeerName); DXUtil_ConvertGenericStringToWideCch(wszPeerName, strPeerName, 256); ZeroMemory(&dpPlayerInfo, sizeof(DPN_PLAYER_INFO)); dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO); dpPlayerInfo.dwInfoFlags = DPNINFO_NAME; dpPlayerInfo.pwszName = wszPeerName; ret = g_pDP->SetPeerInfo(&dpPlayerInfo, NULL, NULL, DPNSETPEERINFO_SYNC); MessageBox(m_hWnd, "Error fail SetPeerInfo", "DirectPlayError", MB_ICONERROR); return -1;
ZeroMemory(&dpnAppDesc, sizeof(DPN_APPLICATION_DESC)); dpnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC); dpnAppDesc.guidApplication = DP_SOCKET; DXUtil_ConvertGenericStringToWideCch(wszHostName, strIP, 256); ret = g_pHostAddress->AddComponent(DPNA_KEY_HOSTNAME, wszHostName, (wcslen(wszHostName)+1)*sizeof(WCHAR), DPNA_DATATYPE_STRING); if(FAILED(ret)) { MessageBox(m_hWnd, "Error fail Host Address AddComponent", "DirectPlayError", MB_ICONERROR); return -1; } ret = g_pHostAddress->AddComponent(DPNA_KEY_PORT, &dwPort, sizeof(DWORD), DPNA_DATATYPE_DWORD); MessageBox(m_hWnd, "Error fail Host Port AddComponent", "DirectPlayError", MB_ICONERROR); ret = g_pDP->Connect(&dpnAppDesc, g_pHostAddress, g_pDeviceAddress, NULL, NULL, NULL, 0, NULL, NULL, &m_hConnectAsyncOp, NULL); if(ret != E_PENDING && FAILED(ret)) MessageBox(m_hWnd, "Error fail Connect", "DirectPlayError", MB_ICONERROR); return ret; HRESULT CDPSocket::SendMessage(UINT nProtocol, int player, char* message) PACKET_OBJECTpacket; DPNHANDLEhAsync; DWORDdwLength = strlen(message); DPN_BUFFER_DESCbufferDesc; if(dwLength == 0) return S_OK;
packet.protocol = nProtocol; strcpy(packet.szMsg, message); strcpy(packet.szName, m_szPeerName); bufferDesc.dwBufferSize = sizeof(PACKET_OBJECT); bufferDesc.pBufferData = (BYTE*)&packet; if(player == -1) g_pDP->SendTo(DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1, 0, NULL, &hAsync, 0); else g_pDP->SendTo(PlayerInfo[player].dpnidPlayer, &bufferDesc, 1, 0, NULL, &hAsync, 0); return S_OK; } HRESULT WINAPI CDPSocket::DirectPlayMessageHandler(PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer) { HRESULTret = S_OK; PACKET_OBJECT*receive; intprotocol = 0; charstrMessage[256]; charstrName[256]; switch(dwMessageId) case DPN_MSGID_CREATE_PLAYER: CDPSocket::CreatePlayer(pvUserContext, pMsgBuffer); //MessageBox(pDPSocket->m_hWnd, "CreatePlayer!!!", "음..", MB_OK); break; case DPN_MSGID_DESTROY_PLAYER: CDPSocket::DestoryPlayer(pvUserContext, pMsgBuffer); case DPN_MSGID_HOST_MIGRATE: PDPNMSG_HOST_MIGRATE pHostMigrateMsg; pHostMigrateMsg = (PDPNMSG_HOST_MIGRATE)pMsgBuffer;
if(pHostMigrateMsg->dpnidNewHost == g_dpnidLocalPlayer) { MessageBox(pDPSocket->m_hWnd, "You are the Host!!", "DirectPlay", MB_OK); } break; case DPN_MSGID_TERMINATE_SESSION: MessageBox(pDPSocket->m_hWnd, "Terminating Session!!!", "DirectPlay", MB_OK); PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg; pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer; case DPN_MSGID_RECEIVE: PDPNMSG_RECEIVE pReceiveMsg; pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer; receive = (struct PACKET_OBJECT*)pReceiveMsg->pReceiveData; protocol = receive->protocol; strcpy(strMessage, receive->szMsg); strcpy(strName, receive->szName); //MessageBox(pDPSocket->m_hWnd, strMessage, strName, MB_OK); if (protocol == CHAT_MESSAGE) ::SendMessage(pDPSocket->m_hWnd, WM_UCHAT, (WPARAM)strMessage, (LPARAM)strName); else if (protocol == MOVE_MESSAGE) ::SendMessage(pDPSocket->m_hWnd, WM_UMOVE, (WPARAM)strMessage, (LPARAM)strName); else if (protocol == START_MESSAGE) ::SendMessage(pDPSocket->m_hWnd, WM_USTARTM, (WPARAM)strMessage, (LPARAM)strName);
case DPN_MSGID_CONNECT_COMPLETE: PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg; pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer; break; } return ret; HRESULT CDPSocket::CreatePlayer(PVOID pvUserContenxt, PVOID pMsgBuffer) { HRESULTret = S_OK; PDPNMSG_CREATE_PLAYERpCreatePlayerMsg; charstrName[256]; DWORDdwSize = 0; DPN_PLAYER_INFO*pdpPlayerInfo = NULL; inti; pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer; ret = g_pDP->GetPeerInfo(pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0); if(FAILED(ret) && ret != DPNERR_BUFFERTOOSMALL) ret = -1; else pdpPlayerInfo = (DPN_PLAYER_INFO*)new BYTE[dwSize]; ZeroMemory(pdpPlayerInfo, dwSize); pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO); if(FAILED(ret)) DXUtil_ConvertWideStringToGenericCch(strName, pdpPlayerInfo->pwszName, 256);
for(i = 0 ; i < MAX_PLAYERS ; i++) { if(!PlayerInfo[i].bActive) PlayerInfo[i].bActive = 1; PlayerInfo[i].dpnidPlayer = pCreatePlayerMsg->dpnidPlayer; strcpy(PlayerInfo[i].szPlayerName, strName); ::SendMessage(pDPSocket->m_hWnd, WM_UCONNECT, (WPARAM)0, (LPARAM)strName); //MessageBox(pDPSocket->m_hWnd, strName, " ", MB_OK); break; } if(i == MAX_PLAYERS) MessageBox(pDPSocket->m_hWnd, "No free slots!!", "DirectPlay", MB_OK); else if(pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL) g_dpnidLocalPlayer = pCreatePlayerMsg->dpnidPlayer; char temp[24]; sprintf(temp, "<Slot%d> Added Ourselves", i); MessageBox(pDPSocket->m_hWnd, temp, "DirectPlay", MB_OK); else sprintf(temp, "<Slot%d><%s> Is In the room", i, strName); if(bHost) sprintf(temp, "Welcome to the room, %s!", strName); pDPSocket->SendMessage(CHAT_MESSAGE, i, temp); delete pdpPlayerInfo;
return ret; } HRESULT CDPSocket::DestoryPlayer(PVOID pvUserContext, PVOID pMsgBuffer) { PDPNMSG_DESTROY_PLAYERpDestroyPlayerMsg; HRESULTret = S_OK; pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer; if(pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_NORMAL) //그냥 나갔다 else if(pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_CONNECTIONLOST) //연결이 끊겼다 else if(pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_SESSIONTERMINATED) //세션이 끝나다 else if(pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER) //짤렸다 DPN_PLAYER_INFO*pdpPlayerInfo = NULL; DWORDdwSize = 0; PDPNMSG_CREATE_PLAYERpCreatePlayerMsg; charstrName[256]; pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer; g_pDP->GetPeerInfo(pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0); pdpPlayerInfo = (DPN_PLAYER_INFO*)new BYTE[dwSize]; ZeroMemory(pdpPlayerInfo, dwSize); pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO); DXUtil_ConvertWideStringToGenericCch(strName, pdpPlayerInfo->pwszName, 256);
return ret; ::SendMessage(pDPSocket->m_hWnd, WM_UDISCON, (WPARAM)0, (LPARAM)strName); delete pdpPlayerInfo; //::SendMessage(pDPSocket->m_hWnd, WM_UDISCON, (WPARAM)0, (LPARAM)strName); for(int i = 0 ; i < MAX_PLAYERS ; i++) { if(PlayerInfo[i].bActive) if(PlayerInfo[i].dpnidPlayer == pDestroyPlayerMsg->dpnidPlayer) PlayerInfo[i].bActive = 0; //나갔다는 메시지 뿌리고 break; } return ret;
Direct X Demo 따라하기 모든 클래스가 준비 되었으니 프로젝트이름.h 와 프로젝트이름.cpp를 수정하도록 하겠다. #include"Chating.h" #include"dsdemo.h" #include"dpsocket.h" #include"ListManager.h" CMyD3DApplication클래스의 멤버변수로 다음과 같이 추가한다. XUser user1; Chating chat; DSDemo Multi_Sound; ListManager user_lManager; CDPSocket *pDPSocket;
Direct X Demo 따라하기 프로젝트이름.cpp에 다음과 같이 수정한다. CMyD3DApplication()안에 다음을 추가한다. pDPSocket = NULL; InitDeviceObjects()안(return()직전)에 다음을 추가한다. //자신과 접속자 모두의 3차원 객체 생성 user1.InitDeviceObjects(m_pd3dDevice); user_lManager.initListmanager(m_pd3dDevice); Render()안(EndScene()전)에 다음을 추가한다. //자신과 모든 사용자 렌더링 user1.Render(); user_lManager.allRander(); DeleteDeviceObjects()에 다음을 추가한다. user1.DeleteDeviceObjects(); user_lManager.DeleteDeviceObjects();
Direct X Demo 따라하기 다음으로 다이얼로그(Host, Connect)다이얼로그 처리를 위한 프로시저를 MsgProc() 직전에 삽입한다 다음의 코드를 프로젝트이름.cpp에 삽입한다. //다이얼로그 박스에 의한 전달값 char d_str1[128]; // Connect시 아이피값 char d_str2[128]; // Connect시 아이디값 char d_str3[128]; // Host시 아이디값 BOOL CALLBACK ConnectDlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam) { switch(iMessage) case WM_COMMAND: switch(wParam) case IDOK: GetDlgItemText(hDlg, IDC_IPADDR, d_str1, 128); GetDlgItemText(hDlg, IDC_CHATID, d_str2, 128); EndDialog(hDlg, IDOK); break; } case IDCANCEL: EndDialog(hDlg, IDCANCEL);
} break; return 0; BOOL CALLBACK HostDlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam) { switch(iMessage) case WM_COMMAND: switch(wParam) case IDOK: GetDlgItemText(hDlg, IDC_CHATID, d_str3, 128); EndDialog(hDlg, IDOK); case IDCANCEL: EndDialog(hDlg, IDCANCEL);
Direct X Demo 따라하기 다음으로 프로그램의 모든 이벤트를 다루기 위한 MsgProc를 수정해야 하나 양이 많음으로 삭제 후 다음과 같이 삽입한다. 자세한 내용은 주석을 참조한다 코드 LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { char temp[256]; switch( msg ) case WM_UCHAT: {//메시지 화면에 찍기 sprintf(temp, "%s %s", (char *)lParam, (char *)wParam); chat.chat_SetText(temp); break; } case WM_UMOVE: {//사용자 이동 //이동에 따른 효과음 출력 Multi_Sound.PlayFGSound(); user_lManager.userMove((char *)lParam, (char *)wParam); case WM_UCHATSEND: {//메시지 보내기 pDPSocket->SendMessage(CHAT_MESSAGE, -1, (char *)lParam);
case WM_UCONNECT: {//처음 접속시 //자신을 제외하고 접속이 들어왔을경우 접속한 사용자들에게 //자신의 최초좌표를 전송한다. if (strcmp(user1.get_Name(),(char *)lParam) != 0) { user_lManager.userAdd((char *)lParam); sprintf(temp, "%f %f %f", user1.get_x(), user1.get_y(), user1.get_z()); pDPSocket->SendMessage(START_MESSAGE, -1, temp); } break; case WM_UDISCON: {//사용자 접속 해제시 사용자 제거 user_lManager.userRemove((char *)lParam); case WM_USTARTM: {//사용자의 초기 위치값을 받았을 경우 세팅 float vx, vy, vz; sscanf((char *)wParam, "%f%f%f", &vx, &vy, &vz); user_lManager.setInitMove(vx, vy, vz, (char *)lParam); case WM_COMMAND: switch(wParam) case INET_HOST: //호스트 다이얼로그 박스 Pause(true); if (DialogBox(g_hInst, MAKEINTRESOURCE(IDD_HOST), hWnd, HostDlgProc) == IDOK) pDPSocket = CDPSocket::getInstance(); pDPSocket->InitializeDirectPlay(); pDPSocket->SetHWnd(hWnd);
user1.set_Name(d_str3); pDPSocket->Host(d_str3, 5150); } Pause(false); break; case INET_CONNECT: // 컨넥트 다이얼로그 박스 Pause(true); if (DialogBox(g_hInst, MAKEINTRESOURCE(IDD_CONNECT), hWnd, ConnectDlgProc) == IDOK) { pDPSocket = CDPSocket::getInstance(); pDPSocket->InitializeDirectPlay(); pDPSocket->SetHWnd(hWnd); user1.set_Name(d_str2); pDPSocket->Connect(d_str1, 5150, d_str2); case WM_CREATE: //chat클래스와 사운드 클레스 생성및 세팅 //백그라운드 음악 출력 chat.init_Chating(hWnd, g_hInst); Multi_Sound.Initialize(hWnd); Multi_Sound.CreateBGSound("Multi3.wav"); Multi_Sound.CreateFGSound("Multi2.wav"); Multi_Sound.PlayBGSound(); case WM_KEYDOWN: //네트워크 상태가 아닐경우 아무 변화도 일어나지 않게 함
if (pDPSocket == NULL) { MessageBox(hWnd, "네트워크 연결(HOST, CONNECT)을 하십시오.", "경고", MB_OK); break; } switch (wParam) //사용자 키 입력에 따른 메시지 처리 //엔터키를 입력하였을 경우 채팅창으로 포커스 이동. case VK_RETURN: chat.set_Focus(); //사용자 키 입력에 따른 이동내용 모든 사용자에게 통보 case VK_UP: user1.set_Move(0.0f, 0.0f, 1.0f); user1.UserRotate(-1.0f); pDPSocket->SendMessage(MOVE_MESSAGE, -1, "UP"); case VK_DOWN: user1.set_Move(0.0f, 0.0f, -1.0f); user1.UserRotate(1.0f); pDPSocket->SendMessage(MOVE_MESSAGE, -1, "DOWN"); case VK_LEFT: user1.set_Move(-1.0f, 0.0f, 0.0f); pDPSocket->SendMessage(MOVE_MESSAGE, -1, "LEFT"); case VK_RIGHT: user1.set_Move(1.0f, 0.0f, 0.0f); pDPSocket->SendMessage(MOVE_MESSAGE, -1, "RIGHT");
case WM_PAINT: { if( m_bLoadingApp ) // Draw on the window tell the user that the app is loading // TODO: change as needed HDC hDC = GetDC( hWnd ); TCHAR strMsg[MAX_PATH]; wsprintf( strMsg, TEXT("Loading... Please wait") ); RECT rct; GetClientRect( hWnd, &rct ); DrawText( hDC, strMsg, -1, &rct, DT_CENTER|DT_VCENTER|DT_SINGLELINE ); ReleaseDC( hWnd, hDC ); } break; case WM_CLOSE: delete pDPSocket; return CD3DApplication::MsgProc( hWnd, msg, wParam, lParam );
Direct X Demo 따라하기 Direct 3D로 인하여 화면의 채팅 에디트 박스와, 리스트 박스를 지워버림으로 부득이하게 d3dapp.cpp를 다음과 같이 수정 HRESULT CD3DApplication::Create( HINSTANCE hInstance )안에 WS_CLIPCHILDREN 속성 추가 m_dwWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE | WS_CLIPCHILDREN; 전체화면에서는 불가능