xファイルで読み込んだキャラクターを表示し、カーソルキーで動かしたい

解決


宇宙円盤  2011-03-29 04:27:59  No: 72528  IP: 192.*.*.*

xファイルで読み込んだキャラクターを表示し、カーソルキーで動かしたい
初めて質問させていただきます。
言語はC++を使ってソフトはVisual C++ 2010を使っています

15歳からはじめるDirectX9 3Dゲームプログラミング教室C++編という本を参考にして
xファイルを読み込み表示させて、読み込んだキャラクターを
カーソルキーで動かせるようにしたいのですが
エラーは出ず、読み込んだキャラクターは表示されるのですが、
動かすことが出来ません
初心者ですが何処が間違ってるか教えていただけるとありがたいです。

--------------------------------------------my3dlib.h---------------------------------------- 

#include <Windows.h>
#include <mmsystem.h>
#include <d3dx9.h>
#include <tchar.h>
#include<dinput.h>



struct Model
{
  LPD3DXMESH        pmesh;
  D3DMATERIAL9*      pmaterials;
  LPDIRECT3DTEXTURE9*    ptextures;
  DWORD          nummaterials;
  BOOL used;
};


//グローバル変数
extern LPDIRECT3D9      g_pD3D;
extern LPDIRECT3DDEVICE9  g_pd3dDevice;
extern float        g_aspect;
extern Model        g_models[];

//関数プロトタイプ宣言
HRESULT InitD3DWindow(LPCTSTR wintitle, int w,int h);
int LoadModel(LPCTSTR filename);
void RenderModel(int idx);
const char *GetKeyState();

-----------------------------------------my3dlib.cpp----------------------------------------- 
#include "my3dlib.h"

LPDIRECT3D9        g_pD3D = NULL;
LPDIRECT3DDEVICE9  g_pd3dDevice = NULL;
float        g_aspect = 1.0f;
const int      MAXMODEL = 64; //64のxファイルを配列
Model        g_models[MAXMODEL];
LPDIRECTINPUT8      g_pDI = NULL;
LPDIRECTINPUTDEVICE8 g_pDIDevice = NULL;
char                g_keys[256];



//リソースの解放
void CleanupD3D(){

  for(int i=0; i<MAXMODEL; i=i+1)
  {
    if(g_models[i].used==TRUE)
    {
      if(g_models[i].pmaterials!=NULL)
      {
        delete[] g_models[i].pmaterials;
      }
      if(g_models[i].ptextures!=NULL)
      {
        for(DWORD j=0; j<g_models[i].nummaterials; j=j+1)
        {
          g_models[i].ptextures[j]->Release();
        }
        delete[] g_models[i].ptextures;
      }
      if(g_models[i].pmesh!=NULL)
      {
        g_models[i].pmesh->Release();    
    }
  }
  if(g_pd3dDevice != NULL) g_pd3dDevice->Release();
  if(g_pD3D != NULL) g_pD3D->Release();

  if(g_pDIDevice != NULL)
  {
              g_pDIDevice->Unacquire();
          g_pDIDevice->Release();
        }
        if( g_pDI != NULL) g_pDI->Release();
      }
}

//ウィンドウプロシージャー
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg,WPARAM wParam,LPARAM lParam)
{
  switch(msg)
  {
  case WM_DESTROY:
    CleanupD3D();
    PostQuitMessage(0);
    return 0;
  }

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





HRESULT InitD3DWindow(LPCTSTR wintitle,int w,int h)
{

  ZeroMemory(&g_models,sizeof(Model)*MAXMODEL);
  //ウィンドウクラス作成
  WNDCLASSEX wc = {sizeof(WNDCLASSEX),CS_CLASSDC,MsgProc,0L,0L,GetModuleHandle(NULL),NULL,NULL,NULL,NULL,_T("D3D Window Class"),NULL};
  RegisterClassEx(&wc);
  //ウィンドウ作成
  HWND hWnd = CreateWindow( _T("D3D Window Class"),wintitle,WS_OVERLAPPED | WS_SYSMENU,100,100,w,h,NULL,NULL,wc.hInstance,NULL);

  //ビューポートアスペクトの記録
  g_aspect = (float)w / (float)h;

  //D3D9の作成
  if(NULL==(g_pD3D = Direct3DCreate9( D3D_SDK_VERSION)))
    return E_FAIL;

  //D3Dデバイスの作成
  D3DPRESENT_PARAMETERS d3dpp;
  ZeroMemory(&d3dpp,sizeof(d3dpp));
  d3dpp.Windowed=TRUE;
  d3dpp.SwapEffect= D3DSWAPEFFECT_DISCARD;
  d3dpp.BackBufferFormat=D3DFMT_UNKNOWN;
  d3dpp.EnableAutoDepthStencil=TRUE;
  d3dpp.AutoDepthStencilFormat=D3DFMT_D16;

  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)))
      {
        return E_FAIL;
      }
  }

  //Zバッファをオン
  g_pd3dDevice->SetRenderState(D3DRS_ZENABLE,TRUE);
  ShowWindow(hWnd,SW_SHOWDEFAULT);

  //DirectInputの初期化
  if(FAILED(DirectInput8Create(wc.hInstance,DIRECTINPUT_VERSION,
       IID_IDirectInput8,(void**)&g_pDI,NULL) ) )
     return E_FAIL;
  if(FAILED(g_pDI->CreateDevice(GUID_SysKeyboard, &g_pDIDevice,NULL)))
    return E_FAIL;
    g_pDIDevice->SetDataFormat(&c_dfDIKeyboard);
    g_pDIDevice->SetCooperativeLevel(hWnd,
              DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
  return S_OK;
}


//Xファイルを読み込む関数
int LoadModel(LPCTSTR filename)
{
  int idx;
  for(idx=0; idx<MAXMODEL; idx=idx+1)
  {
    if(g_models[idx].used==FALSE) break;
  }
  if(idx>=MAXMODEL) return -1;

  LPD3DXBUFFER pD3DXMtrlBuffer;

  if(FAILED(D3DXLoadMeshFromX(filename,D3DXMESH_SYSTEMMEM,g_pd3dDevice,NULL,&pD3DXMtrlBuffer,NULL,&g_models[idx].nummaterials,&g_models[idx].pmesh)))
  {
    MessageBox(NULL,_T("Xファイルが見つかりません"),_T("3D lib"),MB_OK);
    return -1;
  }

  //マテリアルとテクスチャ記録用配列確保
  D3DXMATERIAL* d3dxMaterials=
    (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
  int num=g_models[idx].nummaterials;
  g_models[idx].pmaterials=new D3DMATERIAL9[num];
  if(g_models[idx].pmaterials==NULL) return -1;
  g_models[idx].ptextures=new LPDIRECT3DTEXTURE9[num];
  if(g_models[idx].ptextures==NULL) return -1;

  for(int i=0; i<num; i=i+1)
  {
    //マテリアルのコピー
    g_models[idx].pmaterials[i]=d3dxMaterials[i].MatD3D;
    //アンビエント色の設定
    g_models[idx].pmaterials[i].Ambient=
      g_models[idx].pmaterials[i].Diffuse;
    //テクスチャの読み込み
    g_models[idx].ptextures[i] = NULL;
    if(d3dxMaterials[i].pTextureFilename !=NULL&&
      lstrlenA(d3dxMaterials[i].pTextureFilename)>0)
    {
      if(FAILED(D3DXCreateTextureFromFileA(g_pd3dDevice,d3dxMaterials[i].pTextureFilename,&g_models[idx].ptextures[i])))
      {
        MessageBox(NULL,_T("テクスチャが見つかりません"),_T("3D Lib"),MB_OK);
        return -1;
      }
    }
  }

  pD3DXMtrlBuffer->Release();
  g_models[idx].used=TRUE;
  return idx;
}

void RenderModel(int idx)
{
  if(g_models[idx].used==FALSE) return;

  for(DWORD i=0; i<g_models[idx].nummaterials; i=i+1)
  {
    g_pd3dDevice->SetMaterial(&g_models[idx].pmaterials[i]);
    g_pd3dDevice->SetTexture(0,g_models[idx].ptextures[i]);
    g_models[idx].pmesh->DrawSubset(i);
  }
}

const char *GetKeyState(){
  HRESULT hr = g_pDIDevice->Acquire();
  if((hr==DI_OK) || (hr==S_FALSE)){
    g_pDIDevice->GetDeviceState(sizeof(g_keys), &g_keys);
    return g_keys;
  }
  return NULL;
}

-----------------------------------------main.cpp-----------------------------------------

#include "my3dlib.h"

int modelindex;
float mx =0.0f, mz =2.0f;
DWORD lasttime; //前回のループ終了時間
float looptime = 0; //1ループにかかる時間秒
float speed = 5.0f;//5.0m/s

void SetMatrices(){
    const char *keys = GetKeyState();
    if(keys != NULL){
    if(keys[DIK_UP]&0x80 )    mz = mz + speed * looptime;
    if(keys[DIK_DOWN]&0x80 )  mz = mz - speed * looptime;
    if(keys[DIK_LEFT]&0x80 )  mx = mx - speed * looptime;
    if(keys[DIK_RIGHT]&0x80 ) mx = mx + speed * looptime;
    }

  //ワールド変換
  D3DXMATRIXA16 matWorld1,matWorld2;
    D3DXMatrixTranslation( &matWorld1, mx , 0.0f , mz );
  D3DXMatrixRotationY( &matWorld2 , D3DX_PI);
  matWorld2 *= matWorld1;
  g_pd3dDevice->SetTransform(D3DTS_WORLD,&matWorld2);
  //ビュー変換
  D3DXVECTOR3 vEyePt   (0.0f,3.0f,-5.0f);
  D3DXVECTOR3 vLookatPt(0.0f,0.0f,0.0f);
  D3DXVECTOR3 vUpVec   (0.0f,1.0f,0.0f);
  D3DXMATRIXA16 matView;
  D3DXMatrixLookAtLH(&matView,&vEyePt,&vLookatPt,&vUpVec);
  g_pd3dDevice->SetTransform(D3DTS_VIEW,&matView);
  //射影変換
  D3DXMATRIXA16 matProj;
  D3DXMatrixPerspectiveFovLH( &matProj,D3DX_PI/4,g_aspect,1.0f,100.0f);
  g_pd3dDevice->SetTransform(D3DTS_PROJECTION,&matProj);
}


void Render(){
  g_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
    D3DCOLOR_XRGB(0,0,255),1.0f,0);

  if(SUCCEEDED(g_pd3dDevice->BeginScene()))
  {
    g_pd3dDevice->SetRenderState(D3DRS_AMBIENT,0xfffffff );
    SetMatrices();
    D3DXMATRIXA16 matWorld1,matWorld2;
    D3DXMatrixTranslation(&matWorld1,0.0f,0.0f,1.0f);
    D3DXMatrixRotationY( &matWorld2, D3DX_PI);
    matWorld2*= matWorld1;
    g_pd3dDevice->SetTransform( D3DTS_WORLD,&matWorld2);



    RenderModel(modelindex);
    g_pd3dDevice->EndScene();
  }

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

//WinMain関数
INT WINAPI WinMain( HINSTANCE hInst,HINSTANCE,LPSTR,INT)
{
  if(SUCCEEDED(InitD3DWindow(_T("My3DLibTest"),640,480)))
  {
    modelindex= LoadModel(_T("catsenkan.x"));
    if(modelindex==-1) return 0;
    //メッセージループ
    lasttime = timeGetTime();//ループ直前の時間を計測
    MSG msg = {0};
    while(msg.message!=WM_QUIT)
    {
      if(PeekMessage(&msg,NULL,0U,0U,PM_REMOVE))
      {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }

      else
      {  Render();

        DWORD curtime = timeGetTime();
        looptime = (float)(curtime - lasttime)/1000.0f;
        lasttime = curtime;
      }
    }
  }
  

  UnregisterClass(_T("D3D Window Class"),GetModuleHandle(NULL));
  return 0;
}

編集 削除
きのこ  2011-03-31 01:12:07  No: 72529  IP: 192.*.*.*

>if(keys[DIK_UP]&0x80 )    mz = mz + speed * looptime;
>if(keys[DIK_DOWN]&0x80 )  mz = mz - speed * looptime;
>if(keys[DIK_LEFT]&0x80 )  mx = mx - speed * looptime;
>if(keys[DIK_RIGHT]&0x80 ) mx = mx + speed * looptime;
ここを

if(keys[DIK_UP]&0x80 )    mz = mz + 0.5F;
if(keys[DIK_DOWN]&0x80 )  mz = mz - 0.5F;
if(keys[DIK_LEFT]&0x80 )  mx = mx - 0.5F;
if(keys[DIK_RIGHT]&0x80 ) mx = mx + 0.5F;

にしたらどうなりますか?
もしこれで動くなら、原因はspeed * looptime;で、おそらく
looptime = (float)(curtime - lasttime)/1000.0f;
の結果が想定よりも小さい値になっているのかもしれません。

余談ですがソースを全部載せて質問するより
載せる部分をある程度しぼって質問する方が
レスが付きやすいかも。

編集 削除
円盤宇宙  2011-03-31 12:42:36  No: 72530  IP: 192.*.*.*

解答ありがとうございました。
>if(keys[DIK_UP]&0x80 )    mz = mz + 0.5F;
>if(keys[DIK_DOWN]&0x80 )  mz = mz - 0.5F;
>if(keys[DIK_LEFT]&0x80 )  mx = mx - 0.5F;
>if(keys[DIK_RIGHT]&0x80 ) mx = mx + 0.5F;

>にしたらどうなりますか?
すみません、動きませんでした。

また、書き忘れましたが、CGを表示するプログラムを終了した後に"read"になることはできませんでしたのエラーがでます

>余談ですがソースを全部載せて質問するより>
>載せる部分をある程度しぼって質問する方が
>レスが付きやすいかも。
そうですね、次からそうしてみます。

編集 削除
宇宙円盤  2011-03-31 16:33:14  No: 72531  IP: 192.*.*.*

↑すみません、名前間違えました
宇宙円盤です

編集 削除
きのこ  2011-04-01 01:07:09  No: 72532  IP: 192.*.*.*

となると、念のためキー入力がきちんと認識できているかブレークポイントを
設定して確認してみてください。(目的の行でF9キーを押して設定もしくは解除)

if(keys[DIK_UP]&0x80 )    mz = mz + speed * looptime;
↓変形
if(keys[DIK_UP]&0x80 ){
mz = mz + speed * looptime;// ここにブレークポイントを設定
}

キー入力が認識できているのならば、mxやmzの使いどころに問題があるのかも。

    D3DXMatrixTranslation( &matWorld1, mx , 0.0f , mz );

部分をコメントアウトし、Render()関数内を

D3DXMatrixTranslation(&matWorld1,0.0f,0.0f,1.0f);

D3DXMatrixTranslation(&matWorld1, mx , 0.0f , mz);

このようにしてみてください。
mxやmzはメッシュオブジェクトをレンダリングする直前で使用する方が
オブジェクトを動かすという意味では合っている気がします。

>終了した後に"read"になることはできませんでしたのエラーがでます

終了処理内で解放後のポインタもしくは、NULLになっているポインタを
使用している箇所があるのかもしれません。

CleanupD3D()にブレークポイントを設定して、F10キーでたどって
どこで落ちているのか確認してみてください。

編集 削除
宇宙円盤  2011-04-01 04:48:58  No: 72533  IP: 192.*.*.*

ありがとうございます!
>D3DXMatrixTranslation( &matWorld1, mx , 0.0f , mz );
>部分をコメントアウトし、Render()関数内を
>D3DXMatrixTranslation(&matWorld1,0.0f,0.0f,1.0f);

>D3DXMatrixTranslation(&matWorld1, mx , 0.0f , mz);
こちらを実行したところ、無事動かすことが出来ますた。

readのエラーは特に今のところエラーが出る以外の支障はないので
そのまま進めていこうと思います。
助かりました

編集 削除