C++游戏之游戏动画的实现(三)

       上一节,我们已经知道如何利用GDI在窗体上绘制图片和文字了,是不是很简单,那么现在如何利用GDI在游戏中实现动画效果呢?俗话说的好,2D游戏是贴图的艺术,3D是渲染的艺术,贴图嘛,也很简单,有两种方式,一种采用定时器,一种则是利用消息循环,目前都是采用的第二种绘制方式(消息循环),这里也只使用第二种,游戏中的动画都是一帧一帧的帖上去的,就像播放电影一样,如何实现呢?我们只需把上一节的代码拿过来稍作修改就行了。(本文内容均为个人理解与学习)


        比如有以下怪物出现的动画(素材来自DNF)(  


很简单,用一个数组把他们保存起来,然后依次播放就行了。

 

HBITMAP *image = new HBITMAP[29];//动画的图片句柄数组,28张图片,从0开始,所以数组为29

资源初始化函数

//初始化资源
void Game_Init(HWND hwnd)
{
	g_hdc = GetDC(hwnd);//获取设备环境DC
	m_hdc = CreateCompatibleDC(g_hdc);//建立兼容的设备环境

	wchar_t fileName[10];//文件名

	//初始化图片数组
	for (int i=0;i<29;i++)
	{
		ZeroMemory(fileName,wcslen(fileName));//初始化数组为0
		swprintf_s(fileName,L"%d.bmp",i);//格式转换
		image[i] = (HBITMAP)LoadImage(NULL,fileName,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE);//加载位图到数组
	}
}


动画的绘制

//绘制图形
void Game_Paint(HWND hwnd)
{
	/*根据下标绘制动画

	    其中(index = (++index)>=29?0:index)为简写等同于

		index++;

		if(index>=29)//判断下班是否越界
		{
		 index=0;
		}
	*/
	SelectObject(m_hdc,image[index = (++index)>=29?0:index]);

	BitBlt(g_hdc,150,0,800,600,m_hdc,0,0,SRCCOPY);//拷贝到设备环境上
}

最后记得清理资源

void Game_Clear(HWND hwnd)
{
	ReleaseDC(hwnd,g_hdc);
	DeleteObject(hfont);
	delete [] image;//清理图片数组
	DeleteObject(m_hdc);
}

运行效果图:如果看起来不是很流畅,那是因为GIF动态本身的原因,非代码问题



     看起来还不错哈,我们来加入点背景音乐,就更不错了,怎么添加呢?很简单,一句话搞定,不过这种方式貌似只能播放wav格式的音频哦。

#pragma comment(lib,"winmm.lib")//添加一个库文件


添加库文件后,调用PlaySound函数就行了

	//第一个参数,文件路径
	//第二参数,应用程序的实例句柄,除非pszSound的指向一个资源标识符,否则必须设置为NULL
	//第三个参数为标示,SND_LOOP重复播放,SND_ASYNC异步播放,SND_FILENAME来自硬盘文件
	PlaySound(L"bg.wav",0,SND_LOOP | SND_ASYNC | SND_FILENAME);

完整源码:

#include <Windows.h>
#include <string>

#pragma comment(lib,"winmm.lib")

using namespace std;

//窗体的过程函数
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam);

HDC g_hdc;//设备环境
HDC m_hdc;//兼容的设备环境
HBITMAP *image = new HBITMAP[29];//绘制动画的图片位图数组
int index=0;//图片下标
wstring test=L"Hello Word";//绘制的字符串
HFONT hfont;//字体对象指针

//初始化资源,用于初始化设备环境和加载背景图片
void Game_Init(HWND hwnd);
//绘制图形,正式绘制
void Game_Paint(HWND hwnd);
//清理资源,程序退出时,释放资源
void Game_Clear(HWND hwnd);

//WinMain主函数
INT WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrivInstance,LPSTR lpCmdLine,int nShowCmd)
{
	//设计一个窗体
	WNDCLASSEX wndClass = {0};
	wndClass.style = CS_HREDRAW|CS_VREDRAW;
	wndClass.cbSize = sizeof(wndClass);
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
	wndClass.hCursor = ::LoadCursor(hInstance,IDC_ARROW);
	wndClass.hIcon = (HICON)::LoadImage(NULL,L"",IMAGE_ICON,0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE);
	wndClass.hInstance = hInstance;
	wndClass.lpfnWndProc = WndProc;
	wndClass.lpszClassName = L"Test";
	wndClass.lpszMenuName = 0; 
	//注册窗体
	if (!RegisterClassEx(&wndClass))
	{
		return -1;
	}
	//创建窗体
	HWND hwnd = CreateWindow(L"Test",L"GDI",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,800,600,NULL,NULL,hInstance,NULL);

	if (hwnd == NULL)
	{
		return -1;
	}
	//初始化资源
	Game_Init(hwnd);

	//显示与更新窗体
	ShowWindow(hwnd,nShowCmd);
	UpdateWindow(hwnd);

	//消息队列
	MSG msg = {0};

	while (msg.message != WM_QUIT)
	{
		if (PeekMessage(&msg,0,0,0,PM_REMOVE))//读取消息
		{
			TranslateMessage(&msg);//翻译消息
			DispatchMessage(&msg);//发送消息
		}
		else
		{
			Game_Paint(hwnd);//绘制函数
			Sleep(50);//绘制间隙50毫秒
		}
	}

	UnregisterClass(L"Test",hInstance);

	return 0;
}

//窗口过程函数
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
{
	switch(message)
	{
	case WM_PAINT:
		ValidateRect(hwnd,NULL);//重绘整个窗体
		break;
	case WM_DESTROY:
		Game_Clear(hwnd);//退出程序时,清理资源
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd,message,wparam,lparam);
	}

	return 0;
}

//初始化资源
void Game_Init(HWND hwnd)
{
	g_hdc = GetDC(hwnd);//获取设备环境DC
	m_hdc = CreateCompatibleDC(g_hdc);//建立兼容的设备环境

	wchar_t fileName[10];//保存文件名

	//初始化图片数组
	for (int i=0;i<29;i++)
	{
		ZeroMemory(fileName,wcslen(fileName));
		swprintf_s(fileName,L"%d.bmp",i);
		image[i] = (HBITMAP)LoadImage(NULL,fileName,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE);
	}

	//播放背景音乐
	//第一个参数,文件路径
	//第二参数,应用程序的实例句柄,除非pszSound的指向一个资源标识符(即fdwSound被定义为SND_RESOURCE),否则必须设置为NULL
	//第三个参数为标示,SND_LOOP重复播放,SND_ASYNC异步播放,SND_FILENAME来自硬盘文件
	PlaySound(L"bg.wav",0,SND_LOOP | SND_ASYNC | SND_FILENAME);
}

//绘制图形
void Game_Paint(HWND hwnd)
{
	/*根据下标绘制动画

	    其中(index = (++index)>=29?0:index)为简写等同于

		index++;

		if(index>=29)//判断下班是否越界
		{
		 index=0;
		}
	*/
	SelectObject(m_hdc,image[index = (++index)>=29?0:index]);

	BitBlt(g_hdc,150,0,800,600,m_hdc,0,0,SRCCOPY);//拷贝到设备环境上
}

//清理内存
void Game_Clear(HWND hwnd)
{
	ReleaseDC(hwnd,g_hdc);
	DeleteObject(hfont);
	delete [] image;
	DeleteObject(m_hdc);
}


代码本来很小的,结果资源却很大 = = ! 汗,CSND居然传不了,等级不够 = = !

源码及其资源下载:http://pan.baidu.com/s/1i3iU3Pj
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值