【Visual C++】游戏开发笔记二十三 游戏基础物理建模 五 粒子系统模拟 二

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

本系列文章由zhmxy555(毛星云)编写,转载请注明出处。

http://blog.csdn.net/zhmxy555/article/details/7607916

作者:毛星云    邮箱: happylifemxy@qq.com    期待着与志同道合的朋友们相互交流




本节在笔记二十二的基础上继续讲解了例子系统的模拟与实际运用,着重讲解和分析了基于例子系统的一个“星光绽放

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[i].lasted>50)   {    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  = NULLreturn 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[i].lasted>50)   {    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) {  case WM_TIMER:                      //时间消息     MyPaint(hdc);                   //在消息循环中加入处理WM_TIMER消息,当接收到此消息时便调用MyPaint()函数进行窗口绘图              break;    case WM_KEYDOWN:      //按键消息     if(wParam==VK_ESCAPE)    //按下【Esc】键    PostQuitMessage(0);   break;  case WM_DESTROY:      //窗口结束消息    DeleteDC(mdc);   DeleteDC(bufdc);   DeleteObject(bg);   DeleteObject(star);   DeleteObject(mask);   KillTimer(hWnd,1);             //窗口结束时,删除所建立的定时器          ReleaseDC(hWnd,hdc);   PostQuitMessage(0);   break;  default:       //其他消息   return DefWindowProc(hWnd, message, wParam, lParam);   }   return 0;}


这个“星光绽放”demo运行的截图如下:













背景图片是盛大旗下网络游戏《龙之谷》的游戏原画。


这节的代码可以与之前讲解的重力系统,摩擦力系统相结合,创造出更为逼真的爆炸特效,有兴趣的朋友可以尝试一下,做出真实的受重力影响的烟花盛放的效果出来。





 三、史诗级游戏作品《暗黑破坏神3》上市首周所创下的传奇


在文章末尾,我们来盘点一下暴雪大作《暗黑破坏神3》不俗的销售成绩。



5月15日《暗黑破坏神3》发售至今已经过了一周多,全球暗黑粉丝在激情中度过了美妙的一个星期。

《暗黑破坏神3》发布以来,受到了广大玩家的热情追捧。暴雪公布的数据显示,《暗黑破坏神3》开服24小时内共卖出了350万份拷贝。加上120万的魔兽世界年费用户,游戏发售当天共有470万玩家通过战网进入到庇护所世界。游戏发布第一周,游戏总销量为630万份(不包含WOW年费赠送和韩国数据)。  




这份数据刷新了PC游戏史最高数据,并且大大超越去年暴雪另一款热卖游戏《星际争霸2》所创下的销售记录。《暗黑3》有望在一个月内突破《星际争霸》14年来1100万份的累计销量。





这是电子游戏界上的一个传奇!

暴雪花十几年时间交出的这份答卷可谓非常的出色~~!!


还是那句话,暴雪出品,必属精品。浅墨觉得,采用精品战略的公司一般都会有不俗的发展,比如说苹果,比如说暴雪,它们都是依靠着几款精雕细琢出来的精品,统治着他们各自所在的领域。

对于期待了8年的《暗黑破坏神3》,浅墨在5月15号“大菠萝3”发售之后的第一时间就购买了CD-KEY,但买过来之后一直比较忙,没有第一时间开始体验,也就是近几天才开始玩的。是在台服玩的一个“狩魔猎人”,每天也就花一个小时左右,浅墨打算慢慢玩,沿途看下风景,期待了这么多年的作品,如果很快就打通了就枉费了这么多年的期待了,是吧。(浅墨记得有一个在15号“大菠萝3”刚发售,开服8小时之后候就满级60级的家伙……)所以浅墨的升级速度不算快,目前才22级,不过身上目前基本上一身稀有装备了,敏捷堆了200+了,对于一个22级的狩魔猎人,已经很高了吧。我的BattleTag是浅墨#3762,也在台服玩的朋友可以加我好友一起玩哈。

同时在这里浅墨也提醒大家,“大菠萝3”虽然经典,但是一定要适度游戏,千万不要影响学习和生活。

前几天就爆出了美国一位32岁的男子连续玩了3天3夜的《暗黑破坏神3》后猝死,与世长辞的新闻,可真让人惋惜。

 

 

好了,本节笔记就到这里吧,关于源码的提供,浅墨越来越觉得没有提供两个版本的必要了,但是一定会满足不同IDE的朋友都可以把源码运行起来。下面是通用版的源码:


本篇文章的配套源码请点击这里下载:【Visual C++】Note_Code_23

 

(VC6.0直接可以打开工程,VS2005,VS2008,VS2010,VS2011等版本的朋友可以双击其中的工程文件进行版本转化,然后即可打开工程)




感谢一直支持【Visual C++】游戏开发笔记系列专栏的朋友们。

目前在讲的GDI只是前奏。DirectX 11会在GDI梳理完后进行深入讲解,敬请期待~~

【Visual C++】游戏开发 系列文章才刚刚展开一点而已,因为游戏世界实在是太博大精深了~

但我们不能着急,得慢慢打好基础。做学问最忌好高骛远,不是吗?

 

浅墨希望看到大家的留言,希望与大家共同交流,希望得到睿智的评论(即使是批评)。

你们的支持是我写下去的动力~

 

精通游戏开发的路还很长很长,非常希望能和大家一起交流,共同学习,共同进步。

大家看过后觉得值得一看的话,可以顶一下这篇文章,你们的支持是我继续写下去的动力~

如果文章中有什么疏漏的地方,也请大家指正。也希望大家可以多留言来和我探讨相关的问题。

最后,谢谢你们一直的支持~~~

                                               

 

                                                   ——————————浅墨于2012年5月27日

------------------------------------------------------------------------------------------------------------------------------

浅墨历时一年为游戏编程爱好者锻造的入门宝典:《逐梦旅程:Windows游戏编程之从零开始》

如果你喜欢浅墨写的【Visual C++】游戏开发系列博客文章,那么你一定会爱上这本书。

这是浅墨专门为热爱游戏编程的朋友们写的入门级游戏编程宝典。



------------------------------------------------------------------------------------------------------------------------------





           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述
你好! 这是你第一次使用 **Markdown编辑器** 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block var foo = 'bar'; 

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t &ThinSpace; . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

gantt
        dateFormat  YYYY-MM-DD
        title Adding GANTT diagram functionality to mermaid
        section 现有任务
        已完成               :done,    des1, 2014-01-06,2014-01-08
        进行中               :active,  des2, 2014-01-09, 3d
        计划一               :         des3, after des2, 5d
        计划二               :         des4, after des3, 5d
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值