利用VS创建一个游戏(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));
} 

最后结果如下:


猜你喜欢

转载自blog.csdn.net/hao5119266/article/details/80228378