DirectXで視点の回転がうまくいかない
Posted: 2012年12月04日(火) 18:58
FPSゲームを作ろうとしているのですが、視点の回転がうまくいきません。
上のほうを見ようとすると、前にある物体が前に来るのです。
(このようになる→http://kuwasa.net/captingm/vi?key=aiknorCDFGIRTVWYZ3)
どうしたらよいのでしょうか?
また、前進,後退をしようとしてもすこしも進みません。
こちらの改善点も教えて頂けると嬉しいです。
分かりにくいコードで申し訳ない;;
上のほうを見ようとすると、前にある物体が前に来るのです。
(このようになる→http://kuwasa.net/captingm/vi?key=aiknorCDFGIRTVWYZ3)
どうしたらよいのでしょうか?
また、前進,後退をしようとしてもすこしも進みません。
こちらの改善点も教えて頂けると嬉しいです。
//DirectX.h
#ifndef DEF_DIRECTX_H
#define DEF_DIRECTX_H
HRESULT DxInit(HWND hWnd);
int DxMainloop(HWND hWnd);
int DxEnd(void);
int Draw2Drect(float left,float top,float right,float bottom,DWORD color);
#endif
//DirectX.cpp
#include <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
#include <stdio.h>
#include "DirectX.h"
#include "WndKey.h"
#define SCREEN_WIDTH GetSystemMetrics(SM_CXSCREEN)
#define SCREEN_HEIGHT GetSystemMetrics(SM_CYSCREEN)
#define FVF_CUSTOM ( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 )
#define WINDOW_WIDTH (500.0f)
#define WINDOW_HEIGHT (450.0f)
static LPDIRECT3D9 g_pD3D=NULL;
static LPDIRECT3DDEVICE9 g_pd3dDevice=NULL;
static IDirect3DVertexBuffer9 *pVertex;
static ID3DXBuffer *obj_pMat;
static ID3DXMesh *obj_pMesh;
static D3DLIGHT9 light;
DWORD obj_NumMat;
static float fCamX=12.0f,fCamY=2.0f,fCamZ=19.0f;
typedef struct CUSTOMVERTEX{
float x,y,z;
float rhw;
DWORD dwcolor;
float u,v;
}CUSTOMVERTEX;
HRESULT DxInit(HWND hWnd)
{
char msgbuff[2048];
BOOL WINDED = TRUE;
// DirectXの初期化
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
{
g_pD3D->Release();
MessageBox(hWnd,"Startup Failed.","DirectX9",MB_OK);
return E_FAIL;
}
// 画面などの設定
D3DDISPLAYMODE d3ddm;
D3DFORMAT fmt_mode;
if( FAILED( g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
{
g_pD3D->Release();
return E_FAIL;
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = WINDED; // WINDEDには、true か false を入れておく
if(WINDED)
{
fmt_mode = d3ddm.Format;
} else {
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; //D3DPRESENT_RATE_UNLIMITED D3DPRESENT_RATE_DEFAULT
}
d3dpp.BackBufferFormat = fmt_mode;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; //D3DSWAPEFFECT_FLIP D3DSWAPEFFECT_DISCARD D3DSWAPEFFECT_COPY;//描画フラグ
d3dpp.EnableAutoDepthStencil = TRUE; // Zバッファを使用する
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.BackBufferCount = 1;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
// 設定した画面情報をDirectXに登録する。
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) )
{
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) )
{
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) )
{
sprintf_s(msgbuff,"CreateDevice Error. \nBackBufferFormat=0x%04X\n",d3dpp.BackBufferFormat);
MessageBox(hWnd,msgbuff,"Error!",MB_OK);
g_pD3D->Release();
return E_FAIL;
}
}
}
//-----------------------------------------------
// 画像以外のDirectXの初期化は、ここで行う
//-----------------------------------------------
if(FAILED(D3DXLoadMeshFromX(_T("ground.x"),
D3DXMESH_MANAGED,
g_pd3dDevice,
NULL,
&obj_pMat,
NULL,
&obj_NumMat,
&obj_pMesh)))
{
g_pd3dDevice->Release();
g_pD3D->Release();
return E_FAIL;
}
ZeroMemory(&light,sizeof(D3DLIGHT9));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse.r= light.Diffuse.g= light.Diffuse.b=0.4f;
light.Specular.r= light.Specular.g= light.Specular.b=0.1f;
light.Ambient.r= light.Ambient.g= light.Ambient.b=0.2f;
light.Direction = D3DXVECTOR3(1,-5,-10); // 平行光源なので向きが必要
g_pd3dDevice->SetLight(0,&light);
g_pd3dDevice->LightEnable(0,TRUE);
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_AMBIENT,0x00808080);
return S_OK;
}
int DxMainloop(HWND hWnd)
{
D3DXMATRIX World_gr;
D3DXMATRIX Rot;
D3DXMATRIX Offset;
D3DXMATRIX View;
D3DXMATRIX Persp;
D3DCOLORVALUE MAmbient = {0.2f, 0.2f, 0.2f, 1.0f};
int Ground_NumX=10,Ground_NumZ=10;//地面の数
int x,y;
//int CurrentKey;
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(40,40,80),
1.0f,
NULL );
g_pd3dDevice->BeginScene();
//ビュー変換+移動について
if(GetKey()==KEY_W){fCamX+=(float)cos(3.14159/180*GetMoveX());
fCamZ+=(float)sin(3.14159/180*GetMoveX());}
if(GetKey()==KEY_A){}
if(GetKey()==KEY_S){fCamX-=(float)cos(3.14159/180*GetMoveX());
fCamZ-=(float)sin(3.14159/180*GetMoveX()); }
if(GetKey()==KEY_D){}
D3DXMatrixLookAtLH(
&View,
&D3DXVECTOR3(fCamX, 2.0f, fCamZ),
&D3DXVECTOR3((float)fCamX+(float)cos(3.14159/180*GetMoveX()),
(float)fCamY+(float)cos(3.14159/180*GetMoveY()/2),
(float)fCamZ+(float)sin(3.14159/180*GetMoveX())),
&D3DXVECTOR3(0.0f, 1.0f, 0.0f)
);
//射影変換
D3DXMatrixPerspectiveFovLH(
&Persp,
D3DXToRadian(90),
WINDOW_HEIGHT/WINDOW_WIDTH,
1.0f,
10000.0f);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &View);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &Persp);
for(x=0;x<Ground_NumX;x++)
for(y=0;y<Ground_NumZ;y++)
{
//FLOAT PosX = (FLOAT)x-Ground_NumX/220.0f; // 板の制御点の
//FLOAT PosY = (FLOAT)y-Ground_NumZ/220.0f; // 位置(x,y,0)を決め、
FLOAT PosX = (FLOAT)x-Ground_NumX/200.0f;
FLOAT PosY = (FLOAT)y-Ground_NumZ/200.0f;
D3DXMatrixTranslation(&Offset,PosX,0.0f,PosY);
D3DXMatrixIdentity(&World_gr);
D3DXMatrixMultiply(&World_gr,&World_gr,&Offset);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &World_gr);
for(UINT i=0; i<obj_NumMat; i++){ // 描画
D3DXMATERIAL *mtrl = ( (D3DXMATERIAL*)(obj_pMat->GetBufferPointer()) + i);
mtrl->MatD3D.Ambient = MAmbient;
g_pd3dDevice->SetMaterial( &mtrl->MatD3D );
obj_pMesh->DrawSubset(i);
};
}
// レンダリングステートの再初期化
g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE);
g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
Draw2Drect(0.0f,0.0f,0.0f,0.0f,RGB(0,0,0));//エラー回避
g_pd3dDevice->EndScene();
g_pd3dDevice->Present(NULL,NULL,NULL,NULL);
return 0;
}
int DxEnd(void)
{
g_pd3dDevice->Release();
g_pD3D->Release();
pVertex->Release();
obj_pMesh->Release();
return 0;
}
int Draw2Drect(float left,float top,float right,float bottom,COLORREF color)
{
CUSTOMVERTEX v[4]=
{
{ right , top , 0.0f , 1.0f , color , left , top },
{ right , bottom , 0.0f , 1.0f , color , left , bottom },
{ left , top , 0.0f , 1.0f , color , right , top },
{ left , bottom , 0.0f , 1.0f , color , right , bottom }
};
void *pData;
if(g_pd3dDevice->CreateVertexBuffer(sizeof(CUSTOMVERTEX)*4,
D3DUSAGE_WRITEONLY,
FVF_CUSTOM,D3DPOOL_MANAGED,
&pVertex,NULL)
!=D3D_OK)
{
MessageBox(NULL,_T("内部エラー\n描画に失敗しました"),_T("Error!"),MB_OK);
g_pd3dDevice->Release();
g_pD3D->Release();
return -1;
}
if(pVertex->Lock(0,sizeof(CUSTOMVERTEX)*4,(void**)&pData,0)==D3D_OK)
{
memcpy(pData,v,sizeof(CUSTOMVERTEX)*4);
pVertex->Unlock();
}else{
MessageBox(NULL,_T("描画失敗"),_T(""),MB_OK);
g_pd3dDevice->Release();
g_pD3D->Release();
return -1;
}
g_pd3dDevice->SetStreamSource(0,pVertex,0,sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetFVF(FVF_CUSTOM);
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);
return 0;
}
/*WndKey.h*/
#ifndef DEF_WNDKEY_H
#define DEF_WNDKEY_H
//キー関数向けの定数(キーコード)
#define KEY_1 1
#define KEY_2 2
#define KEY_3 3
#define KEY_4 4
#define KEY_5 5
#define KEY_6 6
#define KEY_7 7
#define KEY_8 8
#define KEY_9 9
#define KEY_0 10
#define KEY_A 11
#define KEY_B 12
#define KEY_C 13
#define KEY_D 14
#define KEY_E 15
#define KEY_F 16
#define KEY_G 17
#define KEY_H 18
#define KEY_I 19
#define KEY_J 20
#define KEY_K 21
#define KEY_L 22
#define KEY_M 22
#define KEY_N 23
#define KEY_O 24
#define KEY_P 25
#define KEY_Q 26
#define KEY_R 27
#define KEY_S 28
#define KEY_T 29
#define KEY_U 30
#define KEY_V 31
#define KEY_W 32
#define KEY_X 33
#define KEY_Y 34
#define KEY_Z 35
#define KEY_BACK 36
#define KEY_TAB 37
#define KEY_CLEAR 38
#define KEY_RETURN 39
#define KEY_SHIFT 40
#define KEY_CONTROL 41//CTRLキー
#define KEY_MENU 42
#define KEY_PAUSE 43
#define KEY_CAPITAL 44//CAPSロックキー
#define KEY_ESCAPE 45//ESCキー
#define KEY_SPACE 46
#define KEY_PRIOR 47//PageUpキー
#define KEY_NEXT 48//PageDownキー
#define KEY_END 49
#define KEY_HOME 50
#define KEY_LEFT 51//カーソルキー始
#define KEY_UP 52
#define KEY_RIGHT 53
#define KEY_DOWN 54//カーソルキー終
#define KEY_PRINT 55//PrintScreenキー
#define KEY_INSERT 56
#define KEY_DELETE 57
#define KEY_LWIN 58//左Windowsキー
#define KEY_RWIN 59//右Windowsキー
#define KEY_NUMPAD0 60//テンキー始
#define KEY_NUMPAD1 61
#define KEY_NUMPAD2 62
#define KEY_NUMPAD3 63
#define KEY_NUMPAD4 64
#define KEY_NUMPAD5 65
#define KEY_NUMPAD6 66
#define KEY_NUMPAD7 67
#define KEY_NUMPAD8 68
#define KEY_NUMPAD9 69
#define KEY_MULTIPLY 70//テンキー*
#define KEY_ADD 71//テンキー+
#define KEY_SEPARATOR 72//テンキーEnter
#define KEY_SUBTRACT 73//テンキー-
#define KEY_DECIMAL 74//テンキー.
#define KEY_DEVIDE 75//テンキー/ テンキー終
#define KEY_F1 76
#define KEY_F2 77
#define KEY_F3 78
#define KEY_F4 79
#define KEY_F5 80
#define KEY_F6 81
#define KEY_F7 82
#define KEY_F8 83
#define KEY_F9 84
#define KEY_F10 85
#define KEY_F11 86
#define KEY_F12 87
#define KEY_F13 88
#define KEY_F14 89
#define KEY_F15 90
#define KEY_F16 91
#define KEY_NUMLOCK 92
#define KEY_SCROLL 93//ScrollLockキー
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);//ウィンドウプロシージャ
HWND Create(HINSTANCE hInst); //ウィンドウクラス等作成
HWND ProcessWindow(HINSTANCE hInst);//ウィンドウ作成と表示
int ProcessMessage(void);//メッセージの処理
int GetKey();//押されているキーの取得
float GetMoveX();//マウスカーソルの動きを取得X
float GetMoveY();//マウスカーソルの動きを取得Y
#endif
/*WndKey.cpp*/
#include <windows.h>
#include <tchar.h>
#include "WndKey.h"
//定数
#define WINDOW_WIDTH (500)
#define WINDOW_HEIGHT (450)
#define WINDOW_X ((GetSystemMetrics(SM_CXSCREEN)-WINDOW_WIDTH)/2)
#define WINDOW_Y ((GetSystemMetrics(SM_CYSCREEN)-WINDOW_HEIGHT)/2)
//ウィンドウハンドル
static HWND hWnd;
//メッセージ変数
static MSG msg;
//キー情報格納
static int keywp;
//マウスの位置を格納
static POINT CursorPos;
//カーソルの動いた距離を格納
static int mouseposX,mouseposY;
static int addX=0,addY=0;
//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch( msg )
{
case WM_MOUSEMOVE:
GetCursorPos(&CursorPos);
if (CursorPos.x!=(WINDOW_WIDTH/2)&&CursorPos.y!=(WINDOW_HEIGHT/2))
{
mouseposX=(addX*((WINDOW_WIDTH/2)-100))+CursorPos.x-(WINDOW_WIDTH/2);
mouseposY=(addY*((WINDOW_HEIGHT/2)-100))+CursorPos.y-(WINDOW_HEIGHT/2);
}
if (CursorPos.x>400)
{
addX++;
mouseposX=(addX*((WINDOW_WIDTH/2)-100))+CursorPos.x-(WINDOW_WIDTH/2);
mouseposY=(addY*((WINDOW_HEIGHT/2)-100))+CursorPos.y-(WINDOW_HEIGHT/2);
SetCursorPos(WINDOW_WIDTH/2,WINDOW_HEIGHT/2);
}
if (CursorPos.y>350)
{
addY++;
mouseposX=(addX*((WINDOW_WIDTH/2)-100))+CursorPos.x-(WINDOW_WIDTH/2);
mouseposY=(addY*((WINDOW_HEIGHT/2)-100))+CursorPos.y-(WINDOW_HEIGHT/2);
SetCursorPos(WINDOW_WIDTH/2,WINDOW_HEIGHT/2);
}
if (CursorPos.x<100)
{
addX--;
mouseposX=(addX*((WINDOW_WIDTH/2)-100))+CursorPos.x-(WINDOW_WIDTH/2);
mouseposY=(addY*((WINDOW_HEIGHT/2)-100))+CursorPos.y-(WINDOW_HEIGHT/2);
SetCursorPos(WINDOW_WIDTH/2,WINDOW_HEIGHT/2);
}
if (CursorPos.y<100)
{
addY--;
mouseposX=(addX*((WINDOW_WIDTH/2)-100))+CursorPos.x-(WINDOW_WIDTH/2);
mouseposY=(addY*((WINDOW_HEIGHT/2)-100))+CursorPos.y-(WINDOW_HEIGHT/2);
SetCursorPos(WINDOW_WIDTH/2,WINDOW_HEIGHT/2);
}
return 0;
case WM_KEYDOWN:
keywp=wp;//グローバル変数に押されたキーの情報を渡す
return 0;
case WM_DESTROY: // ウィンドウを破棄するとき
PostQuitMessage( 0 );
return 0;
}
// 他のメッセージは、デフォルトの処理を行う
return DefWindowProc( hWnd, msg, wp, lp );
}
HWND Create(HINSTANCE hInst)
{
WNDCLASSEX wc;
// ウィンドウクラスの情報を設定
wc.cbSize = sizeof(wc); // 構造体サイズ
wc.style = CS_HREDRAW | CS_VREDRAW; // スタイル
wc.lpfnWndProc = WndProc; // ウィンドウプロシージャ
wc.cbClsExtra = 0; // 拡張情報1
wc.cbWndExtra = 0; // 拡張情報2
wc.hInstance = hInst; // インスタンスハンドル
wc.hIcon = (HICON)LoadImage( // アイコン
NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON,
0, 0, LR_DEFAULTSIZE | LR_SHARED
);
wc.hIconSm = wc.hIcon; // 子アイコン
wc.hCursor = (HCURSOR)LoadImage( // マウスカーソル
NULL, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR,
0, 0, LR_DEFAULTSIZE | LR_SHARED
);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // ウィンドウ背景
wc.lpszMenuName = NULL; // メニュー名
wc.lpszClassName = _T("Default Class Name");// ウィンドウクラス名
// ウィンドウクラスを登録する
if( RegisterClassEx( &wc ) == 0 ){ return NULL; }
// ウィンドウを作成する
return CreateWindow(
wc.lpszClassName, // ウィンドウクラス名
_T("Main Window"), // タイトルバーに表示する文字列
WS_OVERLAPPEDWINDOW&~WS_THICKFRAME&~WS_MAXIMIZEBOX, // ウィンドウの種類
WINDOW_X, // ウィンドウを表示する位置(X座標)
WINDOW_Y, // ウィンドウを表示する位置(Y座標)
WINDOW_WIDTH, // ウィンドウの幅
WINDOW_HEIGHT, // ウィンドウの高さ
NULL, // 親ウィンドウのウィンドウハンドル
NULL, // メニューハンドル
hInst, // インスタンスハンドル
NULL // その他の作成データ
);
}
HWND ProcessWindow(HINSTANCE hInst)//ウィンドウを作成・表示
{
hWnd = Create(hInst);//ウィンドウの作成
if( hWnd == NULL )
{
MessageBox(NULL, _T("Startup Failed."),_T("errid_1"),MB_OK);
return 0;
}
// ウィンドウを表示する
ShowWindow( hWnd, SW_SHOW );
UpdateWindow( hWnd );
return hWnd;
}
int ProcessMessage(void)
{
BOOL ret = GetMessage( &msg, NULL, 0, 0 ); // メッセージを取得する
if( ret == 0 || ret == -1 )
{
// アプリケーションを終了させるメッセージが来ていたら、
// あるいは GetMessage() が失敗したら( -1 が返されたら )、-1を返す
return -1;
}
else
{
// メッセージを処理する
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return 0;
}
int GetKey()//グローバル変数に渡されたキーの情報を処理する
{
switch(keywp)//作りかけ・・
{
case '0':
keywp=NULL;
return KEY_0;
case '1':
keywp=NULL;
return KEY_1;
case '2':
keywp=NULL;
return KEY_2;
case 'A':
keywp=NULL;
return KEY_A;
case VK_LEFT:
keywp=NULL;
return KEY_LEFT;
case VK_UP:
keywp=NULL;
return KEY_UP;
case VK_RIGHT:
keywp=NULL;
return KEY_RIGHT;
case VK_DOWN:
keywp=NULL;
return KEY_DOWN;
default:
break;
}
return 0;
}
float GetMoveX()
{
return (float)mouseposX;
}
float GetMoveY()
{
return (float)mouseposY;
}