ホーム < ゲームつくろー!< 衝突判定編
Havok編
その2 Havok導入!:サンプルプログラム
衝突判定編Havok編その2「Havok導入!」で説明した内容を踏まえたサンプルプログラムです。実行すると、8つのキューブが100m上空から床に向かって自由落下をし、床に当たると弾けます。
サンプルスクリーンショット。直方体がはじけてます!
○ コンパイル方法
Visual Studioで新規プロジェクト(Win32アプリケーション)を作成し、main.cppを追加します。次に下記のプログラムをコピペします。「Havok導入!」で説明したヘッダーとライブラリパスをプロジェクトに設定すると実行できます。
#pragma comment(lib, "hkBase.lib")
#pragma comment(lib, "hkInternal.lib")
#pragma comment(lib, "hkpCollide.lib")
#pragma comment(lib, "hkpconstraintsolver.lib")
#pragma comment(lib, "hkpDynamics.lib")
#pragma comment(lib, "hkpinternal.lib")
#pragma comment(lib, "hkputilities.lib")
#include <Common/Base/keycode.cxx>
#include <Common/Base/hkBase.h>
#include <Common/Base/Memory/System/Util/hkMemoryInitUtil.h>
#include <Physics/Dynamics/World/hkpWorld.h>
#include <Physics/Dynamics/Entity/hkpRigidBody.h>
#include <Physics/Dynamics/Entity/hkpRigidBodyCinfo.h>
#include <Physics/Utilities/Dynamics/Inertia/hkpInertiaTensorComputer.h>
#include <Physics/Collide/Shape/Convex/Box/hkpBoxShape.h>
#include <Physics/Collide/Dispatch/hkpAgentRegisterUtil.h>
#include <windows.h>
#include <tchar.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <stdio.h>
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
// HAvok内でエラーが起きた時によばれます
void HavokErrorReportFunction(const char* s, void* errorReportObject) {}
TCHAR gName[100] = _T("Havokサンプル");
LRESULT CALLBACK WndProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam){
if(mes == WM_DESTROY) {PostQuitMessage(0); return 0;}
return DefWindowProc(hWnd, mes, wParam, lParam);
}
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
// アプリケーションの初期化
MSG msg; HWND hWnd;
WNDCLASSEX wcex ={sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, NULL, NULL, (HBRUSH)(COLOR_WINDOW+1), NULL, (TCHAR*)gName, NULL};
if(!RegisterClassEx(&wcex))
return 0;
if(!(hWnd = CreateWindow(gName, gName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL)))
return 0;
// Direct3Dの初期化
LPDIRECT3D9 g_pD3D;
LPDIRECT3DDEVICE9 g_pD3DDev;
if( !(g_pD3D = Direct3DCreate9( D3D_SDK_VERSION )) ) return 0;
D3DPRESENT_PARAMETERS d3dpp = {0,0,D3DFMT_UNKNOWN,0,D3DMULTISAMPLE_NONE,0,D3DSWAPEFFECT_DISCARD,NULL,TRUE,0,D3DFMT_UNKNOWN,0,0};
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) ) {
g_pD3D->Release();
return 0;
}
ShowWindow(hWnd, nCmdShow);
//////////////////////////////
// Havokの初期化
hkMemoryRouter* memoryRouter = hkMemoryInitUtil::initDefault();
hkBaseSystem::init(memoryRouter, HavokErrorReportFunction);
hkpWorldCinfo info;
info.m_simulationType = hkpWorldCinfo::SIMULATION_TYPE_CONTINUOUS;
info.m_collisionTolerance = 0.001f;
info.setBroadPhaseWorldSize( 10000.0f );
info.setupSolverInfo( hkpWorldCinfo::SOLVER_TYPE_8ITERS_HARD );
info.m_gravity = hkVector4(0.0f, -9.8f, 0.0f);
hkpWorld *world = new hkpWorld(info);
hkpAgentRegisterUtil::registerAllAgents( world->getCollisionDispatcher() );
/////////////////////////////
// 床を作ってみよう
const float groundHalfH = 2.0f;
const hkVector4 halfExtents(2000.0f, groundHalfH, 2000.0f);
hkpBoxShape* groundShape = new hkpBoxShape(halfExtents);
hkpRigidBodyCinfo bodyInfo;
bodyInfo.m_mass = 0.0f;
bodyInfo.m_shape = groundShape;
bodyInfo.m_motionType = hkpMotion::MOTION_FIXED;
bodyInfo.m_position.set(0.0f, -groundHalfH, 0.0f);
hkpRigidBody* groundBody = new hkpRigidBody(bodyInfo);
groundShape->removeReference();
world->addEntity(groundBody);
groundBody->removeReference();
//////////////////////////////
// Boxを作ってみよう
const float bx = 1.0f, by = 2.0f, bz = 1.0f;
const int nx = 2, ny = 2, nz = 2;
const int NUM_BODIES = nx * ny * nz;
hkpRigidBody *bodies[NUM_BODIES];
{
const hkVector4 halfExtents(bx, by, bz);
hkpShape* shape = new hkpBoxShape(halfExtents, 0.0f);
hkpMassProperties massProperties;
hkpInertiaTensorComputer::computeShapeVolumeMassProperties(shape, 5.0f, massProperties);
hkpRigidBodyCinfo bodyInfo;
bodyInfo.m_mass = massProperties.m_mass;
bodyInfo.m_centerOfMass = massProperties.m_centerOfMass;
bodyInfo.m_inertiaTensor = massProperties.m_inertiaTensor;
bodyInfo.m_shape = shape;
bodyInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA;
int i = 0;
for(int x = 0; x < nx; x++)
for(int y = 0; y < ny; y++)
for(int z = 0; z < nz; z++) {
hkpRigidBody *body = new hkpRigidBody(bodyInfo);
body->setPosition(hkVector4(x * bx * 2, 100.0f + y * by * 2, z * bz * 2));
bodies[i] = body;
world->addEntity(body);
body->removeReference();
i++;
}
shape->removeReference();
}
////////////////////////////////////
// 床、Boxモデル作成
ID3DXMesh *floor, *box;
D3DXCreateBox(g_pD3DDev, bx * 2, by * 2, bz * 2, &box, 0);
D3DXCreateBox(g_pD3DDev, 4000.0f, groundHalfH * 2.0f, 4000.0f, &floor, 0);
// ID3DXFontコンポーネント生成
int fontsize = 24;
D3DXFONT_DESC lf = {fontsize, 0, 0, 1, 0, SHIFTJIS_CHARSET, OUT_TT_ONLY_PRECIS, PROOF_QUALITY, FIXED_PITCH | FF_MODERN, _T("MS ゴシック")};
LPD3DXFONT pD3DFont;
if(FAILED(D3DXCreateFontIndirect(g_pD3DDev, &lf, &pD3DFont))) {
g_pD3DDev->Release(); g_pD3D->Release();
return 0;
}
// 変換行列
D3DXMATRIX view, proj;
D3DXMatrixPerspectiveFovLH( &proj, D3DXToRadian(45), 640.0f/480.0f, 1.0f, 10000.0f);
g_pD3DDev->SetTransform(D3DTS_PROJECTION, &proj);
// ライト
D3DLIGHT9 light;
ZeroMemory(&light, sizeof(D3DLIGHT9));
light.Direction = D3DXVECTOR3(-1, -2, 0.5);
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse.r = 0.7f;
light.Diffuse.g = 0.7f;
light.Diffuse.b = 0.7f;
light.Diffuse.a = 1.0f;
g_pD3DDev->SetLight( 0, &light );
g_pD3DDev->LightEnable( 0, true );
g_pD3DDev->SetRenderState( D3DRS_LIGHTING, TRUE );
g_pD3DDev->SetRenderState( D3DRS_AMBIENT, 0x00808080 ); // アンビエントライト
// マテリアル
D3DMATERIAL9 ground_material = {
{1.0f, 1.0f, 1.0f, 1.0f},
{0.2f, 0.2f, 0.2f, 1.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
10.0f
};
D3DMATERIAL9 cube_material = {
{0.7f, 1.0f, 0.7f, 1.0f},
{0.2f, 0.2f, 0.2f, 1.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
10.0f
};
// メッセージ ループ
float tm = 0.0f;
do{
if( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ){
DispatchMessage(&msg);
}
else {
tm += 1.0f/60.0f;
world->stepDeltaTime(1.0f/60.0f);
// 1つのリジッドに注視します
hkVector4 pos = bodies[0]->getPosition();
{
const hkTransform &trans = bodies[0]->getTransform();
const hkVector4 &t = trans.getTranslation();
D3DXMatrixLookAtLH(&view, &D3DXVECTOR3(0.0f, 50.0f, -25.0f), &D3DXVECTOR3(t(0), t(1), t(2)), &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
g_pD3DDev->SetTransform(D3DTS_VIEW, &view);
}
char c[128];
sprintf(c, "Pos(%f, %f, %f) %5.1f sec.", pos(0), pos(1), pos(2), tm);
// Direct3Dの処理
g_pD3DDev->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
g_pD3DDev->BeginScene();
// 床描画
{
const hkTransform &t = groundBody->getTransform();
D3DXMATRIX transMat(
t(0,0), t(1,0), t(2,0), 0.0f,
t(0,1), t(1,1), t(2,1), 0.0f,
t(0,2), t(1,2), t(2,2), 0.0f,
t(0,3), t(1,3), t(2,3), 1.0f);
g_pD3DDev->SetTransform(D3DTS_WORLD, &transMat);
g_pD3DDev->SetMaterial(&ground_material);
floor->DrawSubset(0);
}
// キューブ描画
{
for (int i = 0; i < NUM_BODIES; i++) {
const hkTransform &t = bodies[i]->getTransform();
D3DXMATRIX transMat(
t(0,0), t(1,0), t(2,0), 0.0f,
t(0,1), t(1,1), t(2,1), 0.0f,
t(0,2), t(1,2), t(2,2), 0.0f,
t(0,3), t(1,3), t(2,3), 1.0f);
g_pD3DDev->SetTransform(D3DTS_WORLD, &transMat);
g_pD3DDev->SetMaterial(&cube_material);
box->DrawSubset(0);
}
}
// 位置描画
RECT rc = {0, 0, 0, 0};
pD3DFont->DrawTextA(NULL, c, -1, &rc, DT_LEFT | DT_SINGLELINE | DT_NOCLIP, 0xffffffff);
g_pD3DDev->EndScene();
g_pD3DDev->Present( NULL, NULL, NULL, NULL );
}
} while(msg.message != WM_QUIT);
// 後片付け
delete world;
hkBaseSystem::quit();
hkMemoryInitUtil::quit();
floor->Release();
box->Release();
pD3DFont->Release();
g_pD3DDev->Release();
g_pD3D->Release();
return 0;
}