1. 程式人生 > >【遊戲程式設計】音樂播放

【遊戲程式設計】音樂播放

一直不知道如何播放遊戲音樂。以前做的遊戲只要加上音效就會變的非常的卡頓也不知道為啥。

UltramanGaia520這裡學習瞭如果正確的播放遊戲音樂以及音效等。

傳送門:音樂播放

執行效果:

原始碼:

#include <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define WINDOW_TITLE L"Direct 3D 音樂播放"
#define SAFE_RELEASE(p) { if(p) {(p)->Release(); (p) = NULL;}}										//銷燬指標
//---------------------------------------【全域性變數宣告部分】------------------------------------------------
//描述:全域性變數的宣告
//-----------------------------------------------------------------------------------------------------------
LPDIRECT3DDEVICE9 g_pd3dDevice;																//Direct 3D裝置物件
LPD3DXFONT g_pTextHelper;																	//幫助文字的2D文字
LPD3DXFONT g_pTextFPS;																		//FPS文字的2D文字
wchar_t g_strFPS[50];																		//包含幀頻率的字元陣列

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT Direct3D_Init(HWND);													//在這個函式中繼續Direct3D的初始化
HRESULT Objects_Init(HWND);														//在這個函式中進行要繪製的物體的資源初始化
void Direct3D_Render(HWND);														//在這個函式中進行Direct3D渲染程式碼的書寫
void Direct3D_ClearUp();														//在這個函式中清理COM資源以及其他資源
float Get_FPS();
void HelpText_Render(HWND);
void LoadMusic();
//----------------------------------------【WinMain()函式】-------------------------------------------------
//描述:Windows應用程式的入口函式
//-------------------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wndClass = {0};
	wndClass.cbSize = sizeof(WNDCLASSEX);
	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = (WNDPROC)WndProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = (HICON)LoadImage(NULL, L"icon.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = L"3DGameBase";
	if(!RegisterClassEx(&wndClass))
		return -1;

	HWND hWnd = CreateWindow(L"3DGameBase", WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 
		WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
	MoveWindow(hWnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true);
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	LoadMusic();																		//音樂資源載入
	mciSendString(L"play bgm repeat", NULL, 0, NULL);									//播放背景音樂
	
	if(FAILED(Direct3D_Init(hWnd)))
		MessageBox(hWnd, L"Direct3D 初始化失敗!", L"訊息視窗", 0);
	MSG msg = {0};
	while(msg.message != WM_QUIT)
	{
		if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
			Direct3D_Render(hWnd);
	}

	UnregisterClass(L"3DGameBase", wndClass.hInstance);
	return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch(message)
	{
	case WM_PAINT:
		Direct3D_Render(hWnd);
		ValidateRect(hWnd, NULL);													//使視窗區域生效
		break;
	case WM_KEYDOWN:
		if(wParam == VK_ESCAPE)
			DestroyWindow(hWnd);
		switch(wParam)																//播放各種音效
		{
		case VK_NUMPAD1:
			mciSendString(L"play bullet from 0", NULL, 0, NULL);
			break;
		case VK_NUMPAD2:
			mciSendString(L"play coin from 0", NULL, 0, NULL);
			break;
		case VK_NUMPAD3:
			mciSendString(L"play jump from 0", NULL, 0, NULL);
			break;
		case VK_NUMPAD4:
			mciSendString(L"play hit_enemy from 0", NULL, 0, NULL);
			break;
		case VK_NUMPAD5:
			mciSendString(L"play hit_wall from 0", NULL, 0, NULL);
			break;
		case VK_NUMPAD6:
			mciSendString(L"play hit_brick from 0", NULL, 0, NULL);
			break;
		case VK_NUMPAD7:
			mciSendString(L"play step from 0", NULL, 0, NULL);
			break;
		case VK_NUMPAD8:
			mciSendString(L"play arm from 0", NULL, 0, NULL);
			break;
		case VK_NUMPAD9:
			mciSendString(L"play dead1 from 0", NULL, 0, NULL);
			break;
		case VK_NUMPAD0:
			mciSendString(L"stop bgm", NULL, 0, NULL); 
			mciSendString(L"play gameover from 0", NULL, 0, NULL);
			break;
		}
		break;
	case WM_DESTROY:
		//呼叫自定義的資源清理函式Direct3D_ClearUp();進行退出前的資源清理
		Direct3D_ClearUp();
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}

	return 0;
}
//---------------------------------------------【Direct3D_Init()函式】-----------------------------------------
//描述:Direct3D初始化函式,進行Direct3D的初始化
//---------------------------------------------------------------------------------------------------------------
HRESULT Direct3D_Init(HWND hWnd)
{
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D初始化步驟一】:建立Direct3D介面物件,以便用該Direct3D物件建立Direct3D裝置物件
	//---------------------------------------------------------------------------------------------------------------
	LPDIRECT3D9 pD3D = NULL; //Direct3D介面物件的建立。

	if((pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)						//初始化Direct3D介面物件,並進行DirectX版本協商。
		return E_FAIL;
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D初始化步驟二】:獲取硬體裝置資訊
	//---------------------------------------------------------------------------------------------------------------
	D3DCAPS9 caps;
	int vp = 0;
	if(FAILED(pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps))) 
		return E_FAIL;
	if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
		vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;								//支援硬體頂點運算,採用硬體頂點運算
	else
		vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;								//不支援硬體頂點運算,採用軟體頂點運算

	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D初始化步驟三】:填充D3DPRESENT_PARAMETERS結構體
	//---------------------------------------------------------------------------------------------------------------
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));

	d3dpp.BackBufferWidth = WINDOW_WIDTH;
	d3dpp.BackBufferHeight = WINDOW_HEIGHT;
	d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
	d3dpp.BackBufferCount = 1;
	d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
	d3dpp.MultiSampleQuality = 0;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow = hWnd;
	d3dpp.Windowed = true;
	d3dpp.EnableAutoDepthStencil = true;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
	d3dpp.Flags = 0;
	d3dpp.FullScreen_RefreshRateInHz = 0;
	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D初始化步驟四】:建立Direct3D裝置介面。
	//---------------------------------------------------------------------------------------------------------------
	if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, vp, &d3dpp, &g_pd3dDevice)))
		return E_FAIL;

	SAFE_RELEASE(pD3D);														//LPDIRECT3D9介面物件的使命完成,將其釋放掉
	if(FAILED(Objects_Init(hWnd)))											// 呼叫一次Objects_Init,進行渲染資源的初始化
		return E_FAIL;

	return S_OK;
}
//---------------------------------------------【LoadMusic()()函式】-----------------------------------------
//描述:進行遊戲音樂資源的載入
//---------------------------------------------------------------------------------------------------------------
void LoadMusic()
{
	mciSendString(L"open Musics\\背景音樂.mp3 alias bgm", NULL, 0, NULL);
    mciSendString(L"open Musics\\子彈.mp3 alias bullet", NULL, 0, NULL);
    mciSendString(L"open Musics\\金幣.mp3 alias coin", NULL, 0, NULL);
    mciSendString(L"open Musics\\跳.mp3 alias jump", NULL, 0, NULL);
    mciSendString(L"open Musics\\子彈打到敵人.mp3 alias hit_enemy", NULL, 0, NULL);
    mciSendString(L"open Musics\\子彈撞牆.mp3 alias hit_wall", NULL, 0, NULL);
    mciSendString(L"open Musics\\撞擊磚塊.mp3 alias hit_brick", NULL, 0, NULL);
    mciSendString(L"open Musics\\踩敵人.mp3 alias step", NULL, 0, NULL);
    mciSendString(L"open Musics\\吃到武器.mp3 alias arm", NULL, 0, NULL);
    mciSendString(L"open Musics\\死亡1.mp3 alias dead1", NULL, 0, NULL);
    mciSendString(L"open Musics\\遊戲結束.mp3 alias gameover", NULL, 0, NULL);
}

//------------------------------------------【Objects_Init()】函式---------------------------------------------
//描述:渲染資源初始化函式,在此函式中進行要被渲染的物體的資源的初始化
//---------------------------------------------------------------------------------------------------------------
HRESULT Objects_Init(HWND hWnd)
{
	if(FAILED(D3DXCreateFont(g_pd3dDevice, 36, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, 
													DEFAULT_QUALITY, 0, L"Calibri", &g_pTextFPS)))
		return E_FAIL;
	if(FAILED(D3DXCreateFont(g_pd3dDevice, 23, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
													DEFAULT_QUALITY, 0, L"微軟雅黑", &g_pTextHelper)))
		return E_FAIL;

	return S_OK;
}
//-----------------------------------------【Get_FPS()函式】---------------------------------------------------
//描述:用於計算幀頻率
//---------------------------------------------------------------------------------------------------------------
float Get_FPS()
{
	//定義四個靜態變數
	static int frameCount = 0;																	//幀數
	static float currentTime = 0;																//當前時間 
	static float lastTime = 0;																	//上次計算幀頻率的時間
	static float fps = 0;																		//需要計算的fps值
	
	++frameCount;																				//每呼叫一次此函式,幀數加一
	//獲取系統時間, timeGetTime() 返回系統時間,以毫秒為單位,乘以0.001得到秒
	currentTime = timeGetTime() * 0.001f;												
	//如果當前時間減去之前計算幀頻率的時間大於1秒鐘,就進行幀頻率的更新,並將幀數歸零
	if(currentTime - lastTime > 1.0f)															//將時間控制在1秒鐘
	{
		fps = frameCount / (currentTime - lastTime);											//計算這一秒的fps值
		frameCount = 0;																			//將本次幀數清零
		lastTime = currentTime;								//將當前時間賦給上次計算幀頻率的時間,作為下一秒的基準時間
	}

	return fps;
}

//----------------------------------------【HelpText_Render()函式】--------------------------------------------
//描述:封裝了幫助資訊的函式
//---------------------------------------------------------------------------------------------------------------
void HelpText_Render(HWND hWnd)
{
	//定義一個矩形,用來獲取主視窗矩形
	RECT formatRect;
	GetClientRect(hWnd, &formatRect);
	//在視窗右上角處,顯示每秒幀數  
	swprintf_s(g_strFPS, L"FPS:%.3f", Get_FPS());
	g_pTextFPS->DrawText(0, g_strFPS, -1, &formatRect, DT_TOP | DT_RIGHT, D3DCOLOR_XRGB(255,255,255));
	//在縱座標100處,寫第一段文字
    formatRect.top = 100;//指定文字的縱座標
    g_pTextHelper->DrawText(0, _T("開始時迴圈播放背景音樂\n按數字鍵1,2,3....\n分別對應播放  發射子彈,吃到金幣,跳,子彈打到敵人,\n子彈打到牆,撞擊磚塊,踩敵人,吃到花可以用武器,死亡,遊戲結束"), -1, &formatRect, DT_LEFT|DT_BOTTOM, 
        D3DCOLOR_XRGB(68,139,256));
}

//----------------------------------------【Direct3D_Render()函式】--------------------------------------------
//描述:使用Direct3D進行渲染
//---------------------------------------------------------------------------------------------------------------
void Direct3D_Render(HWND hWnd)
{
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步驟一】:清屏操作
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
	//定義一個矩形,用來獲取主視窗矩形
	RECT formatRect;
	GetClientRect(hWnd, &formatRect);
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步驟二】:開始繪製
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->BeginScene();																				//開始繪製
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步驟三】:正式繪製
	//---------------------------------------------------------------------------------------------------------------
	HelpText_Render(hWnd);
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步驟四】:結束繪製
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->EndScene();																				//結束繪製
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步驟五】:顯示翻轉
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->Present(NULL, NULL, NULL, NULL);															//翻轉與顯示
}
//------------------------------------------------【 Direct3D_ClearUp函式】------------------------------------------
//描述:資源清理函式,在此函式中進行程式退出前資源的清理工作
//-------------------------------------------------------------------------------------------------------------------
void Direct3D_ClearUp()
{
	SAFE_RELEASE(g_pd3dDevice);
	//釋放COM介面物件
	SAFE_RELEASE(g_pTextHelper);
	SAFE_RELEASE(g_pTextFPS);
}