CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  专题开发/技术/项目 >  游戏开发

游戏入门

楼主sttony(冥界来客)2001-11-03 14:17:46 在 专题开发/技术/项目 / 游戏开发 提问

                                                                                                                                                            游戏入门      
           
   
      if(!你喜欢游戏)exit(0);  
          if(你精通游戏编程)exit(0);  
          各位游戏fans是否想过编自己的游戏。小弟我学习这个问题很久了,从DOS时代的ModeX到Windows下的DirectX,其间略有所得。愿我的经验和教训,为大家抛砖引玉,引出中国的世界级游戏大作,拿起你的笔开始写游戏吧!  
      什么是游戏呢?从最原始的游戏机到现在,游戏已经越来越精美,种类也越来越多,角色扮演、即时战略、第一人称射击等等。这些游戏的共性是什么呢?就我个人看来,游戏有一个游戏空间,有一套游戏规则和将游戏空间和游戏规则封装起来的交互界面。玩家(人或AI)通过交互界面,遵循游戏规则去改变游戏空间的状态(当然电脑可以绕过交互界面),直到游戏结束。无论什么游戏都可归结为此。  
      比如下象棋。游戏空间可描述为一个矩阵,矩阵中的元素有“无”、“车”、“将”等属性。游戏规则自然是象棋的规则了。棋盘棋子组成交互界面。下棋时,通过棋盘棋子去改变游戏空间,当然必须遵循各种棋子的走法。有一步时,游戏空间中少了有“将”或“帅”属性的元素,则下完了。与电脑对弈时,电脑可以直接改变游戏空间,但改变必须通过交互界面表现出来。  
      举一个电脑游戏的例子,如Starcraft。表示地形、建筑、部队的数据结构构成了游戏空间。各兵种的攻防,建筑的防护,生产的速度等等内容是人和电脑都要遵守的规则(不排除有些游戏中用作弊以掩盖AI太低的做法)。至于Starcraft的交互界面大家一定都很熟了吧,我就不再罗嗦了!  
      游戏空间和规则可化为内核,在电脑游戏中,AI也可算内核的一部分。现在有些游戏,只注重交互界面而不注重内核。比如有些游戏换成了花里胡哨的3D界面,而内核则和几年前的老前辈一模一样,实在……  
      现在,大家对如何实现游戏有了一个大概了解了吧!根据这个框架就可以有如下的实现方法:首先用数学模型表示游戏空间,然后将数学模型反映到交互界面上去。当玩家产生一个输入时,由交互界面处理,按游戏规则改变游戏空间,再将游戏空间反映到交互界面上。重复该过程直到游戏结束。  
      虽然游戏的内核是吸引玩家的关键,但再好的内核也需要交互界面来表现。交互界面,多数时候是图形动画,对游戏来说也是十分重要的。下面讲一讲动画的基本原理。  
          现在做动画的软件很多Flash,Director等等,但用程序去实现动画就必须从动画的基本原理入手。动画和电影一样,将差异很小的图像一幅幅显示,由于人眼的视觉暂留现象,看上去就像图像动了起来。比如在RPG中,我们要实现主角从(x1,y1)移动到(x2,y2)处,我们可用如下代码:  
              while(主角不在(x2,y2)){  
                      在主角(x,y)处恢复背景;  
                      在(x+dx,y+dy)处重绘主角;  
                      x=x+dx;y=y+dy;  
              };  
              当主角很小时,这种方法是可行的,但主角稍大,就会出现闪烁现象。闪烁的原因不是因为你的CPU和GPU不够快,而同样是因为视觉暂留。当你恢复背景之后,屏幕上没有主角,虽然这个过程很短,但由于视觉暂留的原因,这幅图仍然会在你的眼中持续一段时间,你就会觉得主角一会出现一会儿消失。解决的方法是双缓冲技术。即构造两个屏幕缓冲区,一个表示当前屏幕,一个在后台表示下一帧的屏幕。在后台缓冲区上画好下一帧后,一次性送到前台上去,这样就不会出现闪烁现象了。刚才的过程可以描述为:  
          while(主角不在(x2,y2)){  
                          在后台缓冲恢复背景;  
                  在后台缓冲(x+dx,y+dy)处恢主角;  
                          将后台缓冲送到前台;  
                          x=x+dx;y=y+dy;  
                  };      
              以上过程在ModeX下可用VGA的寄存器置位来实现,在DirectX中可用Flip或Blt实现。ModeX是实模式下的编程方式,以前DOS下的游戏经常使用,在《图形编程人员手册》(作者是编写QUACK   I     小组的成员)中详细讲述了Mode   13和Mode   X下如何编程。DirectX,什么你不知道?你是游戏Fans吗?  
   
   
                  说了这么多枯燥的理论,下面   --开始编程了。  
          游戏SDK属DirectX和OpenGL(OpenGL的主要用途并不是编游戏),这里我们主要讲DirectX中的DirectDraw。因为三维图形编程非常复杂,需要大量图形学的知识,非几篇文章可以讲清的。我们不用3D方式,Direct3D和OpenGL就用不上了,各位Fans如果对3D编程感兴趣,努力去学计算机图形学吧!  
                  用DirectX编程就需要编译器和DirectX的SDK。我使用的是MS的VC++6.0和DirectX7.0的SDK。一般DirectX7.0的安装组件是不行的,需要一份207MB的SDK。假定SDK安装在E:\mssdk\,文件夹下会有bin,doc,   include,   lib   ,samples几个文件来。对我们最有用的是inlude和lib文件夹,编译器需要的头文件和库文件都在这里。VC++6.0自带对DirectX5.0的支持,要使VC使用新版的头文件和库文件,需要作如下设置:在Tools     ->   Option的Directories标签下,为include   files   和library   files分别添加E:\mssdk\include   和   E:\mssdk\lib   ,注意,应放在最前面。  
          做完了上述准备活动后,我们就可以使用DirectX7.0的强大功能了。下面让我们小试牛刀一把!  
          创建一个空的Win32   Application工程。在Project   ->   Settings的Link标签下的Object/library   modules     中添加ddraw.lib   和dxguid.lib(用到其他库时应添加相应的库)。  
          头文伴Dobject.h  
              #include   <ddraw.h>  
              int   TIMER;  
              LPDIRECTDRAW         pDD;  
              LPDIRECTDRAW7     pDD7;  
              LPDIRECTDRAWSURFACE7     pDDSPrimary=NULL;  
              LPDIRECTDRAWSURFACE7     pDDSBack=NULL;  
              int   bActive;  
              本文件定义了所用的全局变量。LPDIRECTDRAW7是指向DirectDraw7对象接口的指针,LPDIRECTDRAWSURFACE7是指向DirectDrawSurface7对象接口的指针。TIMER是一个定时器,bActive则是表示窗口是否被激活。  
   
          头文件   Dfun.h  
              #include   "windows.h"  
              int   CreateDrawScreen(int   cx,int   cy,int   bit_depth,HWND   hwnd);  
              int   onTIMER(HWND   hwnd,   UINT   iMsg,   WPARAM   wParam,LPARAM   lParam);  
              int   onKEYDOWN(HWND   hwnd,   UINT   iMsg,   WPARAM   wParam,LPARAM   lParam);  
              int   UpdataBackSurface(HWND   hwnd);  
              int   ReleaseAllObjects(void);  
              这里定义了全局函数。这些函数从名字上一看即知其用途,我就不细讲了。至于定义为int,纯属小弟我的习惯。  
   
          源文件DD1main.cpp  
              #include   "Dfun.h"  
              #include   <windows.h>  
              HINSTANCE     pInstance;  
              LRESULT   CALLBACK   WndProc   (HWND,   UINT,   WPARAM,   LPARAM)   ;  
              int   WINAPI   WinMain   (HINSTANCE   hInstance,   HINSTANCE   hPrevInstance,  
                                          PSTR   szCmdLine,   int   iCmdShow)   {  
   
                              static   char   szAppName[]   =   "AppName"   ;   //   Application   name  
                              HWND                 hwnd   ;  
                              MSG                 msg   ;  
                              extern   int   TIMER;  
                              WNDCLASSEX     wndclass   ;  
                              wndclass.cbSize                 =   sizeof   (wndclass)   ;  
                              wndclass.style                 =   CS_HREDRAW   &brvbar;   CS_VREDRAW   ;  
                              wndclass.lpfnWndProc     =   WndProc   ;  
                              wndclass.cbClsExtra         =   0   ;  
                              wndclass.cbWndExtra         =   0   ;  
                              wndclass.hInstance         =   hInstance   ;  
                              wndclass.hIcon                 =   LoadIcon   (NULL,   IDI_APPLICATION)   ;  
                              wndclass.hCursor             =   LoadCursor   (NULL,   IDC_ARROW)   ;  
                              wndclass.hbrBackground   =   (HBRUSH)   GetStockObject                                                                                                                                                                             (BLACK_BRUSH)   ;  
                          wndclass.lpszMenuName     =   NULL   ;  
                          wndclass.lpszClassName   =   szAppName   ;    
                          wndclass.hIconSm             =   LoadIcon   (NULL,   IDI_APPLICATION)   ;  
                    pInstance   =   hInstance;  
                          //   Registering   the   structure   wmdclass  
                          RegisterClassEx   (&wndclass)   ;  
                          //   CreateWindow()  
  /*1*/         hwnd   =   CreateWindowEx   (WS_EX_TOPMOST,  
                                                                      szAppName,  
                                                                                                      "DD1",                 //   window   caption  
  /*2*/                                                                                         WS_POPUP&brvbar;WS_MINIMIZE,         //   window   style  
                                                                                                      CW_USEDEFAULT,                     //   initial   x   position  
                                                                                                      CW_USEDEFAULT,                     //   initial   y   position  
  /*3*/                                                                                         GetSystemMetrics(SM_CXSCREEN),                     //   initial   x   size  
  /*4*/                                                                                         GetSystemMetrics(SM_CYSCREEN),                     //   initial   y   size  
                                                                                                      NULL,                                         //   parent   window   handle  
                                                                                                      NULL,                                         //   window   menu   handle  
                                                                                                      hInstance,                             //   program   instance   handle  
                                                                                                      NULL)   ;                                     //   creation   parameters  
                          ShowWindow   (hwnd,   iCmdShow)   ;  
  /*5*/             CreateDrawScreen(640,480,16,hwnd);  
                          SetTimer(hwnd,TIMER,200,NULL);  
                          while   (GetMessage   (&msg,   NULL,   0,   0))  
                          {  
                                  TranslateMessage   (&msg)   ;  
                                  DispatchMessage   (&msg)   ;  
                          }  
                      return   msg.wParam   ;  
              }  
          //****************************  
          //         Windows   Procedure  
          //****************************  
          LRESULT   CALLBACK   WndProc   (HWND   hwnd,   UINT   iMsg,   WPARAM   wParam,  
          LPARAM   lParam)  
          {         extern   int   bActive;  
           
   
                  switch   (iMsg)  
                  {     case   WM_KEYDOWN:  
                          onKEYDOWN(hwnd,iMsg,wParam,lParam);  
                          break;  
            case   WM_TIMER:  
                          onTIMER(hwnd,iMsg,wParam,lParam);  
                          break;  
            case   WM_ACTIVATE:  
                                          bActive   =   !((BOOL)HIWORD(wParam));  
                          return   0;  
                          break;  
            case   WM_DESTROY:  
                                          PostQuitMessage(0);  
                                          ReleaseAllObjects();  
                          return   0;  
                      }  
                      return   DefWindowProc   (hwnd,   iMsg,   wParam,   lParam)   ;  
          }      
          这个源文件应改是大家比较熟悉的(什么?你不会用Win32API编程!快去找本书学习一下)。需要注意的地方,我都加了号。/*1*/行我们将窗口属性设为TOPMOST,同时在/*2*/和/*3*/行设置了POPUP和MINIZE属性。因为DirectDraw程序一般以全屏独占模式运行,所以设为没有标题栏和边框的弹出式窗口,并且总在最上方,而MINIZE使你的窗口可以最小化,否则别的应用程序无法激活。为了使窗口以全屏大小运行,在/*4*//*5*/行用GetSystemMetrics(     )函数取得屏幕大小,并将窗口设为屏幕大小。ShowWindow()之后,我们调用CreateDrawSurface()函数将分辩率设为640*480*16位色,并初始化了全局变量。接着用SetTimer()设置了一个每200亳秒产生一个WM_TIMER消息的定时器。  
   
      源文件Dfun.cpp  
          #include   "Dobject.h"  
          #include   "Dfun.h"  
          #include   <windows.h>  
          int   ReleaseAllObjects()  
          {      
          if   (pDD7!=   NULL)  
              {     if(pDDSBack!=NULL){  
                      pDDSBack->Release();  
                      pDDSBack=NULL;  
                  }  
                  if   (pDDSPrimary   !=   NULL)  
                  {  
                          pDDSPrimary->Release();  
                          pDDSPrimary   =   NULL;  
                  }  
                  pDD7->Release();  
                  pDD7=   NULL;  
          }  
          return   1;  
          };  
          int   UpdataBackSurface(HWND   hwnd)  
          {     DDBLTFX                                         ddbltfx;  
                  RECT                                                 rc;  
              HRESULT                                         hRet;  
          static   int   phase=0;  
          HDC   hdc;  
          ZeroMemory(&ddbltfx,   sizeof(ddbltfx));  
                  ddbltfx.dwSize=sizeof(ddbltfx);  
                  ddbltfx.dwFillColor=0;  
          pDDSBack->Blt(NULL,   NULL,   NULL,   DDBLT_COLORFILL   &brvbar;   DDBLT_WAIT,   &ddbltfx);  
                  //insert   Draw   Suface   code   end  
          if   (pDDSBack->GetDC(&hdc)   ==   DD_OK)  
                  {  
                      SetBkColor(hdc,   RGB(0,   0,   255));  
                      SetTextColor(hdc,   RGB(255,   255,   0));  
                      GetClientRect(hwnd,   &rc);  
                  if   (phase)  
                      {     DrawText(hdc,"你好",-1,&rc,DT_CENTER);  
                  phase=0;  
                  }else{  
                  DrawText(hdc,"DirectTex",-1,&rc,DT_TOP);  
                  phase=1;  
                  };  
                  pDDSBack->ReleaseDC(hdc);  
          }  
              return   1;  
          }  
          int   CreateDrawScreen(int   cx,int   cy,int   bit_depth,HWND   hwnd)  
          {     HRESULT   hRet;  
                  DDSURFACEDESC2   ddsc;  
                  DDSCAPS2             ddsCaps;  
          hRet=DirectDrawCreateEx(NULL,(void**)&pDD7,IID_IDirectDraw7,NULL);  
          if(hRet!=DD_OK)return   0;  
                  hRet=pDD7->SetCooperativeLevel(hwnd,DDSCL_EXCLUSIVE   &brvbar;   DDSCL_FULLSCREEN);  
                  if(hRet!=DD_OK)return   0;  
                  hRet=pDD7->SetDisplayMode(cx,cy,bit_depth,NULL,NULL);  
          if(hRet!=DD_OK)return   0;  
                  ZeroMemory(&ddsc,   sizeof(ddsc));  
          ddsc.dwSize=sizeof(ddsc);  
          ddsc.dwFlags=DDSD_CAPS   &brvbar;   DDSD_BACKBUFFERCOUNT;  
          ddsc.ddsCaps.dwCaps   =   DDSCAPS_PRIMARYSURFACE&brvbar;DDSCAPS_FLIP   &brvbar;                                             DDSCAPS_COMPLEX;  
                  ddsc.dwBackBufferCount   =   1;  
          hRet=pDD7->CreateSurface(&ddsc,&pDDSPrimary,NULL);  
          if(hRet!=DD_OK)return   0;  
          ZeroMemory(&ddsCaps,   sizeof(ddsCaps));  
                  ddsCaps.dwCaps   =   DDSCAPS_BACKBUFFER;  
          hRet=pDDSPrimary->GetAttachedSurface(&ddsCaps,&pDDSBack);  
          if(hRet!=DD_OK)return   0;  
                  return   1;  
              };  
              int   onTIMER(HWND   hwnd,   UINT   iMsg,   WPARAM   wParam,LPARAM   lParam)  
              {     HRESULT   hRet;  
          if(bActive&&TIMER==wParam){  
              UpdataBackSurface(hwnd);  
              while(1){  
                      hRet=pDDSPrimary->Flip(NULL,   0);  
                      if   (hRet==DD_OK)break;  
                      if   (hRet==DDERR_SURFACELOST){  
                              hRet=pDDSPrimary->Restore();  
                              if   (hRet   !=   DD_OK)break;  
                      }  
                      if   (hRet!=   DDERR_WASSTILLDRAWING)break;  
              };  
          };              
          return   1;  
              };  
              int   onKEYDOWN(HWND   hwnd,   UINT   iMsg,   WPARAM   wParam,LPARAM   lParam)  
          {    
                      switch(wParam)  
          {  
                  case   VK_F12:  
                  case   VK_F11:  
                          PostQuitMessage(0);  
                          ReleaseAllObjects();  
                          return   0;  
          };  
              return   0;  
              }  
              本文件集中了关键性代码,一定要注意了。ReleaseAllObjects(     )函数释放所有的全局对象。onKEYDOWN()就不用我说了吧!CreateDrawScreen()完成了所有DirectDraw对象的初始化工作。首先当然是创建一个DriectDraw对象并使pDD7指向他接口。然后设置合作等级为全屏独占模式。设为独占模式后才能设分辩率为640*480*16bit。下一步是创建表面,这里创建了一个复杂的表面,一个由pDDSPrimary和pDDSBack所指向的两个DirectDrawSurface7对象组成的Flip队列。pDDSBack指向的DirectDrawSurface7对象是附加到主表面上的。CreateDrawScreen()是一个通用的函数,以后的程序都可以重用他。  
          onTIMER()函数响应TIMER定时器。如果本程序被激活,则更新后缓冲表面,然后Flip(翻转)到前台。UpdataBackSurface()先用无源表面的Blt(位块传输)是整个表面被黑色填充,再通过DirectDrawSurface对象的GetDC方法得到一个与普通DC完全兼容的DC,然后用API函数DrawText输出文本。简单吧,有了DC,Win32API都可用了。  
          编译,链接之后,运行。你可以看到两行文字在屏幕上闪烁。看上去很简单,但DriectDraw的两个关键方法   Blt   和Flip   都用上了。可能讲的不明白,下次再仔细的讲DirectDraw,DirectDrawSurface,以及高性能的动画   。   问题点数:20、回复次数:16Top

1 楼windindance(风舞轻扬·白首为功名)回复于 2001-11-03 14:21:16 得分 0

关注Top

2 楼xxjiang(箫湘)回复于 2001-11-03 19:16:34 得分 0

刚才看了你以前发的帖子,忘了加分,特来补上。  
  在那里留了言,希望你去看看,交个朋友!Top

3 楼yeahwin(佳佳幼儿园)回复于 2001-11-03 20:00:23 得分 0

兴趣~好  
  GZ~Top

4 楼jerry_baimor(崇拜starfish)回复于 2001-11-10 11:39:04 得分 0

关注。Top

5 楼jackhacker()回复于 2001-11-11 09:24:31 得分 0

很好Top

6 楼chenweijin(陈伟金)回复于 2001-11-11 11:56:11 得分 0

能教我吗?Top

7 楼jhwh(弹剑长歌(搬个凳子来灌水))回复于 2001-11-11 12:53:29 得分 5

最好的教程是M$的   GemeSDKTop

8 楼jackhacker()回复于 2001-12-25 20:11:45 得分 5

gamesdk???Top

9 楼zhouqin442(妖刀)回复于 2001-12-25 22:31:51 得分 5

程序错误百出!Top

10 楼KingofMagic(大魔头)回复于 2001-12-26 08:57:57 得分 0

?????!!!!!!!!!!!Top

11 楼wangqiqi(polymath)回复于 2001-12-26 13:04:48 得分 0

你把内核和外壳搞反了。  
  3D   图象显示是游戏的内核(ENGINE)而游戏的规则等是在引擎的基础上编写的。Top

12 楼liutuohb()回复于 2001-12-26 22:33:58 得分 0

留个QQ  
  56235872Top

13 楼kingofark(平凡的丑人)回复于 2001-12-27 09:04:18 得分 5

大家不妨去看看  
   
  www.lostsidedead.com   上面有用极小的图形库编程简单游戏的C++源代码,非常适合初学入门。  
   
  www.1cplusplusstreet.com   上面有很多游戏源代码,也都很不错。Top

14 楼ilovesex(爱在性)回复于 2001-12-27 10:56:46 得分 0

好哦,我会去看的。Top

15 楼KingofMagic(大魔头)回复于 2001-12-28 09:05:42 得分 0

只是把那几个通用的例子变了一种形式说出来吧了!Top

16 楼hoomail(lh)回复于 2001-12-28 16:52:43 得分 0

厉害!Top

相关问题

  • 搞游戏开发怎样入门?
  • 刚入门,想编一个扫雷的小游戏,请教
  • 新手,想开发小游戏,征求入门建议。
  • 关于手机游戏开发的一个入门问题
  • 请问《c游戏编程 从入门到精通》这本书怎么样?
  • 【请教】手机游戏开发入门文章和技术站点
  • 高分求C游戏编程从入门到精通光盘代码
  • 高分求C游戏编程从入门到精通电子版!谢谢
  • 介绍一本好点的手机游戏开发的入门的书
  • 入门!

关键词

  • vc++
  • win32
  • 游戏
  • 交互
  • 界面
  • 函数
  • directx
  • 图形
  • 屏幕
  • pddsback

得分解答快速导航

  • 帖主:sttony
  • jhwh
  • jackhacker
  • zhouqin442
  • kingofark

相关链接

  • CSDN Blog
  • 技术文档
  • 代码下载
  • 第二书店
  • 读书频道

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo