キャラデータ
※この圧縮ファイルを解凍して、できたファイルを下の図のように、
Tuto11で作ったプロジェクトのDebug フォルダにコピーします。
以下プログラムの改造点です。
/* * class CEnemy01 * 敵キャラの実装クラス * * First edition: February.19.2004 * */ #include "stdafx.h" #include <tchar.h> #include <d3dx9.h> #include "D3DQuickLib.h" #include "Mesh.h" #include "Enemy01.h" /*================================================== * 共有メッシュ * 複数の敵キャラインスタンスから参照できるしくみ * を提供する。 ====================================================*/ CMesh *g_pEnemy01Mesh=NULL; //------------------------------------------------------------- // Name: InitEnemy01 // Desc: 共有メッシュへのポインタの初期化 //------------------------------------------------------------- void InitEnemy01Graphics(CD3DEnv *pEnv) { DeleteEnemy01Graphics(); if (g_pEnemy01Mesh == NULL) g_pEnemy01Mesh = new CMesh(pEnv,"smile.x"); } //------------------------------------------------------------- // Name: DeleteEnemy01 // Desc: 共有メッシュへのポインタの初期化 //------------------------------------------------------------- void DeleteEnemy01Graphics() { if (g_pEnemy01Mesh){ delete g_pEnemy01Mesh; g_pEnemy01Mesh = NULL; } } //------------------------------------------------------------- // Name: CEnemy01 // Desc: コンストラクタ //------------------------------------------------------------- CEnemy01::CEnemy01(float x, float z) { float f; f = (float)rand(); f /= (float)(RAND_MAX+1); m_fX = x; m_fZ = z; m_fAngle = D3DX_PI * 2.0f * ((float)rand() / (float)(RAND_MAX + 1)); D3DXMatrixRotationY(&m_matDir,m_fAngle); D3DXMatrixIdentity(&m_matWorld); } CEnemy01::~CEnemy01() { } //------------------------------------------------------------- // Name: Update // Desc: フレーム毎処理(アニメーション) // timeElapsed: 前フレームからの経過時間 // pPos: プレーヤの位置 // 死亡時 true を返す //------------------------------------------------------------- BOOL CEnemy01::Update(float timeElapsed, D3DXVECTOR3 *pPos) { D3DXMATRIX matTmp; D3DXVECTOR3 vecDir = D3DXVECTOR3(0.0f,0.0f,-1.0f); D3DXVECTOR3 vecCross, vecDot; D3DXVECTOR3 vecPlayer; FLOAT fDiff; // // アルゴリズム:単にプレーヤを追いかけるだけ // // 敵キャラから見たプレーヤの位置を算出 vecPlayer.x = pPos->x - m_fX; vecPlayer.z = pPos->z - m_fZ; vecPlayer.y = 0.0f; // ベクトルの長さを1.0 にして、 // プレーヤの位置−>プレーヤのいる方向 D3DXVec3Normalize(&vecPlayer,&vecPlayer); // キャラクタの向きをベクトルで表す。 D3DXVec3TransformCoord(&vecDir,&vecDir,&m_matDir); // キャラクタの向きとプレーヤへの向きから、 // プレーヤを旋回させる角度を算出する。 // 方法:キャラの方向ベクトルとプレーヤへの方向ベクトルとの // ベクトル積(外積)をとり、 // 結果のベクトルが上向きなら、時計回り // 結果のベクトルが下向きなら、反時計回り D3DXVec3Cross(&vecCross,&vecDir, &vecPlayer); // 外積を算出 FLOAT fDot = D3DXVec3Dot(&vecDir,&vecPlayer); // 内積を算出 static const FLOAT fError = sinf(D3DX_PI / 180.0f); if ((fabs(vecCross.y) < fError)&&(fDot > 0)){ // 誤差±1度 fDiff = 0.0f; }else{ fDiff = timeElapsed * (D3DX_PI / 400.0f); if (vecCross.y < 0.0f) fDiff = -fDiff; } m_fAngle += fDiff; D3DXMatrixRotationY(&m_matDir, m_fAngle); fDiff = 0.01f * timeElapsed; // キャラクタの向きに一定量移動する。 vecDir.y = 0; D3DXVECTOR3 vecMotion = vecDir * fDiff; m_fX += vecMotion.x; m_fY += vecMotion.y; m_fZ += vecMotion.z; D3DXMatrixTranslation(&matTmp,m_fX,m_fY,m_fZ); m_matWorld = m_matDir * matTmp; return false; } //------------------------------------------------------------- // Name: Render // Desc: 描画処理 //------------------------------------------------------------- void CEnemy01::Render(LPDIRECT3DDEVICE9 lpd3ddev) { lpd3ddev->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE); lpd3ddev->SetRenderState(D3DRS_LIGHTING, TRUE ); lpd3ddev->SetTransform( D3DTS_WORLD, &m_matWorld ); g_pEnemy01Mesh->Render(lpd3ddev); }
/* * class CEnemy * 敵キャラの実装クラス * * First edition: February.19.2004 * */ #ifndef __ENEMY01_H__ #define __ENEMY01_H__ class CEnemy01 { public: CEnemy01(float x, float y); virtual ~CEnemy01(); BOOL Update(float timeElapsed,D3DXVECTOR3 *pPos); void Render(LPDIRECT3DDEVICE9 lpd3ddev); private: D3DXMATRIX m_matWorld; // ワールド座標への変換行列 D3DXMATRIX m_matDir; // キャラクタの向きを表す行列 FLOAT m_fAngle; // キャラクタの向き FLOAT m_fX; // キャラクタの座標 FLOAT m_fY; // キャラクタの座標 FLOAT m_fZ; // キャラクタの座標 }; // グラフィックスデータは敵キャラクタクラスとは別に初期化する。 extern void InitEnemy01Graphics(CD3DEnv *pEnv); extern void DeleteEnemy01Graphics(); #endif
#include "stdafx.h" #include <stdio.h> #include <d3dx9.h> #include "D3DQuickLib.h" #include "Enemy01.h" CD3DEnv *g_pD3DEnv = NULL; // D3DQuickLib が提供する描画環境。 CFloor *g_pFloor = NULL; CEnhancedMesh *g_pMesh = NULL; // D3DQuickLib によるモデリングクラス。 float g_fTime = 0; // アニメーションで使用する CEnemy01 *g_pEnemy01 = NULL; D3DXVECTOR3 g_vPos = D3DXVECTOR3(0,0,0); D3DXVECTOR3 g_vDir = D3DXVECTOR3(0,0,1.0f); FLOAT g_fAngle = 0.0f; LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam); //------------------------------------------------------------ // Name: FrameMove // Desc: アニメーションを行う。 // UpdateScene 関数 からコールバックされる。 //------------------------------------------------------------ void FrameMove(float timeElapsed) { g_fTime += timeElapsed; if (g_fTime > 600.0f) g_fTime -= 600.0f; D3DXMATRIX *pView; pView = g_pD3DEnv->GetSystemView(); D3DXVECTOR3 vecDir = D3DXVECTOR3(0,0,0); if (g_pD3DEnv->GetDI8KeyState(DIK_LEFT)){ vecDir.x -= 1.0f; g_vPos.x -= 0.1f * timeElapsed; } if (g_pD3DEnv->GetDI8KeyState(DIK_RIGHT)){ vecDir.x += 1.0f; g_vPos.x += 0.1f * timeElapsed; } if (g_pD3DEnv->GetDI8KeyState(DIK_UP)){ vecDir.z += 1.0f; g_vPos.z += 0.1f * timeElapsed; } if (g_pD3DEnv->GetDI8KeyState(DIK_DOWN)){ vecDir.z -= 1.0f; g_vPos.z -= 0.1f * timeElapsed; } FLOAT fTmp = vecDir.x * vecDir.x; fTmp += vecDir.z * vecDir.z; if (fTmp > 0){ D3DXMATRIX matRot; FLOAT fDot; D3DXVECTOR3 vCross; D3DXVec3Normalize(&vecDir,&vecDir); D3DXVec3Cross(&vCross,&vecDir,&g_vDir); fDot = D3DXVec3Dot(&vecDir,&g_vDir); static const FLOAT fError = sinf(D3DX_PI / 180.0f); if ((fabs(vCross.y) > fError)||(fDot < 0)){ if (vCross.y > 0){ fTmp = -0.1f * timeElapsed; }else{ fTmp = 0.1f * timeElapsed; } D3DXMatrixRotationY(&matRot,fTmp); D3DXVECTOR4 vec4Tmp; D3DXVec3Transform(&vec4Tmp,&g_vDir,&matRot); g_vDir = (D3DXVECTOR3)vec4Tmp; D3DXVec3Normalize(&g_vDir,&g_vDir); }else{ g_vDir = vecDir; } } D3DXVECTOR3 vecMin, vecMax, vecNormal; FLOAT fAlt,fDist; g_pFloor->GetBoundingBox(&vecMin, &vecMax); // かならず当たり判定を行う。 g_pFloor->ProbeTheGroundAltitude(&g_vPos,&vecMin,&vecMax,&vecNormal,&fAlt,&fDist); g_vPos.y = fAlt; D3DXMatrixLookAtLH(pView,&D3DXVECTOR3(g_vPos.x,g_vPos.y+2.0f,g_vPos.z-10.0f), // カメラの位置 &D3DXVECTOR3( g_vPos.x, g_vPos.y, g_vPos.z ), // カメラを向ける位置 &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) ); // カメラの上を示す if (g_pEnemy01){ g_pEnemy01->Update(timeElapsed,&g_vPos); } } //------------------------------------------------------------ // Name: RenderScene // Desc: レンダリングを行う。 // UpdateScene 関数 からコールバックされる。 //------------------------------------------------------------ void RenderScene(LPDIRECT3DDEVICE9 lpd3ddev) { D3DXMATRIX matWorld; D3DXMatrixIdentity(&matWorld); lpd3ddev->SetTransform( D3DTS_WORLD, &matWorld ); lpd3ddev->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE); lpd3ddev->SetRenderState(D3DRS_LIGHTING, TRUE ); g_pFloor->Render(lpd3ddev); D3DXMatrixTranslation(&matWorld,g_vPos.x,g_vPos.y,g_vPos.z); D3DXMATRIX matRotation; matRotation._11 = g_vDir.z; matRotation._12 = 0; matRotation._13 = -g_vDir.x; matRotation._14 = 0; matRotation._21 = 0; matRotation._22 = 1.0f; matRotation._23 = 0; matRotation._24 = 0; matRotation._31 = g_vDir.x; matRotation._32 = 0; matRotation._33 = g_vDir.z; matRotation._34 = 0; matRotation._41 = 0; matRotation._42 = 0; matRotation._43 = 0; matRotation._44 = 1.0f; matWorld = matRotation * matWorld; lpd3ddev->SetTransform( D3DTS_WORLD, &matWorld); g_pMesh->Render(lpd3ddev); if (g_pEnemy01){ g_pEnemy01->Render(lpd3ddev); } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION)); wcex.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = "Game"; wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&wcex); HWND hWnd; hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,wcex.lpszClassName,"Game", WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, CW_USEDEFAULT,0,640,480,NULL,NULL,hInstance,NULL); if( !hWnd ) return FALSE; RECT bounds,client; GetWindowRect(hWnd,&bounds); GetClientRect(hWnd,&client); MoveWindow(hWnd,bounds.left,bounds.top, 640 * 2 - client.right, 480 * 2 - client.bottom, false ); ShowWindow( hWnd, nCmdShow ); UpdateWindow( hWnd ); // D3DQuickLib の初期化 g_pD3DEnv = new CD3DEnv(); if (FAILED(g_pD3DEnv->InitD3D(hWnd))){ DestroyWindow(hWnd); }else{ g_pFloor = new CFloor(g_pD3DEnv,"ground\\ground.x"); g_pMesh = new CEnhancedMesh(g_pD3DEnv,"ground\\dog.x"); g_pMesh->SetNumSegs(0); // ポリゴン分割を行わない。 InitEnemy01Graphics(g_pD3DEnv); g_pEnemy01 = new CEnemy01(0,0); g_pD3DEnv->ReloadGraphics(); } MSG msg; while(true){ if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){ if(msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); }else{ g_pD3DEnv->UpdateScene(FrameMove,RenderScene); } } // D3DQuickLib の終了 SAFE_DELETE(g_pEnemy01); DeleteEnemy01Graphics(); SAFE_DELETE(g_pMesh); SAFE_DELETE(g_pFloor); SAFE_DELETE(g_pD3DEnv); return (int)msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { switch (message){ case WM_SIZE: // ウインドウが最大化されたら、フルスクリーンモードにする。 if (SIZE_MAXIMIZED == wParam){ if (g_pD3DEnv->IsWindowed()) g_pD3DEnv->ToggleFullscreen(); } break; case WM_SETCURSOR: // フルスクリーン時はカーソルを表示させない。 if (g_pD3DEnv->IsWindowed()) ::SetCursor(::LoadCursor(NULL,IDC_ARROW)); else ::SetCursor(NULL); break; case WM_SYSCHAR: // Alt-Enter でフルスクリーンモードへ切り替える if (lParam&0x20000000){ if (wParam == '\x0d'){ g_pD3DEnv->ToggleFullscreen(); break; } } return DefWindowProc( hWnd, message, wParam, lParam ); case WM_SYSCOMMAND: if (!g_pD3DEnv->IsWindowed()){ // フルスクリーン時 if (wParam != SC_CLOSE) break; // Windowが閉じられる前にWindowモードに戻しておく。 g_pD3DEnv->ToggleFullscreen(); Sleep(100); } return DefWindowProc( hWnd, message, wParam, lParam ); case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }