下载

1下载券

加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 VC++游戏编程

VC++游戏编程.doc

VC++游戏编程

sutingwei521
2011-05-01 0人阅读 举报 0 0 暂无简介

简介:本文档为《VC++游戏编程doc》,可适用于IT/计算机领域

第一章游戏基础            一动画 游戏是动画的延伸只要知道了动画的原理在动画变化时使它根据键盘或鼠标的输入操作而变化就是游戏了。所以在介绍游戏编程之前先讲讲动画。动画一般分三种形式:形变、位变、色变。如下: .​ .形变 即几种形状的图形或位图依次转变而成。(图)图  先看一个简单的实例:a.​ a. 新建工程选择单文档完成。a.​ b. 在view类加变量intituxing并在构造函数里赋值为ituxing=a.​ c. 在OnDraw(CDC*pDC)函数上添上以下语句:voidCMyView::OnDraw(CDC*pDC){CMyDoc*pDoc=GetDocument()ASSERTVALID(pDoc)TODO:adddrawcodefornativedatahere清除当前图形CBrushmybrushmybrushCreateSolidBrush(RGB(,,))CRectmyrect(,,,)pDC>FillRect(myrect,mybrush)判断当前图形ituxingif(ituxing==)ituxing=画矩形pDC>Rectangle(,,,)elseif(ituxing==)ituxing=画圆pDC>Ellipse(,,,)else否则画三角形{pDC>MoveTo(,)pDC>LineTo(,)pDC>LineTo(,)pDC>LineTo(,)}}a.​ d. 添加OnTimer(UINTnIDEvent)和OnCreate(LPCREATESTRUCTlpCreateStruct)并加上语句如下:voidCMyView::OnTimer(UINTnIDEvent){TODO:Addyourmessagehandlercodehereandorcalldefault获取指针pdcCDC*pDC=GetDC()调用OnDraw(pDC)重画OnDraw(pDC)使ituxing循环ituxing=(ituxing) CView::OnTimer(nIDEvent)} intCMyView::OnCreate(LPCREATESTRUCTlpCreateStruct){if(CView::OnCreate(lpCreateStruct)==)returnTODO:Addyourspecializedcreationcodehere设置更新时间SetTimer(,,)return}a.​ e. 完成。 .​ .位变 即同一个图形或位图依次在不同的位置上出现而形成动画。(图) 图 见实例:a​ a      复制实例文件夹改名为。把voidCMyView::OnTimer(UINTnIDEvent)中的ituxing=(ituxing)改为ituxing=(ituxing)a​ b      把OnDraw(CDC*pDC)函数改为:voidCMyView::OnDraw(CDC*pDC){CMyDoc*pDoc=GetDocument()ASSERTVALID(pDoc)TODO:adddrawcodefornativedatahere清除当前图形CBrushmybrushmybrushCreateSolidBrush(RGB(,,))CRectmyrect(,,,)pDC>FillRect(myrect,mybrush) 用当前图形位置ituxing画圆pDC>Ellipse(*ituxing,*ituxing,*ituxing,*ituxing)}a​ c      执行OK!.​ . 色变 即利用不同颜色的转变而形成有动感的图画。(图)图  实例:a​ a      新建单文档工程。a​ b      添加参数inticolor并赋值为。a​ c      添加函数OnTimer(UINTnIDEvent)和OnCreate(LPCREATESTRUCTlpCreateStruct)并添加语句如下: voidCMyView::OnTimer(UINTnIDEvent){TODO:Addyourmessagehandlercodehereandorcalldefaulticolor=此函数使客户区失效以致重画Invalidate()CView::OnTimer(nIDEvent)} intCMyView::OnCreate(LPCREATESTRUCTlpCreateStruct){if(CView::OnCreate(lpCreateStruct)==)returnTODO:AddyourspecializedcreationcodehereSetTimer(,,)return}a​ d      最后在OnDraw(CDC*pDC)加上画圆语句:voidCMyView::OnDraw(CDC*pDC){CMyDoc*pDoc=GetDocument()ASSERTVALID(pDoc)TODO:adddrawcodefornativedatahere获取icolor值inti=icolor在不同位置画四个不同颜色的圆CBrushbrush(RGB((*i),(*i),*(i)))CBrush*pOldBrush=pDC>SelectObject(brush)pDC>Ellipse(,,,)pDC>SelectObject(pOldBrush)CBrushbrush(RGB((*i),(*i),(*i)))CBrush*pOldBrush=pDC>SelectObject(brush)pDC>Ellipse(,,,)pDC>SelectObject(pOldBrush)CBrushbrush(RGB((*i),(*i),(*i)))CBrush*pOldBrush=pDC>SelectObject(brush)pDC>Ellipse(,,,)pDC>SelectObject(pOldBrush)CBrushbrush(RGB((*i),(*i),(*i)))CBrush*pOldBrush=pDC>SelectObject(brush)pDC>Ellipse(,,,)pDC>SelectObject(pOldBrush)}a​ e      完成。 以上是三种最基本的动画。当然具体情况不会这么简单而往往的其中二或三种的复杂的结合。 而作为游戏它的关键在:在动画的基础上加一些主观的操作。如先画一个球然后用方向键或鼠标移动。如实例: a​ a      新建单文档工程。a​ b      添加半径和圆心intir半径CPointcenter圆心在CMyView()中赋值如下:CMyView::CMyView(){TODO:addconstructioncodeherecenterx=centery=ir=}a​ c      在OnDraw(CDC*pDC)函数中画圆voidCMyView::OnDraw(CDC*pDC){CMyDoc*pDoc=GetDocument()ASSERTVALID(pDoc)TODO:adddrawcodefornativedatahere画圆pDC>Ellipse(centerxir,centeryir,centerxir,centeryir)}a​ d      添加OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags)使它按照键盘方向键的操作而移动圆的位置。如下: voidCMyView::OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags){TODO:Addyourmessagehandlercodehereandorcalldefault利用方向键左右上下移动switch(nChar){caseVKLEFT:centerx=breakcaseVKRIGHT:centerx=breakcaseVKUP:centery=breakcaseVKDOWN:centery=break}重画Invalidate()CView::OnKeyDown(nChar,nRepCnt,nFlags)}a​ e      执行看看效果你就可以操纵了。a​ f       那么利用鼠标又是怎样操作呢?添加OnLButtonDown(UINTnFlags,CPointpoint)如下: voidCMyView::OnLButtonDown(UINTnFlags,CPointpoint){TODO:Addyourmessagehandlercodehereandorcalldefault把圆移动鼠标指定位置圆心赋值为pointcenter=point重画Invalidate()CView::OnLButtonDown(nFlags,point)}a​ g      再执行你现在键盘鼠标都可以操作了。 真正的游戏也就是以上简单的图形或位图的复杂化和简单操作的复杂化而已。     二部分图更新  既然游戏是动画就离不开“动”而所谓“动”就是利用画面的刷新用新的要求的图画或位置去代替原先的图画或位置。图画储存在哪里?内存。画图需要什么?系统资源。而它们有什么关系?成正比。为什么说这些呢?因为这关系到游戏编程一个极大的问题:速度!上面那些简单的例子我们是怎样实现的呢?不就是利用一个控制时间的函数定期地对画面进行重画吗?它们的速度快吗?快。是的但如果你编一个大屏幕的画面并在上面画上几十种图形添上几十种颜色然后再利用上面的方法试试速度还快吗?慢了。为什么?因为这个图画太占用内存需要太多的系统资源我们的机器满足不了要求变慢了。 怎样解决呢?一切的计算机图形都是利用部分图形重画的原理!一种是:只保存要改变的那部分图形然后把要改变的新图接在已保存过画面的范围内形成新的图。接着把刚才保存的图画还原变成原先的图画。再保存另一个地方贴上新图变成新图画再还原。反复进行(如下图)。一种是:不重画直接在要变化的位置变化。 图 实例:一个正方形在复杂的画面上移动。要求:先用全部重画做一次再用部分重画做一次对比一下。a​ a      新建单文档工程添加两个变量:intixunhuanCBitmapmBitmapa​ b      添加位图IDBBITMAP即狮子图象。图 a​ c      在构造函数里面添加两个语句:CMyView::CMyView(){TODO:addconstructioncodehere获得位图mBitmapLoadBitmap(IDBBITMAP)ixunhuan=}a​ d      添加虚函数OnInitialUpdate()初始化位图变量a​ e      添加OnCreate(LPCREATESTRUCTlpCreateStruct)和OnTimer(UINTnIDEvent)函数如下:intCMyView::OnCreate(LPCREATESTRUCTlpCreateStruct){if(CView::OnCreate(lpCreateStruct)==)returnTODO:AddyourspecializedcreationcodehereSetTimer(,,)return} voidCMyView::OnTimer(UINTnIDEvent){TODO:AddyourmessagehandlercodehereandorcalldefaultTODO:Addyourmessagehandlercodehereandorcalldefault即大于后变小ixunhuan=(ixunhuan)Invalidate()CView::OnTimer(nIDEvent)}a​ f       在OnDraw(CDC*pDC)函数中添加画多图形多颜色的语句并加上狮子位图如下:voidCMyView::OnDraw(CDC*pDC){CMyDoc*pDoc=GetDocument()ASSERTVALID(pDoc)TODO:adddrawcodefornativedatahereCDCDcif(DcCreateCompatibleDC(pDC)==FALSE)AfxMessageBox("Can'tcreateDC")画复杂图形有多种颜色for(intj=j<j)for(inti=i<i){CBrushmybrushmybrushCreateSolidBrush(RGB((i*),(j*),(ij)))正方形CRectmyrect(*i,*j,*i,*j)pDC>FillRect(myrect,mybrush)圆pDC>Ellipse(*i,*j,*i,*j)小正方形CRectmyrect(*i,*j,*i,*j)pDC>FillRect(myrect,mybrush)小圆pDC>Ellipse(*i,*j,*i,*j)更小正方形CRectmyrect(*i,*j,*i,*j)pDC>FillRect(myrect,mybrush)更小圆pDC>Ellipse(*i,*j,*i,*j)最小正方形CRectmyrect(*i,*j,*i,*j)pDC>FillRect(myrect,mybrush)}在不同位置显示位图DcSelectObject(mBitmap)pDC>StretchBlt(ixunhuan,,,,Dc,,,,,SRCCOPY)}a​ g      执行你就可以看到它重画时有多慢了。a​ h      现在再用部分重画做:把OnTimer(UINTnIDEvent)函数改为如下:voidCMyView::OnTimer(UINTnIDEvent){TODO:AddyourmessagehandlercodehereandorcalldefaultTODO:Addyourmessagehandlercodehereandorcalldefaultixunhuan=(ixunhuan)如果图象回到开头全部重画if(ixunhuan<)Invalidate()设置部分更新区域CRectrrleft=ixunhuanrtop=rbottom=rtoprright=rleft部分更新函数InvalidateRect(r,TRUE)CView::OnTimer(nIDEvent)}a​ i        执行现在感觉怎样是不是变快了。看看图象在头尾交换时的对比就知道了。当然上面的程序并不是很好。例如如此复杂的背景大可用一张图代替而那狮子也不行它覆盖了背景怎么办呢?下面就谈消去狮子位图的白色(或其它颜色)背景的方法。  三设置透明背景  游戏无非就是由核心操作和界面组成。界面一般都有前景背景背景一般是显示一张大的位图前景一般是被人操作(或计算机模拟人操作)的那部分。背景位图一般都是覆盖了整个界面它周围整洁只要你把它画好了加上去就行而前景位图不同它一般是不规矩的如飞机、动物、人物等。而像上例狮子位图的周围是原位图的颜色而不是背景的颜色不好看。那么怎样把前景位图的背景颜色去掉而使背景位图能看到呢?就是本节的内容。实现的原理是:指定一种颜色然后对这种颜色进行处理使它的色素不画出来。如上面的狮子指定白色RGB(,,)为透明色就行了。下面就介绍一个函数TransparentBitmap():本函数把一种指定的颜色变成透明色并可改变大小hdc显示句柄hBitmap要显示的位图xStartxStart显示的位置xadd,yadd显示的位图的大小变化:放大缩小如:xadd=表示位图宽度加cTransparentColor变成透明的那种颜色voidCMyView::TransparentBitmap(HDChdc,HBITMAPhBitmap,shortxStart,shortyStart,shortxadd,shortyadd,COLORREFcTransparentColor){BITMAPmbmCOLORREFcColor创建临时DCHDChMem,hBack,hObject,hTemp,hSavehBack=CreateCompatibleDC(hdc)hObject=CreateCompatibleDC(hdc)hMem=CreateCompatibleDC(hdc)hSave=CreateCompatibleDC(hdc)hTemp=CreateCompatibleDC(hdc)选入位图SelectObject(hTemp,hBitmap)GetObject(hBitmap,sizeof(BITMAP),(LPSTR)mbm)显示位图宽高POINTptSize取得位图的宽度ptSizex=mbmbmWidth取得位图的该度ptSizey=mbmbmHeight转换为逻辑点值DPtoLP(hTemp,ptSize,)创建临时位图HBITMAPbmBack,bmObject,bmMem,bmSave单色位图bmBack=CreateBitmap(ptSizex,ptSizey,,,)bmObject=CreateBitmap(ptSizex,ptSizey,,,)与设备兼容位图bmMem=CreateCompatibleBitmap(hdc,ptSizex,ptSizey)bmSave=CreateCompatibleBitmap(hdc,ptSizex,ptSizey) 将创建的临时位图选入临时DC中HBITMAPOldbmBack,OldbmObject,OldbmMem,OldbmSaveOldbmBack=(HBITMAP)SelectObject(hBack,bmBack)OldbmObject=(HBITMAP)SelectObject(hObject,bmObject)OldbmMem=(HBITMAP)SelectObject(hMem,bmMem)OldbmSave=(HBITMAP)SelectObject(hSave,bmSave) 设置映射模式SetMapMode(hTemp,GetMapMode(hdc))先保留原始位图BitBlt(hSave,,,ptSizex,ptSizey,hTemp,,,SRCCOPY)将背景颜色设置为需透明的颜色cColor=SetBkColor(hTemp,cTransparentColor)创建目标屏蔽码BitBlt(hObject,,,ptSizex,ptSizey,hTemp,,,SRCCOPY)恢复源DC的原始背景色SetBkColor(hTemp,cColor) 创建反转的目标屏蔽码BitBlt(hBack,,,ptSizex,ptSizey,hObject,,,NOTSRCCOPY)拷贝主DC的背景到目标DCBitBlt(hMem,,,ptSizex,ptSizey,hdc,xStart,yStart,SRCCOPY)屏蔽位图的显示区BitBlt(hMem,,,ptSizex,ptSizey,hObject,,,SRCAND)屏蔽位图中的透明色BitBlt(hTemp,,,ptSizex,ptSizey,hBack,,,SRCAND)将位图与目标DC的背景左异或操作BitBlt(hMem,,,ptSizex,ptSizey,hTemp,,,SRCPAINT)拷贝目标到屏幕上StretchBlt(hdc,xStart,yStart,ptSizexxadd,ptSizeyyadd,hMem,,,ptSizex,ptSizey,SRCCOPY)恢复原始位图BitBlt(hTemp,,,ptSizex,ptSizey,hSave,,,SRCCOPY) 删除临时内存位图DeleteObject(SelectObject(hBack,OldbmBack))DeleteObject(SelectObject(hObject,OldbmObject))DeleteObject(SelectObject(hMem,OldbmMem))DeleteObject(SelectObject(hSave,OldbmSave)) 删除临时内存DCDeleteDC(hMem)DeleteDC(hBack)DeleteDC(hObject)DeleteDC(hSave)DeleteDC(hTemp)} 注释已经写得很清楚了用时只要按照要求在函数括号里加上各个值就行了。下面用实例演示一下:a​ a      新建单文档工程加上变量如下:(注释已在上面)shortxStartshortyStartshortxaddshortyaddCBitmapmBitmapCOLORREFcTransparentColora​ b      在函数CMyView()加上以下语句:CMyView::CMyView(){TODO:addconstructioncodeherexStart=yStart=xadd=yadd=mBitmapLoadBitmap(IDBBITMAP)cTransparentColor=RGB(,,)} a​ c      添加上面的狮子位图。a​ d      加上OnCreate(LPCREATESTRUCTlpCreateStruct)和OnTimer(UINTnIDEvent)函数如下:intCMyView::OnCreate(LPCREATESTRUCTlpCreateStruct){if(CView::OnCreate(lpCreateStruct)==)returnTODO:AddyourspecializedcreationcodehereSetTimer(,,)return} voidCMyView::OnTimer(UINTnIDEvent){TODO:Addyourmessagehandlercodehereandorcalldefault获取指针pdcCDC*pDC=GetDC()调用OnDraw(pDC)重画OnDraw(pDC)CClientDCdc(this)向右向下移动xStart=yStart=位图宽高加xadd=yadd=显示TransparentBitmap(dcGetSafeHdc(),mBitmap,xStart,yStart,xadd,yadd,cTransparentColor)CView::OnTimer(nIDEvent)}a​ e      上面的“透明位图”函数还没有定义必须把开头的函数添加进来。把函数整个拷贝到Viewcpp,然后在Viewh中加上:voidTransparentBitmap(HDChdc,HBITMAPhBitmap,shortxStart,shortyStart,shortxadd,shortyadd,COLORREFcTransparentColor)a​ f       最后在函数OnDraw(CDC*pDC)加上背景:voidCMyView::OnDraw(CDC*pDC){CMyDoc*pDoc=GetDocument()ASSERTVALID(pDoc)TODO:adddrawcodefornativedatahere画红色背景CBrushmybrushmybrushCreateSolidBrush(RGB(,,))CRectmyrect(,,,)pDC>FillRect(myrect,mybrush)} a​ g      运行怎么样?图象还会变大呢!  四显示对称图像 上面既然谈到了位图的透明显示那么我们经常用到的另外一种显示方式:对称也就该接着说明一下。毕竟无论是人或是景我们都讲究对称特别是中国人无论你向左还是向右它的图像一般也是讲究对称的。既然对称在我们的社会里在我们的文化中是多么地受到人们的追求人们是非常强烈地以对称为美我们就必须学会怎样用程序来实现它。这也就是我把它放在前面讲的原因。下面我们就来说明对称位图的实现。我们的程序语言里面有许多关于位图的操作包括位图的复制放大缩小位图的反转甚至布尔运算。但是我们找不到对称的操作。开始我也不知道该怎么办难道一边看着位图一边对称地画另一张位图吗?事实上我差一点就这么做了。但是我突然发现我可以一行一行地利用复制的方法在原来的位图上面复制一行或一列然后粘贴到另一张位图上面对称的地方去。我是这么做了并且由于我的这个实践我发现我根本就可以利用程序的for循环来帮助我完成这一件事。甚至让它能够按照我们的意愿放大缩小按照我们的意愿在我们希望的位置显示。实例如下:添加单文档工程,添加一个位图改变如下函数:由于下面说明清楚不再细说。voidCMyView::OnDraw(CDC*pDC){CMyDoc*pDoc=GetDocument()ASSERTVALID(pDoc)TODO:adddrawcodefornativedatahere intx,y,width,height,i设置反面显示位图的起点和大小可以在别的地方设置赋值x=y=width=height= BITMAPmbmCDCDcif(DcCreateCompatibleDC(pDC)==FALSE)AfxMessageBox("Can'tcreateDC")选入位图DcSelectObject(bitmap)GetObject(bitmap,sizeof(BITMAP),(LPSTR)mbm)显示位图宽高POINTptSize取得位图的宽度ptSizex=mbmbmWidth取得位图的该度ptSizey=mbmbmHeight显示正面位图pDC>StretchBlt(,,,,Dc,,,ptSizex,ptSizey,SRCCOPY)显示反面位图以下参数的说明:x(i*widthptSizex)表示每个循环的起点位置其中widthptSizex表示每次移动的大小y为显示的topheight为显示位图的高度ptSizexi为每次SRCCOPY的起点x在不同位置显示位图for(i=i<ptSizexi)pDC>StretchBlt(x(i*widthptSizex),y,widthptSizex,height,Dc,ptSizexi,,,ptSizey,SRCCOPY) } 运行效果就在第一页。  五游戏的内核  上面所说的并不是游戏它只能算是游戏中的一些元素。一个游戏不可能只是表面图形这么简单我们还没有谈到它的实质的东西内核。我们后面将讲到的挖雷游戏、俄罗斯方块等都是一些简单的游戏可是第一次接触时你能说出它的原理吗?它是怎么实现的吗?游戏的核心并不是我们所看到的图形反而是我们所看不到的游戏的算法。那么游戏的图形和核心之间是怎么联系的呢?例如我们怎么利用键盘的方向键来控制俄罗斯方块的移动和转变呢?我们又如何利用鼠标来对挖雷游戏进行操作呢?游戏的图形和核心的联系是必然的。但我之所以要说是因为我想告诉你:正是这个联系障碍了人们编程的思路!其实它们的联系就像两个城市之间的那条公路一样连接着它们事实上是两个整体是分离的。为什么?什么是游戏?游戏本来就是一种变化过程它是无形的是不依奈图形而存在的。我们可以举一个例子先编好一个游戏(如俄罗斯方块)运行它你可以高兴地玩了。然后你再修改一下把它的左(或右)半边用一张鲜花美女图象盖上去然后再一次运行游戏虽然你只能到一半游戏界面但你依然可以玩游戏。或许说游戏依然正常运行。那么我们把整个界面都盖上不难想象游戏还是会正常运行的。由此可见游戏本来就是存在的它是无形的是不依奈于图形界面的。即使你编一个没有界面的俄罗斯方块游戏它也能运行它是一个我们只知道开始和结束的游戏是不为人们所喜欢的。游戏可以说是不依奈于图形而存在的如果你不想让别人玩的话。而图形的存在就是为了别人可以玩。它是作用就是让你看清楚游戏的进程让你更好地把握你所玩的游戏罢了。用上面的城市来说核心城市并不依奈于图形城市不与图形城市交流核心城市依然能发展下去如没有界面的俄罗斯方块游戏而图形城市也不依奈于核心城市如上面的鲜花美女图象。但是我们编程并不希望它们各自独立我们要利用它们的联系来展开我们的游戏。于是我们就朝着文明发展的方向为它们建了高速公路。我们究竟是怎样联系它们的呢?我们怎样把它们同步实现呢?事实上我们所看到的同步并不是真的!只是一种错觉!核心城市每时每刻都在发展而图形城市并不是每时每刻都知道核心城市的发展情况的它只是每隔一段时间才去了解一下情况或许核心城市有情况传来时图形城市才知道的这时图形界面才改变给人看。游戏编程就是你把实质的东西全部用算法在核心城市表现出来然后再依照你的要求把那些要让人看的东西让图形城市知道让图形城市帮你公布到界面上。

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

文档小程序码

使用微信“扫一扫”扫码寻找文档

1

打开微信

2

扫描小程序码

3

发布寻找信息

4

等待寻找结果

我知道了
评分:

/14

VC++游戏编程

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利