源代码下载地址:
网盘:http://pan.baidu.com/s/1eQ33c7w
CSDN:http://download.csdn.net/detail/u011418173/9080501
最近,看了下毛星云的书:《逐梦旅程 windows游戏编程之从零开始》,对其十分的感兴趣,这本书的内容浅显易懂,很适合像我们这些编程的入门者阅读。目前只看了该书的前半部分,也就是2D游戏的编程,自己便尝试着在浅墨大神的基础框架上做一些别的东西。
在一些大型游戏的游戏资源载入的过程中,都是会有专门的载入界面,让玩家在等待的过程中不至于太无聊和焦虑。一般,载入界面运行是要有动态效果的,这一般可以说明该游戏没有崩溃,让玩家不要慌:别急,游戏正在加载呢,等等吧。之前玩文明5时的载入界面令我印象深刻,由于自己的电脑不好,一次载入都要好几分钟,有时候游戏死了都不知道ORZ。
首先要准备一些图片资源,一些简单的资源我都是自己制作的,这里我准备了一个旋转的loading效果图片,如下所示:
当然了,想通过C++载入gif图片是有些困难的,于是我将这些图片分解为8帧,使用透明遮罩法来显示,具体的制作方法这里就不详述。下面是制成的图片,:
载入时的背景图片:
还有正式游戏时的背景图片:
在浅墨的框架中,有三个关键的函数,分别是:
1 2 3 |
BOOL
Game_Init
(
HWND
hwnd
);
//在此函数中进行资源的初始化
VOID
Game_Paint
(
HWND
hwnd
);
//在此函数中进行绘图代码的书写
BOOL
Game_CleanUp
(
HWND
hwnd
);
//在此函数中进行资源的清理
|
那么载入界面的代码当然是要写在初始化中了,为了不影响其他资源的载入,我考虑创建一个线程,在这里实现loading界面的绘制。同时主程序实现加载游戏资源的任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
BOOL
Game_Init
(
HWND
hwnd
)
{
HBITMAP
bmp
;
g_hdc
=
GetDC
(
hwnd
);
g_mdc
=
CreateCompatibleDC
(
g_hdc
);
//创建一个和hdc兼容的内存DC
g_bufdc
=
CreateCompatibleDC
(
g_hdc
);
//再创建一个和hdc兼容的缓冲DC
bmp
=
CreateCompatibleBitmap
(
g_hdc
,
WINDOW_WIDTH
,
WINDOW_HEIGHT
);
SelectObject
(
g_mdc
,
bmp
);
//预先加载Loading界面
g_hLoading
=
(
HBITMAP
)
LoadImage
(
NULL
,
L"loading.bmp"
,
IMAGE_BITMAP
,
2400
,
600
,
LR_LOADFROMFILE
);
g_hlLoading_bk
=
(
HBITMAP
)
LoadImage
(
NULL
,
L"loading_bk.bmp"
,
IMAGE_BITMAP
,
1500
,
1000
,
LR_LOADFROMFILE
);
//设置字体
HFONT
hFont
;
hFont
=
CreateFont
(
80
,
0
,
0
,
0
,
700
,
0
,
0
,
0
,
GB2312_CHARSET
,
0
,
0
,
0
,
0
,
TEXT
(
"钟齐段宁行书"
));
SelectObject
(
g_mdc
,
hFont
);
SetBkMode
(
g_mdc
,
TRANSPARENT
);
_beginthread(ThreadFunc,0,NULL);
//加载其他各种正式的游戏资源的地方
g_hBackGround
=
(
HBITMAP
)
LoadImage
(
NULL
,
L"场景1.bmp"
,
IMAGE_BITMAP
,
WINDOW_WIDTH
,
WINDOW_HEIGHT
,
LR_LOADFROMFILE
);
//为了测试效果,强行增加Loading时间,正常运行时,只要资源加载完后,就可以退出线程
Sleep
(
3000
);
g_bFinishThread
=
1
;
Game_Paint
(
hwnd
);
return
TRUE
;
}
|
由于这个例子的资源极少,载入极快,故几乎看不到载入时的效果,所以添加了一句:Sleep(3000)。这样我们能够看到3秒的loading界面,从而判断效果的好坏。
下面是线程函数的具体内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
void
ThreadFunc
(
PVOID
pvoid
)
{
srand
((
int
)
time
(
NULL
));
//设置随机种子
int
i
=
0
;
//用于帧数的循环
DWORD
tNow
,
tPre
;
//保存当前时间和上一帧的时间
tPre
=
GetTickCount
();//获得当前的时间
//若游戏资源未加载完,则g_bFinishThread一直为0,将一直循环下去
while
(
!
g_bFinishThread
)
{
//载入loading时的背景图片
SelectObject
(
g_bufdc
,
g_hlLoading_bk
);
BitBlt
(
g_mdc
,
0
,
0
,
WINDOW_WIDTH
,
WINDOW_HEIGHT
,
g_bufdc
,
0
,
0
,
SRCCOPY
);
//载入loading时的旋转图片,使用透明遮罩法
SelectObject
(
g_bufdc
,
g_hLoading
);
BitBlt
(
g_mdc
,
600
,
300
,
300
,
300
,
g_bufdc
,
i
*
300
,
300
,
SRCAND
);
BitBlt
(
g_mdc
,
600
,
300
,
300
,
300
,
g_bufdc
,
i
*
300
,
0
,
SRCPAINT
);
//绘制提示文字
WCHAR
str
[
50
];
swprintf_s
(
str
,
L"游戏资源正在拼命加载中,请稍后..."
);
SetTextColor
(
g_mdc
,
RGB
(
rand
()
%
255
,
rand
()
%
255
,
rand
()
%
255
));
//使用随机数,呈现随机的颜色
TextOut
(
g_mdc
,
150
,
700
,
str
,
wcslen
(
str
));
//将最后的画面显示在窗口中
BitBlt
(
g_hdc
,
0
,
0
,
WINDOW_WIDTH
,
WINDOW_HEIGHT
,
g_mdc
,
0
,
0
,
SRCCOPY
);
i
++
;
if
(
i
==
8
)
//每8张一个循环
i
=
0
;
do
{
tNow
=
GetTickCount
();
}
while
(
tNow
-
tPre
<
100
);
//当前后时间超过0.1s后,绘制下一帧
tPre
=
tNow
;
}
return
;
}
|
为了防止在绘制loading界面的同时进行正常游戏的绘制,我在winmain函数的循环体中加入了一条判断:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
while
(
msg
.
message
!=
WM_QUIT
)
//使用while循环,如果消息不是WM_QUIT消息,就继续循环
{
if
(
PeekMessage
(
&
msg
,
0
,
0
,
0
,
PM_REMOVE
)
)
//查看应用程序消息队列,有消息时将队列中的消息派发出去。
{
TranslateMessage
(
&
msg
);
//将虚拟键消息转换为字符消息
DispatchMessage
(
&
msg
);
//分发一个消息给窗口程序。
}
else
{
g_tNow
=
GetTickCount
();
//获取当前系统时间
if
(
g_tNow
-
g_tPre
>=
100
)
//当此次循环运行与上次绘图时间相差0.1秒时再进行重绘操作
if(g_bFinishThread)
//如果loading线程结束,则进行正常的游戏绘制
Game_Paint
(
hwnd
);
}
}
|
但是这种方法的话,在编译器中调试时是发不出声音的!一开始还以为是代码的问题,后来尝试直接运行Debug文件夹下的.exe文件,发现代码原来没有问题。。。
注:需要链接winmm.lib库