- 追加された行はこの色です。
- 削除された行はこの色です。
2Dゲームの最低必要要素である
SIZE(20){ COLOR(#ffaa00){・入力}}
SIZE(20){ COLOR(#ffaa00){・画像表示}}
SIZE(20){ COLOR(#ffaa00){・サウンド再生}}
をやってきました
今回はそれをまとめます
入力は、DirectX講座2回
画像描画は、DirectX講座10回
サウンド再生は、DirectX講座12回
で、すでにやりました
この3つを合体させます
具体的には12回のプログラムに10回のプログラムを合体します
クラスに関しては変更はありません
今回使うファイルは次のようになってます。どぞー(-ω-)つ旦
・&ref(framework.cpp);
・&ref(car.bmp);
・&ref(katana.wav);
・&ref(bomb.wav);
zipでほしい人はこちら
・&ref(framework.zip);
// Direct3Dに必要なヘッダーとライブラリ
#define _CRT_SECURE_NO_WARNINGS
//////////////////////////////////////////////////////////////////////
#define D3D_DEBUG_INFO // Direct3Dデバックフラグ
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "d3dxof.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "winmm.lib")
#include <comdef.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <mmsystem.h>
//////////////////////////////////////////////////////////////////////
// DirectSoundに必要なヘッダーとライブラリ
#define DIRECTSOUND_VERSION 0x800 // DirectSoundのバージョン
#pragma comment(lib, "dsound.lib")
#pragma comment(lib, "d3dxof.lib")
#pragma comment(lib, "dxguid.lib")
#include <comdef.h>
#include <dsound.h>
//////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <tchar.h>
//////////////////////////////////////////////////////////////////////
// Direct3Dクラス
class Direct3D
{
public:
IDirect3D9* pD3D9; // Direct3Dデバイス生成用オブジェクト
IDirect3DDevice9* pDevice3D; // Direct3Dのデバイス
// コンストラクタ
Direct3D();
// デストラクタ
~Direct3D();
// デバイス作成
bool Create(HWND hWnd,int Width,int Height);
};
// コンストラクタ
Direct3D::Direct3D(){
pD3D9 = NULL; // Direct3Dデバイス生成用オブジェクト
pDevice3D = NULL; // Direct3Dのデバイス
}
// デストラクタ
Direct3D::~Direct3D(){
// DirectXの変数は必ず後処理をすること
if(pDevice3D != NULL)
pDevice3D->Release();
if(pD3D9 != NULL)
pD3D9->Release();
}
// デバイス作成
bool Direct3D::Create(HWND hWnd,int Width,int Height){
// Direct3D9オブジェクトの作成
pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
// ディスプレイ情報取得
D3DDISPLAYMODE Display;
pD3D9->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &Display);
D3DPRESENT_PARAMETERS D3DParam = { // スワップチェイン設定
Width,Height,Display.Format,1,D3DMULTISAMPLE_NONE,0,
D3DSWAPEFFECT_DISCARD,hWnd,TRUE,TRUE,D3DFMT_D24S8,0,0,D3DPRESENT_INTERVAL_DEFAULT
};
// HALモードで3Dデバイス作成
if (FAILED(pD3D9->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, D3DParam.hDeviceWindow,
D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, &D3DParam, &pDevice3D)))
if (FAILED(pD3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DParam.hDeviceWindow,
D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, &D3DParam, &pDevice3D)))
// REFモードで3Dデバイス作成
if (FAILED(pD3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, D3DParam.hDeviceWindow,
D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, &D3DParam, &pDevice3D)))
if (FAILED(pD3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, D3DParam.hDeviceWindow,
D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, &D3DParam, &pDevice3D)))
{
// 3Dデバイス作成失敗(このグラフィックボードではDirectXが使えない)
pD3D9->Release();
return false;
}
return true;
}
///////////////////////////////////////////////////////////////////
// テクスチャクラス
class Texture
{
public:
IDirect3DTexture9* pTexture;
// コンストラクタ
Texture();
// デストラクタ
~Texture();
// 画像データ読み込み
bool Load(IDirect3DDevice9* pDevice3D,TCHAR* FileName);
};
Texture::Texture(){
pTexture = NULL;
}
Texture::~Texture()
{
// 読み込まれていたら破棄
if(pTexture != NULL)
pTexture->Release();
}
bool Texture::Load(IDirect3DDevice9* pDevice3D,TCHAR* FileName)
{
// 画像読み込み
// DirextXやWindowsAPIの関数はHRESULTを結果に返す関数が多い
// FAILEDマクロで関数が失敗したかわかる
// SUCEEDEDマクロで関数が成功したかわかる
if(FAILED(D3DXCreateTextureFromFile(pDevice3D,FileName,&pTexture)))
return false; // 画像読み込み失敗(ファイルがない可能性あり)
// 画像読み込み成功
return true;
}
//////////////////////////////////////////////////////////////////////
// スプライトクラス(2D板ポリゴン)
class Sprite
{
public:
// 板ポリゴン頂点情報
struct Vertex{
float x,y,z;// 3次元座標
float rhw; // 2D変換済みフラグ
float u,v; // UV座標
};
// FVF(柔軟な頂点構造体宣言)フラグ
static const DWORD SPRITE_FVF = D3DFVF_XYZRHW | D3DFVF_TEX1;
// スプライト位置
D3DXVECTOR2 pos;
// スプライトサイズ
int width;
int height;
// コンストラクタ
Sprite();
// デストラクタ
~Sprite();
void SetPos(float x,float y);
void SetWidth(int Width,int Height);
void Draw(IDirect3DDevice9* pDevice3D,IDirect3DTexture9* pTexture);
};
// コンストラクタ
Sprite::Sprite()
{
pos.x = pos.y = 0.0f;
width = 0;
height = 0;
}
// デストラクタ
Sprite::~Sprite(){}
void Sprite::SetPos(float x,float y)
{
pos.x = x;
pos.y = y;
}
void Sprite::SetWidth(int Width,int Height)
{
width = Width;
height = Height;
}
void Sprite::Draw(IDirect3DDevice9* pDevice3D,IDirect3DTexture9* pTexture)
{
// 頂点情報セット
Vertex vtx[4]={
{ pos.x + width/2, pos.y - height/2, 0.0f, 1.0f, 1.0f, 0.0f},
{ pos.x + width/2, pos.y + height/2, 0.0f, 1.0f, 1.0f, 1.0f},
{ pos.x - width/2, pos.y - height/2, 0.0f, 1.0f, 0.0f, 0.0f},
{ pos.x - width/2, pos.y + height/2, 0.0f, 1.0f, 0.0f, 1.0f}
};
// テクスチャセット
pDevice3D->SetTexture(0,pTexture);
// 頂点構造体宣言セット
pDevice3D->SetFVF(SPRITE_FVF);
// スプライト描画
pDevice3D->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,2,vtx,sizeof(Vertex));
}
///////////////////////////////////////////
// DirectSoundクラス
class DirectSound
{
public:
IDirectSound8* pDirectSound8; // DirectSoundデバイス
// コンストラクタ
DirectSound();
// デストラクタ
~DirectSound();
bool Create(HWND hWnd);
};
// コンストラクタ
DirectSound::DirectSound()
{
pDirectSound8 = NULL; // DirectSoundデバイス
}
// デストラクタ
DirectSound::~DirectSound()
{
if(pDirectSound8 != NULL)
pDirectSound8->Release();
}
bool DirectSound::Create(HWND hWnd)
{
// サウンドデバイス作成
DirectSoundCreate8(NULL, &pDirectSound8, NULL);
// 協調レベルのセット(ここで音を鳴らすウィンドウを指定する必要がある)
if (FAILED(pDirectSound8->SetCooperativeLevel(hWnd, DSSCL_PRIORITY)))
{
// 失敗
return false;
}
return true;
}
////////////////////////////////////////////
class Wave{
public:
WAVEFORMATEX WaveFormat; // Waveフォーマット
byte* WaveData; // 音の生データ
int DataSize; // データサイズ
// コンストラクタ
Wave();
// デストラクタ
~Wave();
// Wavファイル読み込み
bool Load(TCHAR* FileName);
};
// コンストラクタ
Wave::Wave()
{
memset(&WaveFormat,0,sizeof(WAVEFORMATEX));
WaveData = NULL;
DataSize = 0;
}
// デストラクタ
Wave::~Wave()
{
if(WaveData != NULL)
delete[] WaveData;
}
// Wavファイル読み込み
bool Wave::Load(TCHAR* FileName)
{
// バイナリ読み込みモードで開く
FILE* fp;
if (!(fp = ::_tfopen(FileName, _T("rb") )))
return false;
char chunkId[5] = {};
char tmp[5] = {};
unsigned int chunkSize = 0;
// RIFFチャンク読み込み
fread(chunkId, sizeof(char) * 4, 1, fp);
fread(&chunkSize, sizeof(unsigned int), 1, fp);
fread(tmp, sizeof(char) * 4, 1, fp);
if (strcmp(chunkId, "RIFF") || strcmp(tmp, "WAVE")){
return false; // Waveファイルじゃない
}
// 子チャンク読み込み
bool fmtchunk = false;
bool datachunk = false;
while (true)
{
fread(chunkId, sizeof(char) * 4, 1, fp);
fread(&chunkSize, sizeof(unsigned int), 1, fp);
if (!strcmp(chunkId, "fmt "))
{
if (chunkSize >= sizeof(WAVEFORMATEX))
{
fread(&WaveFormat, sizeof(WAVEFORMATEX), 1, fp);
int diff = chunkSize - sizeof(WAVEFORMATEX);
fseek(fp, diff, SEEK_CUR);
}
else
{
memset(&WaveFormat, 0, sizeof(WAVEFORMATEX));
fread(&WaveFormat, chunkSize, 1, fp);
}
fmtchunk = true;
}
else if (!strcmp(chunkId, "data"))
{
// データサイズ確保
DataSize = chunkSize;
WaveData = new byte[chunkSize];
// データ読み込み
if (fread(WaveData, sizeof(byte), chunkSize, fp) != chunkSize)
{
fclose(fp);
return false; // ファイルが壊れている
}
datachunk = true;
}
else
{
fseek(fp, chunkSize, SEEK_CUR);
}
if (fmtchunk && datachunk)
break;
// ファイルサイズチェックも行なった方がいいかも
}
fclose(fp);
return true;
}
////////////////////////////////////////////////
class SoundBuffer
{
public:
IDirectSoundBuffer8* pSecondaryBuffer; // セカンダリバッファ
// コンストラクタ
SoundBuffer();
// デストラクタ
~SoundBuffer();
bool Create(IDirectSound8* pDirectSound8,WAVEFORMATEX& WaveFormat,byte* WaveData,int DataSize);
void Play(bool isLoop);
void Stop();
};
// コンストラクタ
SoundBuffer::SoundBuffer()
{
pSecondaryBuffer = NULL;
}
// デストラクタ
SoundBuffer::~SoundBuffer()
{
Stop(); // セカンダリバッファは破棄する前に再生停止すること
if(pSecondaryBuffer != NULL)
pSecondaryBuffer->Release();
}
bool SoundBuffer::Create(IDirectSound8* pDirectSound8,WAVEFORMATEX& WaveFormat,byte* WaveData,int DataSize)
{
DSBUFFERDESC desc = {}; // セカンダリバッファ作成用設定
// チャンネル数での分岐、モノラルは1チャンネル、ステレオは2チャンネル
if(WaveFormat.nChannels == 1){
desc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY |
DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_STATIC;
desc.guid3DAlgorithm = DS3DALG_NO_VIRTUALIZATION;
}
else{
desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY |
DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_CTRLPAN | DSBCAPS_STATIC;
// | DSBCAPS_CTRLFX; エフェクトを追加すると Duplicate できない
desc.guid3DAlgorithm = GUID_NULL;
}
desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwBufferBytes = DataSize; // 音データサイズ指定
desc.lpwfxFormat = &WaveFormat; // フォーマット指定
IDirectSoundBuffer* pPrimaryBuffer = NULL; // プライマリバッファ
// プライマリバッファ作成
pDirectSound8->CreateSoundBuffer(&desc,&pPrimaryBuffer,NULL);
// プライマリバッファからセカンダリバッファ作成
pPrimaryBuffer->QueryInterface(IID_IDirectSoundBuffer8, (void**)&pSecondaryBuffer);
pPrimaryBuffer->Release(); // セカンダリバッファが作成できれば、プライマリバッファは破棄してかまわない
unsigned char* block1 = NULL;
unsigned char* block2 = NULL;
unsigned long blockSize1 = 0;
unsigned long blockSize2 = 0;
// セカンダリバッファをロックしてデータ書き込み
pSecondaryBuffer->Lock(0, DataSize,
(void**)&block1, &blockSize1, (void**)&block2, &blockSize2, DSBLOCK_ENTIREBUFFER);
// セカンダリバッファに音データコピー
memcpy(block1, WaveData, DataSize);
// セカンダリバッファロック解除
pSecondaryBuffer->Unlock(block1, blockSize1, block2, 0);
return true;
}
void SoundBuffer::Play(bool isLoop)
{
// サウンド再生
if(pSecondaryBuffer != NULL){
DWORD LoopFlag = (isLoop ? DSBPLAY_LOOPING : 0);
pSecondaryBuffer->Play(0,0,LoopFlag);
}
}
void SoundBuffer::Stop()
{
if(pSecondaryBuffer != NULL)
pSecondaryBuffer->Stop();
}
//////////////////////////////////////////////////////////////////////
// ウィンドウプロシージャ、ウィンドウに対するメッセージ処理を行う
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch(msg){
// ウィンドウが破棄されたとき
case WM_DESTROY:
PostQuitMessage(0); // WM_QUITメッセージをメッセージキューに送る
return 0;
}
// デフォルトのメッセージ処理を行う
return DefWindowProc(hWnd, msg, wParam, lParam);
}
// WinMain関数(アプリケーションの開始関数)
// コンソールアプリケーションと違い、コンソールを開かない
int _stdcall WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
const TCHAR* WC_BASIC = _T("BASIC_WINDOW");
// シンプルウィンドウクラス設定
WNDCLASSEX wcex ={sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,WndProc, 0,0,hInstance,
(HICON)LoadImage(NULL,MAKEINTRESOURCE(IDI_APPLICATION),IMAGE_ICON,0,0,LR_DEFAULTSIZE | LR_SHARED),
(HCURSOR)LoadImage(NULL,MAKEINTRESOURCE(IDC_ARROW),IMAGE_CURSOR,0,0,LR_DEFAULTSIZE | LR_SHARED),
(HBRUSH)GetStockObject(WHITE_BRUSH), NULL, WC_BASIC , NULL};
// シンプルウィンドウクラス作成
if(!RegisterClassEx(&wcex))
return false;
// ウィンドウ幅、高さはディスプレイに依存する。普通は4:3
const int WINDOW_WIDTH = 640;
const int WINDOW_HEIGHT = 480;
// ウィンドウの作成
HWND hWnd = CreateWindowEx(0,WC_BASIC,
_T("Application"), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE,
CW_USEDEFAULT,CW_USEDEFAULT,WINDOW_WIDTH,WINDOW_HEIGHT,NULL,NULL,hInstance,NULL);
///////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////
// Direct3Dの初期化
////////////////////////////////////
Direct3D direct3d;
direct3d.Create(hWnd,WINDOW_WIDTH,WINDOW_HEIGHT);
////////////////////////////////
// テクスチャ作成
////////////////////////////////
Texture cartex;
cartex.Load(direct3d.pDevice3D,_T("car.bmp"));
////////////////////////////////
// スプライト作成
////////////////////////////////
Sprite sprite[2];
sprite[0].SetPos(100,100);
sprite[0].SetWidth(128,128);
sprite[1].SetPos(300,300);
sprite[1].SetWidth(128,128);
///////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////
// DirectSoundデバイス作成
////////////////////////////////
DirectSound directsound;
directsound.Create(hWnd);
///////////////////////////////////////////////
// Waveファイル読込み
///////////////////////////////////////////////
Wave wave[2];
wave[0].Load(_T("katana.wav"));
wave[1].Load(_T("bomb.wav"));
///////////////////ファイル読込みはここまで
/////////////////////////////////
// セカンダリバッファの作成
// (読み込んだ音データをコピー)
/////////////////////////////////
SoundBuffer sb[2];
for(int i = 0;i < 2;++i)
sb[i].Create(directsound.pDirectSound8,wave[i].WaveFormat,wave[i].WaveData,wave[i].DataSize);
// ループ再生
sb[0].Play(true);
///////////////////////////////////////////////////////////////////////////////////////////////
// メッセージループ
MSG msg = {};
while(msg.message != WM_QUIT) {
// アプリケーションに送られてくるメッセージをメッセージキューから取得する
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
DispatchMessage(&msg); // アプリケーションの各ウィンドウプロシージャにメッセージを転送する
}
// メッセージ処理をしていないとき
else{
//(ここにDirectXの処理を書く)
///////////////////////////////////////////////////////////////////////////////////////////////
// 描画開始
if(SUCCEEDED(direct3d.pDevice3D->BeginScene()))
{
DWORD ClearColor = 0xff808080; // 背景クリア色
// 背景クリア
direct3d.pDevice3D->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL | D3DCLEAR_ZBUFFER, ClearColor, 1.0f, 0 );
// 再生
if(GetAsyncKeyState('A'))
sb[1].Play(false);
// スプライト描画
for(int i = 0;i < 2;++i){
sprite[i].Draw(direct3d.pDevice3D,cartex.pTexture);
}
// 描画終了
direct3d.pDevice3D->EndScene();
}
// 描画反映
direct3d.pDevice3D->Present( NULL, NULL, NULL, NULL );
///////////////////////////////////////////////////////////////////////////////////////////////
}
}
return 0;
}
描画は講座10回と変わりません
そこにサウンド再生が加わります
さらにAキーで追加のサウンドを再生します
&ref("framework.jpg");
今回で2Dゲームに最低限必要なものがそろったので
簡単なゲームくらい作れるようになるはずです
そろそろプログラムが長くなってきました(500行越え)
プログラムが長くなってきたら1つのファイルで管理をすることが困難になってきます(見づらい+追加が大変+バグなどが発見しにくい)
なので、次回はC/C++で別ファイルにプログラムを分割する方法を説明します
前:DirectX講座12回
次:DirectX講座14回
#vote( (^σ^)ウマー[2],動けぇぇぇえええ[1],おまえはもう死んでいる[2])
| (^σ^)ウマー|2|
|動けぇぇぇえええ|2|
|おまえはもう死んでいる|2|