게임프로그래밍 공부

평면위에 미끄러지는 구체

루실리드 2013. 5. 20. 15:58

 

// wasd 로 구체 이동 , 방향키로 평면기울기 변경

Tutorial7.exe

 

#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <time.h>
#include <math.h>
#include <d3dx9.h>

//#define  _FULLMODE
#ifdef _FULLMODE
BOOL gFullScreen =TRUE;
#else
BOOL gFullScreen =FALSE;
#endif

#define  WIDTH_RES  1024
#define  HEIGHT_RES  768

#define Random(num)   (int)(((long)rand() * (num) )/ (RAND_MAX+1) )
#define Randomize()   srand( (unsigned) time(NULL) )
#define RandomA( s, e )  ( (s) + (Random( (e) - (s) + 1 )) )

// FVF 선언
#define D3DFVF_CUSTOMFVF1    (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
#define D3DFVF_CUSTOMFVF2    (D3DFVF_XYZ | D3DFVF_DIFFUSE)

// 구조체
struct CUSTOMVERTEX1
{
 FLOAT x, y, z, rhw;
 DWORD color;
};
struct CUSTOMVERTEX2
{
 FLOAT x, y, z;
 DWORD color;
};

//전역변수
LPDIRECT3D9  g_pD3D    =NULL;
LPDIRECT3DDEVICE9 g_pd3dDevice =NULL;
LPDIRECT3DVERTEXBUFFER9 g_pVB       =NULL;
LPDIRECT3DVERTEXBUFFER9 g_p2VB       =NULL;
LPD3DXMESH      g_Mesh = NULL;

BOOL   g_bGameOver   =FALSE;
TCHAR   *g_pProjectName  =_T("3DSample");
BYTE   g_bKey[256] = {0,};
WORD   g_MouseX, g_MouseY;
BOOL   g_bClick[2] = { FALSE, };

BOOL IntersectTriangle( const D3DXVECTOR3& orig,
                                       const D3DXVECTOR3& dir, D3DXVECTOR3& v0,
                                       D3DXVECTOR3& v1, D3DXVECTOR3& v2,
                                       FLOAT* t, FLOAT* u, FLOAT* v )
{
    // Find vectors for two edges sharing vert0
    D3DXVECTOR3 edge1 = v1 - v0;
    D3DXVECTOR3 edge2 = v2 - v0;

    // Begin calculating determinant - also used to calculate U parameter
    D3DXVECTOR3 pvec;
    D3DXVec3Cross( &pvec, &dir, &edge2 );

    // If determinant is near zero, ray lies in plane of triangle
    FLOAT det = D3DXVec3Dot( &edge1, &pvec );

    D3DXVECTOR3 tvec;
    if( det > 0 )
    {
        tvec = orig - v0;
    }
    else
    {
        tvec = v0 - orig;
        det = -det;
    }

    if( det < 0.0001f )
        return FALSE;

    // Calculate U parameter and test bounds
    *u = D3DXVec3Dot( &tvec, &pvec );
    if( *u < 0.0f || *u > det )
        return FALSE;

    // Prepare to test V parameter
    D3DXVECTOR3 qvec;
    D3DXVec3Cross( &qvec, &tvec, &edge1 );

    // Calculate V parameter and test bounds
    *v = D3DXVec3Dot( &dir, &qvec );
    if( *v < 0.0f || *u + *v > det )
        return FALSE;

    // Calculate t, scale parameters, ray intersects triangle
    *t = D3DXVec3Dot( &edge2, &qvec );
    FLOAT fInvDet = 1.0f / det;
    *t *= fInvDet;
    *u *= fInvDet;
    *v *= fInvDet;

    return TRUE;
}

HRESULT InitD3D( HWND hWnd )
{
 D3DDISPLAYMODE d3ddm;

 if( !(g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
 { return E_FAIL; }

 if( FAILED( g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm) ) )
 { return E_FAIL; }

 D3DPRESENT_PARAMETERS d3dpp;
 ZeroMemory( &d3dpp, sizeof( d3dpp ) );
 

#ifdef  _FULLMODE
 //풀모드 세팅
 d3dpp.BackBufferWidth    = WIDTH_RES;
    d3dpp.BackBufferHeight    = HEIGHT_RES;
 d3dpp.BackBufferFormat    = D3DFMT_R5G6B5;
 d3dpp.BackBufferCount    = 1;

 d3dpp.MultiSampleType    = D3DMULTISAMPLE_NONE;
 d3dpp.SwapEffect     = D3DSWAPEFFECT_DISCARD;

 d3dpp.hDeviceWindow     = hWnd;
 d3dpp.Windowed      = !gFullScreen;

 d3dpp.EnableAutoDepthStencil  = TRUE;
 d3dpp.AutoDepthStencilFormat  = D3DFMT_D24S8;
 d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_DEFAULT;
#else
 //윈도우 모드
 d3dpp.BackBufferWidth    = WIDTH_RES;
    d3dpp.BackBufferHeight    = HEIGHT_RES;
 d3dpp.BackBufferFormat    = d3ddm.Format;
 d3dpp.BackBufferCount    = 1;

 d3dpp.MultiSampleType    = D3DMULTISAMPLE_NONE;
 d3dpp.SwapEffect     = D3DSWAPEFFECT_DISCARD;

 d3dpp.hDeviceWindow     = hWnd;
 d3dpp.Windowed      = !gFullScreen;

 d3dpp.EnableAutoDepthStencil  = TRUE;
 d3dpp.AutoDepthStencilFormat  = D3DFMT_D24S8;
 d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_IMMEDIATE;
#endif
 
 if( FAILED ( g_pD3D->CreateDevice(
       D3DADAPTER_DEFAULT,
       D3DDEVTYPE_HAL,
       hWnd,
       D3DCREATE_SOFTWARE_VERTEXPROCESSING,
       &d3dpp,
       &g_pd3dDevice )
    )
   ) 
 {
  return E_FAIL;
 }

 g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
 //g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
 g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
 g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
 g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );

 g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
 g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
 g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_NONE );

 return S_OK;
}

D3DXVECTOR3 g_Plane[4];

HRESULT InitData( void )
{
 //==========================================================
 //초기화와 관련된 모든 코드
 //==========================================================

 //구체 생성
 if(FAILED(D3DXCreateSphere( g_pd3dDevice, 2.0f, 16, 8, &g_Mesh, NULL)) )
 {
  return E_FAIL;
 }
 
 //바닥생성
 g_Plane[0] = D3DXVECTOR3( -20.0f, 0.0f,  20.0f );
 g_Plane[1] = D3DXVECTOR3(  20.0f, 0.0f,  20.0f );
 g_Plane[2] = D3DXVECTOR3( -20.0f, 0.0f, -20.0f );
 g_Plane[3] = D3DXVECTOR3(  20.0f, 0.0f, -20.0f );

 CUSTOMVERTEX2 cv[] =
 {
  { g_Plane[0].x , g_Plane[0].y ,  g_Plane[0].z , 0xffffffff }, { g_Plane[1].x , g_Plane[1].y ,  g_Plane[1].z , 0xffffffff }, { g_Plane[3].x , g_Plane[3].y ,  g_Plane[3].z , 0xffffffff },
  { g_Plane[0].x , g_Plane[0].y ,  g_Plane[0].z , 0xffffffff }, { g_Plane[3].x , g_Plane[3].y ,  g_Plane[3].z , 0xffffffff }, { g_Plane[2].x , g_Plane[2].y ,  g_Plane[2].z , 0xffffffff },
 };

 if(FAILED(g_pd3dDevice->CreateVertexBuffer( sizeof(CUSTOMVERTEX2)*6, 0, D3DFVF_CUSTOMFVF2, D3DPOOL_DEFAULT, &g_pVB, NULL )) )
 {
  return E_FAIL;
 }

 VOID* pV;
 g_pVB->Lock( 0, sizeof(cv), (VOID**)&pV, 0);
 memcpy( pV, cv, sizeof(cv) );
 g_pVB->Unlock();

 return S_OK;
}

void Cleanup(void)
{
 if( g_Mesh != NULL )
 { g_Mesh->Release(); } 

 if( g_pVB != NULL )
 { g_pVB->Release(); }

 if( g_pd3dDevice != NULL )
 { g_pd3dDevice->Release(); }

 if( g_pD3D != NULL )
 { g_pD3D->Release(); }
}

D3DXVECTOR3 g_Vector(0.0f,0.0f,0.0f);  //출력 위치
FLOAT g_fRotY = D3DX_PI*2.0f*0.5f;   //이동각도

void FrameMove( UINT interval )
{
 //==========================================================
 //변수 갱신과 관련된 모든 코드
 //==========================================================

 //키 처리
 short rotSpeed = 1000;       //한바퀴도는대 걸리는 시간 
 FLOAT SPEED = 1.0f;        //초당 이동속도

 FLOAT intervalRot = (FLOAT)interval / (FLOAT)rotSpeed;  //현재 프래임 이동 각도
 FLOAT intervalSpeed = SPEED / interval;      //현재 프래임 이동 거리

 D3DXVECTOR3 vDir(0.0f, 0.0f, 0.0f);    //이동백터 

 //키처리

  //구 움직임 처리
 BOOL isDown = false;
 if( g_bKey['A'] )
 {
  g_fRotY -= D3DX_PI*2.0f*intervalRot;  
 }
 if( g_bKey['D'] )
 {
  g_fRotY += D3DX_PI*2.0f*intervalRot;  
 }
 if( g_bKey['W'] )
 {
  vDir.z = 1.0f;
  vDir *= intervalSpeed;
  isDown = TRUE;
 }
 if( g_bKey['S'] )
 {
  vDir.z = 1.0f;
  vDir *= -intervalSpeed;
  isDown = TRUE;
 }

  //지면 움직임 처리
 BOOL isPlaneDown = false;
 if( g_bKey[37] )
 {
  g_Plane[0].y += intervalSpeed;
  g_Plane[2].y += intervalSpeed;
  g_Plane[1].y -= intervalSpeed;
  g_Plane[3].y -= intervalSpeed;
  isPlaneDown = TRUE;
 }
 if( g_bKey[39] )
 {
  g_Plane[0].y -= intervalSpeed;
  g_Plane[2].y -= intervalSpeed;
  g_Plane[1].y += intervalSpeed;
  g_Plane[3].y += intervalSpeed;
  isPlaneDown = TRUE;
 }
 if( g_bKey[38] )
 {
  g_Plane[0].y -= intervalSpeed;
  g_Plane[1].y -= intervalSpeed;
  g_Plane[2].y += intervalSpeed;
  g_Plane[3].y += intervalSpeed;
  isPlaneDown = TRUE;
 }
 if( g_bKey[40] )
 {
  g_Plane[0].y += intervalSpeed;
  g_Plane[1].y += intervalSpeed;
  g_Plane[2].y -= intervalSpeed;
  g_Plane[3].y -= intervalSpeed;
  isPlaneDown = TRUE;
 } 
  //지면 갱신
 if( isPlaneDown )
 {
  CUSTOMVERTEX2 cv[] = {
   { g_Plane[0].x , g_Plane[0].y ,  g_Plane[0].z , 0xffffffff }, { g_Plane[1].x , g_Plane[1].y ,  g_Plane[1].z , 0xffffffff }, { g_Plane[3].x , g_Plane[3].y ,  g_Plane[3].z , 0xffffffff },
   { g_Plane[0].x , g_Plane[0].y ,  g_Plane[0].z , 0xffffffff }, { g_Plane[3].x , g_Plane[3].y ,  g_Plane[3].z , 0xffffffff }, { g_Plane[2].x , g_Plane[2].y ,  g_Plane[2].z , 0xffffffff },
  };

  VOID* pV;
  g_pVB->Lock(0, sizeof(cv), (void**)&pV, 0);
  memcpy( pV, cv, sizeof(cv) );
  g_pVB->Unlock();
 }

 //이동
 D3DXMATRIXA16 matRot;
 D3DXMatrixRotationY(&matRot, g_fRotY );
 D3DXVec3TransformCoord( &vDir, &vDir, &matRot );

 //출력위치 갱신
 D3DXVECTOR3 vTemp = g_Vector;
 vTemp += vDir;

 //픽
 vTemp.y = 1000.0f;
 
 FLOAT t,u,v;
 BOOL isPick = false;  //픽 유무
 isPick = ::IntersectTriangle( vTemp, D3DXVECTOR3( 0.0f, -1.0f, 0.0f), g_Plane[0], g_Plane[1], g_Plane[3] , &t, &u, &v );
 if( !isPick )
  isPick = ::IntersectTriangle( vTemp, D3DXVECTOR3( 0.0f, -1.0f, 0.0f), g_Plane[0], g_Plane[3], g_Plane[2] , &t, &u, &v );

 if( isPick )
 {
  //면의 법선을 구하기
  D3DXVECTOR3 v1,v2,vNormal;
  v1 = g_Plane[1] - g_Plane[0] ;
  v2 = g_Plane[3] - g_Plane[0] ;  
  D3DXVec3Cross(&vNormal, &v1 , &v2 );
  D3DXVec3Normalize(&vNormal, &vNormal);
  
  //미끄러짐 백터 구하기
  D3DXVECTOR3 v( 0.0f, -1.0f , 0.0f );
  D3DXVECTOR3 b = -vNormal;
  D3DXVECTOR3 a = v - D3DXVec3Dot(&b,&v)*b;

  //픽위치 구하기
  vTemp = vTemp + (v*t);

  //결과 갱신
  vTemp += a;
  g_Vector = vTemp;
 }
 else
 {
  FLOAT G=9.81f;
  g_Vector += D3DXVECTOR3(0.0f, -1.0f, 0.0f)*G*(interval/1000.0f);
 }

 //떨어질때 처음 위치로
 if( g_Vector.y < -30.0f )
 {
  g_Vector = D3DXVECTOR3(0.0f, 20.0f, 0.0f);
 }
}

void SetupMatrices( void )
{
 //==========================================================
 // World, View, Project Setting
 //==========================================================

 D3DXMATRIXA16 matView;
    D3DXVECTOR3 eye(0.0f, 5.0f , -40.0f);
    D3DXVECTOR3 lookat(0.0f, 0.0f , 0.0f);
    D3DXVECTOR3 up(0.0f, 1.0f , 0.0f);
    D3DXMatrixLookAtLH(&matView, &eye, &lookat, &up);
 g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

 D3DXMATRIXA16 matProj;
 D3DXMatrixPerspectiveLH( &matProj, D3DX_PI/2.0f , (float)WIDTH_RES/(float)HEIGHT_RES, 1.0f, 5000.0f );
 g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}

 

 

HRESULT Render( UINT interval )
{
 g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
                   D3DCOLOR_XRGB(0x80,0x80,0x80), 1.0f, 0 );
 g_pd3dDevice->BeginScene();
 SetupMatrices();
 //==========================================================
 // 그려주세요~
 //==========================================================
  //월드 설정
 UINT iTime = timeGetTime() % 1000;
 FLOAT fAngle = iTime / 1000.0f * 2.0f* D3DX_PI;

 D3DXMATRIXA16 matWorld, matTrans, matRot;
 D3DXMatrixTranslation(&matTrans, g_Vector.x, g_Vector.y+2.0f, g_Vector.z);
 D3DXMatrixRotationY( &matRot, g_fRotY );
 D3DXMatrixIdentity(&matWorld); 

 //지면 출력
 g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
 g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX2) );
 g_pd3dDevice->SetFVF( D3DFVF_CUSTOMFVF2 );
 g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );

 //구출력
 matWorld = matRot * matTrans;
 g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
 g_Mesh->DrawSubset(0);

 g_pd3dDevice->EndScene();
 g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

 return true;
}

// 윈도우 프로시져
LRESULT WINAPI    WindowProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch (msg)
    {
  //마우스입력
  case WM_MOUSEMOVE:
  {
   g_MouseX = LOWORD(lParam);
   g_MouseY = HIWORD(lParam);
  }
  break;
  case WM_LBUTTONDOWN:
  {
   g_MouseX = LOWORD(lParam);
   g_MouseY = HIWORD(lParam);
   g_bClick[0] = 1;
  }
  break;
  case WM_LBUTTONUP:
  {  
   g_bClick[0] = 0;
  }
  break;
  case WM_RBUTTONDOWN:
  {
   g_MouseX = LOWORD(lParam);
   g_MouseY = HIWORD(lParam);
   g_bClick[1] = 1;
  }
  break;
  case WM_RBUTTONUP:
  {  
   g_bClick[1] = 0;
  }
  break;

  //키보드 처리
        case WM_KEYDOWN:
            switch( wParam )
            {
                case VK_ESCAPE :
                    g_bGameOver = TRUE;
                break;
            }

            g_bKey[wParam] = 1;
        break;

        case WM_KEYUP:
            g_bKey[wParam] = 0;
            break; 

        case WM_DESTROY:
            PostQuitMessage(0);
            break;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}

 


INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
 HWND g_hWnd;
 WNDCLASS wc;
 MSG msg;

    wc.style   = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc  = (WNDPROC)WindowProc;
    wc.cbClsExtra  = 0;
    wc.cbWndExtra  = 0;
    wc.hInstance  = hInst;
    wc.hIcon   = LoadIcon( NULL, IDI_APPLICATION );
    wc.hCursor   = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground = NULL;
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_pProjectName;
 
 RegisterClass( &wc );

 if( !gFullScreen )
 {
  //윈도우 모드
  g_hWnd = CreateWindowEx( 0, g_pProjectName, g_pProjectName, WS_POPUP | WS_SYSMENU,
   ( GetSystemMetrics(SM_CXSCREEN) / 2) - (WIDTH_RES /2 ),
   ( GetSystemMetrics(SM_CYSCREEN) / 2) - (HEIGHT_RES /2 ),
   WIDTH_RES, HEIGHT_RES, NULL, NULL, hInst, NULL );
 }
 else
 {
  //전체 모드
  g_hWnd = CreateWindowEx( 0, g_pProjectName, g_pProjectName, WS_POPUP | WS_SYSMENU,
   0, 0, WIDTH_RES, HEIGHT_RES, NULL, NULL, hInst, NULL );
 }

 if( g_hWnd == NULL )     {return FALSE;}
 if( FAILED( InitD3D( g_hWnd ) ) )  {return FALSE;}
 if( FAILED( InitData() ) )   {return FALSE;}

 ShowWindow(g_hWnd, nCmdShow);
 UpdateWindow(g_hWnd);
 SetFocus(g_hWnd);
 ShowCursor( TRUE );

 static UINT preTime = timeGetTime();

 while( !g_bGameOver )
 {
  if( PeekMessage( &msg, NULL ,0, 0, PM_NOREMOVE ) )
  {
   if( !GetMessage( &msg, NULL, 0, 0) )
   { return msg.wParam; }
   TranslateMessage( &msg );
   DispatchMessage( &msg );
  }
  else
  {   
   Sleep(1);
   UINT iTime = timeGetTime();
   FrameMove(iTime - preTime );
   Render(iTime - preTime);
   preTime = iTime;
  }
 }

 Cleanup();
 UnregisterClass( g_pProjectName, wc.hInstance );
 return TRUE;
}

Tutorial7.exe
0.94MB

'게임프로그래밍 공부' 카테고리의 다른 글

4주간 만들다가......  (0) 2013.07.08
코딩안되서하는 물리공부1  (0) 2013.06.28
지형에디터 및 MD2로더 재수정  (0) 2013.05.19
MD2뷰어, 지형에디터 수정  (0) 2013.05.13
안되는거.....  (0) 2013.05.08