愿尽以绵薄之力,薪火相传游戏开发的信仰与梦想,复兴国产单机游戏。
分类: 【Visual C++】游戏开发【Visual C++】 2012-05-28 04:15 25333人阅读 评论(56) 收藏举报
游戏c++nullimagetimerstruct
本系列文章由zhmxy555(毛星云)编写,转载请注明出处。
blog.csdn/zhmxy555/article/details/7607916
作者:毛星云    邮箱: happylifemxy@qq    期待着与志同道合的朋友们相互交流
本节在笔记二十二的基础上继续讲解了例子系统的模拟与实际运用,着重讲解和分析了基于例子系统的一个“星光绽放
demo”,最后盘点了史诗级游戏作品《暗黑破坏神3》上市首周所创下的传奇。
一.基础知识讲解
1.    概念与思路
基本的粒子系统概念在笔记二十二中已经讲过了,还不太清楚的朋友请移步前篇:
【Visual C++】游戏开发笔记二十二 游戏基础物理建模(四) 粒子系统模拟(一)
本节讲解的星光绽放demo相当于是一个模拟爆炸(或者说是烟花)特效的demo,浅墨认为这个特效拿出来讲解很多必要性,它可以为很多问题带来的思路的火花。这个demo之中,绽放(爆炸)点为在窗口中由随机数产生的一个位置,绽放(爆炸)后,会出现很多星光以不同的速度向四方飞散而去,当粒子飞出窗口后或者超出时间后便会消失。每一次爆炸所出现的粒子全部消失后,便会重新出现绽放(爆炸)的画面,以产生不断绽放星光的效果。
2.“星光”粒子的构造
首先我们来看一下这次如何用结构体来构造出星光粒子:
struct flystar
{
int x;      //星光所在的x坐标
int y;      //星光所在的y坐标
int vx;      //星光x方向的速度
int vy;      //星光y方向的速度
int lasted;  //星光存在的时间
BOOL exist;  //星光是否存在
}flystar[50];
6个成员分别为,粒子坐标两个值,粒子方向两个值,持续时间lasted,和粒子是否存在的标识exist。
3.核心代码讲解
最重要的当然是我们的MyPaint()绘图函数:
//全局变量声明
HINSTANCE hInst;
HBITMAP bg,star,mask;  //用于贴图的三个HBITMAP变量
HDC hdc,mdc,bufdc;
HWND hWnd;
RECT rect;
int i,count; //定义count用于计数
//****自定义绘图函数*********************************
// 1.窗口贴图
// 2.实现星光绽放的效果
void MyPaint(HDC hdc)
{
//创建粒子
if(count == 0)              //随机设置爆炸点
{
int x=rand()%rect.right;
int y=rand()%rect.bottom;
for(i=0;i<50;i++)      //产生星光粒子
{
flystar[i].x = x;
flystar[i].y = y;
flystar[i].lasted = 0;  //设定该粒子存在的时间为零
if(i%2==0)      //按粒子编号i来决定粒子在哪个象限运动,且x,y方向的移动速度随机为1—15之间的一个值,由1+rand()%15来完成
{
flystar[i].vx =  -(1+rand()%15);
flystar[i].vy =  -(1+rand()%15);
}
if(i%2==1)
{
flystar[i].vx = 1+rand()%15;
flystar[i].vy = 1+rand()%15;
}
if(i%4==2)
{
flystar[i].vx = -(1+rand()%15);
flystar[i].vy = 1+rand()%15;
}
if(i%4==3)
{
学习编程的单机游戏flystar[i].vx = 1+rand()%15;
flystar[i].vy = -(1+rand()%15);
}
flystar[i].exist = true;  //设定粒子存在
}
count = 50;  //50个粒子由for循环设置完成后,我们将粒子数量设为50,代表目前有50颗星光
}
//先在内存dc中贴上背景图片
SelectObject(bufdc,bg);
BitBlt(mdc,0,0,rect.right,rect.bottom,bufdc,0,0,SRCCOPY);
for(i=0;i<50;i++)
{
if(flystar[i].exist)  //判断粒子是否还存在,若存在,则根据其坐标(flystar[i].x,flystar[i].y)进行贴图操作
{
SelectObject(bufdc,mask);
BitBlt(mdc,flystar[i].x,flystar[i].y,30,30,bufdc,0,0,SRCAND);
SelectObject(bufdc,star);
BitBlt(mdc,flystar[i].x,flystar[i].y,30,30,bufdc,0,0,SRCPAINT);
//计算下一次贴图的坐标
flystar[i].x+=flystar[i].vx;
flystar[i].y+=flystar[i].vy;
//在每进行一次贴图后,将粒子的存在时间累加1.
flystar[i].lasted++;
//进行条件判断,若某粒子跑出窗口区域一定的范围,则将该粒子设为不存在,且粒子数随之递减
if(flystar[i].x<=-10 || flystar[i].x>rect.right || flystar[i].y<=-10 || flystar[i].y>rect.bottom || flystar[
{
flystar[i].exist = false;  //删除星光粒子
count--;                    //递减星光总数
}
}
}
/
/将mdc中的全部内容贴到hdc中
BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY);
}
相关的书写思路在代码注释中浅墨已经写得比较清晰了。
这段代码的书写整体思路即:
第一步,判断粒子是否创建,若星光数量count不为0,则直接跳到第四步进行相关贴图操作。否则需按每步顺序完成粒子的初始化。
第二步,随机设置绽放点。
第三步,创建各个粒子(为结构体各属性赋值)。
第四步,在内存dc上贴上背景图片。
第五步,对各个粒子进行贴图操作并
第六步,对某些值,如count,exist进行特殊的处理
第七步,将mdc(内存dc)中的内容贴到hdc中,完成最后在屏幕上的显示。
二、详细注释的源代码欣赏
OK,讲解完成,现在我们就贴出详细注释的源代码:
#include "stdafx.h"
#include <stdio.h>
//全局变量声明
HINSTANCE hInst;
HBITMAP bg,star,mask;  //用于贴图的三个HBITMAP变量
HDC hdc,mdc,bufdc;
HWND hWnd;
RECT rect;
int i,count; //定义count用于计数
struct flystar
{
int x;      //星光所在的x坐标
int y;      //星光所在的y坐标
int vx;      //星光x方向的速度
int vy;      //星光y方向的速度
int lasted;  //星光存在的时间
BOOL exist;  //星光是否存在
}flystar[50];
//全局函数声明
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void MyPaint(HDC hdc);
//****WinMain函数,程序入口点函数**************************************
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR    lpCmdLine,
int      nCmdShow)
{
MSG msg;
MyRegisterClass(hInstance);
//初始化
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
//消息循环
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//****设计一个窗口类,类似填空题,使用窗口结构体*********************
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc= (WNDPROC)WndProc;
wcex.cbClsExtra= 0;
wcex.cbWndExtra= 0;
wcex.hInstance= hInstance;
wcex.hIcon= NULL;
wcex.hCursor= NULL;
wcex.hCursor= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName= NULL;
wcex.lpszClassName= "maple";
wcex.hIconSm= NULL;
return RegisterClassEx(&wcex);
}
/
/****初始化函数*************************************
// 1.加载位图资源
// 2.取得内部窗口区域信息
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HBITMAP bmp;
hInst = hInstance;
hWnd = CreateWindow("maple", "浅墨的绘图窗口" , WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
MoveWindow(hWnd,10,10,600,450,true);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hdc = GetDC(hWnd);
mdc = CreateCompatibleDC(hdc);
bufdc = CreateCompatibleDC(hdc);
bmp = CreateCompatibleBitmap(hdc,640,480);
SelectObject(mdc,bmp);
bg = (HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,rect.right,rect.bottom,LR_LOADFROMFILE);
star = (HBITMAP)LoadImage(NULL,"star.bmp",IMAGE_BITMAP,30,30,LR_LOADFROMFILE);
mask = (HBITMAP)LoadImage(NULL,"mask.bmp",IMAGE_BITMAP,30,30,LR_LOADFROMFILE);
GetClientRect(hWnd,&rect);
SetTimer(hWnd,1,0,NULL);
MyPaint(hdc);
return TRUE;
}
//****自定义绘图函数*********************************
// 1.窗口贴图
// 2.实现星光绽放的效果
void MyPaint(HDC hdc)
{
//创建粒子
if(count == 0)              //随机设置爆炸点
{
int x=rand()%rect.right;
int y=rand()%rect.bottom;
for(i=0;i<50;i++)      //产生星光粒子
{
flystar[i].x = x;
flystar[i].y = y;
flystar[i].lasted = 0;  //设定该粒子存在的时间为零
if(i%2==0)      //按粒子编号i来决定粒子在哪个象限运动,且x,y方向的移动速度随机为1—15之间的一个值,由1+rand()%15来完成
{
flystar[i].vx =  -(1+rand()%15);
flystar[i].vy =  -(1+rand()%15);
}
if(i%2==1)
{
flystar[i].vx = 1+rand()%15;
flystar[i].vy = 1+rand()%15;
}
if(i%4==2)
{
flystar[i].vx = -(1+rand()%15);
flystar[i].vy = 1+rand()%15;
}
if(i%4==3)
{
flystar[i].vx = 1+rand()%15;
flystar[i].vy = -(1+rand()%15);
}
flystar[i].exist = true;  //设定粒子存在
}
count = 50;  //50个粒子由for循环设置完成后,我们将粒子数量设为50,代表目前有50颗星光
}
//先在内存dc中贴上背景图片
SelectObject(bufdc,bg);
BitBlt(mdc,0,0,rect.right,rect.bottom,bufdc,0,0,SRCCOPY);
for(i=0;i<50;i++)
{
if(flystar[i].exist)  //判断粒子是否还存在,若存在,则根据其坐标(flystar[i].x,flystar[i].y)进行贴图操作
{
SelectObject(bufdc,mask);
BitBlt(mdc,flystar[i].x,flystar[i].y,30,30,bufdc,0,0,SRCAND);
SelectObject(bufdc,star);
BitBlt(mdc,flystar[i].x,flystar[i].y,30,30,bufdc,0,0,SRCPAINT);
//计算下一次贴图的坐标
flystar[i].x+=flystar[i].vx;
flystar[i].y+=flystar[i].vy;
//在每进行一次贴图后,将粒子的存在时间累加1.
flystar[i].lasted++;
//进行条件判断,若某粒子跑出窗口区域一定的范围,则将该粒子设为不存在,且粒子数随之递减
if(flystar[i].x<=-10 || flystar[i].x>rect.right || flystar[i].y<=-10 || flystar[i].y>rect.bottom || flystar[
{
flystar[i].exist = false;  //删除星光粒子
count--;                    //递减星光总数
}
}
}
//将mdc中的全部内容贴到hdc中
BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY);
}
//****消息处理函数***********************************
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。