利用C++創建一個遊戲(4)計算機角色動畫(代碼+註釋)

一、 計算機角色的簡單動畫 

先是使用Windows本身定時器創建程序的代碼:

#include "stdafx.h"    
#include "MyGameFrame.h"    
#include <stdio.h>        

// 全局變量:     
HINSTANCE hInst;
HWND      hWnd;
HDC       hdc, mdc;
HBITMAP   horse[8];       //圖像位圖
int       num;            //當前圖像幀數

// 此代碼模塊中包含的函數的前向聲明:     
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitWindow(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);


int APIENTRY WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR    lpCmdLine,
	int       nCmdShow)
{
	// 初始化全局字符串    
	MyRegisterClass(hInstance);


	// 執行應用程序初始化:     
	if (!InitWindow(hInstance, nCmdShow))//初始化窗口    
	{
		return FALSE;//如果不成功則返回FALSE,並退出程序    
	}

	MSG msg; //創建消息類對象 

	char filename[20] = "";

	int i;

	hdc = GetDC(hWnd);
	mdc = CreateCompatibleDC(hdc);
        
        //加載位圖
	for (i = 0; i<8; i++) { 
	sprintf_s(filename, "horse%d.bmp", i);
		horse[i] = (HBITMAP)LoadImage(NULL, filename, IMAGE_BITMAP, 405, 300, LR_LOADFROMFILE);
	}


	num = 0;


	//創建定時器
	SetTimer(hWnd, 1, 60, NULL);


	SelectObject(mdc, horse[num]);
	BitBlt(hdc, 0, 0, 405, 300, mdc, 0, 0, SRCCOPY);
	num++;


	PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);//賦初值    


	while (msg.message != WM_QUIT)         //進入遊戲消息循環:    
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg); //獲得遊戲玩家輸入的消息;    
			DispatchMessage(&msg);//分配玩家消息並響應用戶消息。    
		}
	}

	return (int)msg.wParam;
}


ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex =
	{
		wcex.cbSize = sizeof(WNDCLASSEX),
		CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
		WndProc,0,0,
		hInstance,
		LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYGAMEFRAME)),
		LoadCursor(NULL, IDC_ARROW),
		(HBRUSH)(COLOR_WINDOW + 1),NULL,
		_T("GameFrame"),
		LoadIcon(NULL,MAKEINTRESOURCE(IDI_SMALL))
	};
	return RegisterClassEx(&wcex);
}


BOOL InitWindow(HINSTANCE hInstance, int nCmdShow)
{
	hInst = hInstance; // 將實例句柄存儲在全局變量中          
    hWnd = CreateWindow
	(
		_T("GameFrame"),
		_T("遊戲框架"),
		WS_OVERLAPPEDWINDOW^WS_THICKFRAME^WS_MAXIMIZEBOX,//普通樣式,不能改變大小,不能最大化    
		CW_USEDEFAULT, CW_USEDEFAULT, 405, 300, nullptr, nullptr, hInstance, nullptr
	);


	if (!hWnd)
	{
		return FALSE;
	}


	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);


	return TRUE;
}


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{  
	switch (msg)                        //判斷消息    
	{
	case WM_CREATE:
		//執行初始化代碼                  
		return(0);
		break;
	case WM_TIMER:
		if (num == 8)
			num = 0;
		SelectObject(mdc, horse[num]);
		BitBlt(hdc, 0, 0, 405, 300, mdc, 0, 0, SRCCOPY);
		num++;
		break;
	case WM_DESTROY:
		DeleteDC(mdc);
		ReleaseDC(hWnd, hdc);
		for (int i = 0; i<8; i++)
			DeleteObject(horse[i]);
		KillTimer(hWnd, 1);
		PostQuitMessage(0);
		break;
	default:
		break;
	}
	return (DefWindowProc(hwnd, msg, wparam, lparam));
}       

動畫效果如下

 

二、接下來是繪製計算機角色的循環動畫 

 

使用遊戲運行時間產生事件消息的代碼:

首先我們需要在全局變量上添加   

//DWORD全稱Double Word,是指註冊表的鍵值,每個word爲2個字節的長度,DWORD 雙字即爲4個字節,每個字節是8位,共32位。
DWORD     tNow,tPre;                         //當前時間與結束時間

刪除

//創建定時器
SetTimer(hWnd, 1, 60, NULL);

將消息循環函數更改

	while (msg.message != WM_QUIT)         //進入遊戲消息循環:  
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg); //獲得遊戲玩家輸入的消息;  
			DispatchMessage(&msg);//分配玩家消息並響應用戶消息。  
		}
		else
		{
			tNow = GetTickCount();                          //取得目前時間
			if (tNow - tPre >= 40) {    //可在while循環外設置tpre初值
				if (num == 8)     num = 0;
				SelectObject(mdc, horse[num]);
				BitBlt(hdc, 0, 0, 405, 300, mdc, 0, 0, SRCCOPY);
				tPre = GetTickCount();                 //取得結束時間
				num++;
			}
		}
	}

刪除WndProc()函數中的

Case  VM_TIMER相關處理內容

	case WM_TIMER:
		if (num == 8)
			num = 0;
		SelectObject(mdc, horse[num]);
		BitBlt(hdc, 0, 0, 405, 300, mdc, 0, 0, SRCCOPY);
		num++;
		break;

 

以及刪除VM_DESTROY中
 

 

KillTimer(hWnd, 1);

運行結果同定時器處理結果。

 

三、接下來是繪製計算機角色的透明動畫 

#include "stdafx.h"      
#include "MyGameFrame.h"      
#include <stdio.h>          

// 全局變量:       
HINSTANCE hInst;
HWND      hWnd;
HDC       hdc, mdc;
HBITMAP   bmp;            //
HBITMAP   horse;          //圖像位圖  
HBITMAP   bg;             //背景
int       num;            //當前圖像幀數

//DWORD全稱Double Word,是指註冊表的鍵值,每個word爲2個字節的長度,DWORD 雙字即爲4個字節,每個字節是8位,共32位。  
DWORD     tNow, tPre;    //當前時間與結束時間

//爲了防止遊戲畫面更新時出現透明貼圖過程中產生的閃爍現象。製作透明動畫必須在一個暫存的內存DC上完成每一張走動圖的透明然後再貼到窗口上。
HDC      bufdc;

// 此代碼模塊中包含的函數的前向聲明:       
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitWindow(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);


int APIENTRY WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR    lpCmdLine,
	int       nCmdShow)
{
	// 初始化全局字符串      
	MyRegisterClass(hInstance);


	// 執行應用程序初始化:       
	if (!InitWindow(hInstance, nCmdShow))//初始化窗口      
	{
		return FALSE;//如果不成功則返回FALSE,並退出程序      
	}

	MSG msg; //創建消息類對象   

	char filename[20] = "";

	hdc = GetDC(hWnd);
	mdc = CreateCompatibleDC(hdc);
	bufdc = CreateCompatibleDC(hdc);//緩存DC

	//創建與指定的設備環境相關的設備兼容的位圖
	bmp = CreateCompatibleBitmap(hdc, 960, 720);
	SelectObject(mdc, bmp);
	horse = (HBITMAP)LoadImage(NULL, "horse.bmp", IMAGE_BITMAP, 1624, 300, LR_LOADFROMFILE);
	bg = (HBITMAP)LoadImage(NULL, "bg.bmp", IMAGE_BITMAP, 960, 720, LR_LOADFROMFILE);

	int x, y;

	//繪製圖畫(一幀)
	num = 0; 		  			    //顯示圖號

	x = -50; 				        //貼圖起始X座標
	y = 150; 				        //貼圖起始Y 座標

	SelectObject(bufdc, bg);
	BitBlt(mdc, 0, 0, 960, 720, bufdc, 0, 0, SRCCOPY);
	SelectObject(bufdc, horse);
	
	//透明處理
	BitBlt(mdc, x, y, 203, 150, bufdc, num * 203, 150, SRCAND);
	BitBlt(mdc, x, y, 203, 150, bufdc, num * 203, 0, SRCPAINT);

	BitBlt(hdc, 0, 0, 960, 720, mdc, 0, 0, SRCCOPY);

	//結束時間
	//GetTickCount()函數,該函數的返回值是DWORD型,表示以毫秒爲單位的計算機啓動後經歷的時間間隔
	tPre = GetTickCount();

	num++;
    
	//動畫移動
	x += 20;
	if (x >= 900)
		x = -50;

	PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);//賦初值      


	while (msg.message != WM_QUIT)         //進入遊戲消息循環:  
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg); //獲得遊戲玩家輸入的消息;  
			DispatchMessage(&msg);//分配玩家消息並響應用戶消息。  
		}
		else
		{
			tNow = GetTickCount();//獲取當前時間
			if (tNow - tPre >= 100)//程序每隔100個單位時間進行一次繪圖操作  
			{
				if (num == 8)   num = 0;
				SelectObject(bufdc, bg);
				BitBlt(mdc, 0, 0, 960, 720, bufdc, 0, 0, SRCCOPY);
				SelectObject(bufdc, horse);

				//透明操作
				BitBlt(mdc, x, y, 203, 150, bufdc, num * 203, 150, SRCAND);
				BitBlt(mdc, x, y, 203, 150, bufdc, num * 203, 0, SRCPAINT);

				BitBlt(hdc, 0, 0, 960, 720, mdc, 0, 0, SRCCOPY);

				tPre = GetTickCount();//獲取結束時間
				num++;

				//動畫移動
				x += 20;
				if (x >= 900)
					x = -50;
			}
		}
	}

	return (int)msg.wParam;
}


ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex =
	{
		wcex.cbSize = sizeof(WNDCLASSEX),
		CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
		WndProc,0,0,
		hInstance,
		LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYGAMEFRAME)),
		LoadCursor(NULL, IDC_ARROW),
		(HBRUSH)(COLOR_WINDOW + 1),NULL,
		_T("GameFrame"),
		LoadIcon(NULL,MAKEINTRESOURCE(IDI_SMALL))
	};
	return RegisterClassEx(&wcex);
}


BOOL InitWindow(HINSTANCE hInstance, int nCmdShow)
{
	hInst = hInstance; // 將實例句柄存儲在全局變量中            
	hWnd = CreateWindow
	(
		_T("GameFrame"),
		_T("遊戲框架"),
		WS_OVERLAPPEDWINDOW^WS_THICKFRAME^WS_MAXIMIZEBOX,//普通樣式,不能改變大小,不能最大化      
		CW_USEDEFAULT, CW_USEDEFAULT, 960, 720, nullptr, nullptr, hInstance, nullptr
	);


	if (!hWnd)
	{
		return FALSE;
	}


	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);


	return TRUE;
}


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	switch (msg)                        //判斷消息      
	{
	case WM_CREATE:
		//執行初始化代碼                    
		return(0);
		break;
	case WM_DESTROY:
		DeleteDC(mdc);
		ReleaseDC(hWnd, hdc);
	    DeleteObject(horse);
		PostQuitMessage(0);
		break;
	default:
		break;
	}
	return (DefWindowProc(hwnd, msg, wparam, lparam));
} 

最後結果如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章