上一节,我们已经知道如何利用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