精华内容
下载资源
问答
  • Visual C++游戏开发经典案例详解.pdf

    千次下载 热门讨论 2012-03-01 08:45:15
    Visual C++游戏开发经典案例详解.pdf
  • c++ 游戏服务器框架socket 包括服务器 客户端 ,项目剥离
  • C++游戏引擎开发

    千次阅读 2019-02-01 15:42:59
    C++游戏引擎开发
                   

    游戏引擎开发

    用C++实现跨平台游戏引擎开发

      你是否梦想写一部格斗游戏但却无从着手呢?是否你只因游戏开发好玩而对之感兴趣?本文我们将分析一个通用的跨平台游戏引擎,每个游戏开发新手都可以自由地使用它。

      1. 3D游戏引擎的简短历史

      在游戏开发中,从一开始就确定正确的开发平台是很重要的。是否你的游戏支持Windows,Linux和OS X?是否你的游戏开发只使用OpenGL就足够了?OpenGL是十九世纪九十年代初期设计的,起初只运行于价值约$25,000的Unix CAD工作站上,后来移植到Windows和其它一些低端平台上。与此同时,随着游戏工业的发展,图形加速器价格从$2,000剧跌到你今天看到的价值约$150的大众市场价格。

      确实,许多人都会援引在1996年用OpenGL开发成功的革命性的游戏Quake,作为以上急速发展现象的直接的原因。然而,成功的Quake级的游戏开发标准要求更多:世界级音频支持,网络连接,用户输入设备支持,以及实时的管理能力等。既需要实现跨平台支持又能使游戏效果激动人心,要实现这样的解决方案最好建立一个体面的游戏开发站台。

      2. 用于C++,Java和其它开发语言的简单DirectMedia层

      对,历史就是这样有趣,但并不是每一部游戏都要做成Quake的克隆品。一直被业界许多人吹捧有着许多优点的选择是简单DirectMedia层(SDML)。这是一套跨平台的多媒体库,它提供对于音频,键盘,鼠标,游戏杆,OpenGL和2D视频帧缓冲的低级存取。SDML支持几乎我能想像出的每一个平台,包括Linux,Windows,所有的MacOS变异物,WinCE,Dreamcast还有另外一些操作系统。它被广泛应用于开发MPEG播放器,硬件仿真器,和许多流行的游戏,包括获奖的运行于Linux平台的Civilization:Call to Power。

      SDML用C写成,但生来就与C++一起工作,已经绑定到了另外许多语言,包括Ada,Eiffel,Java,Lua,ML,Perl,PHP,Pike,Python和Ruby。SDML的应用环境简直就没有什么限制,而且它碰巧是我最喜爱的开源飞行模拟器GL-117(见图1)的开发引擎。事实上,513游戏的当前开发已经基于SDML引擎而且被注册到了SDML的主页。


    图1.GL-117中的一个视图


      3. 通道视觉效果演示程序

      研究游戏引擎的最好方法是看一些示例程序代码。简单地看一下图2中用SDML实现的2D通道类型演示图,你就能发现你仅用几行代码所能完成的工作。你可以使用该实例作为一个保护屏程序,音乐可视化动画效果,等等。篇幅所限,我已经整理了实际的绘制代码。请跟随我的注释分析下面对SDML的工作原理的描述:

    #include "Tunnel.h"
    // SDL 相关变量定义
    SDL_Surface *screen,*bBuffer,*Image;
    SDL_Rect rScreen,rBuffer;
    int main (int argc, char **argv)
    {
     int flag = SDL_SWSURFACE;// 请求一个软件表面.
     //软件表面处于系统内存中,
     // 一般不如硬件表面速度快
     #ifdef WIN32
     int fullscreen = MessageBox(NULL, "Show Full Screen (y/n):","Screen Setting", MB_YESNO);
     if (fullscreen==IDYES) {
      flag |= SDL_FULLSCREEN; // 如果用户需要,接管整个屏幕
     }
     #endif
     Tunnel_Timer(); // 读取起始的系统时钟值
     SDL_Init( SDL_INIT_VIDEO ); // 初始化视频子系统
     //把屏幕设置到 320x240,32位颜色
     screen = SDL_SetVideoMode( 320, 240, 32, flag);
     // 如果可用的话,为屏幕表面请求硬件缓冲
     bBuffer = SDL_CreateRGBSurface( SDL_HWSURFACE, screen->w,screen->h,screen->format->BitsPerPixel,
        screen->format->Rmask,
        screen->format->Gmask,
        screen->format->Bmask,
        screen->format->Amask);
     // 这是种子图像,一旦开始它就会盘旋起来
     Image = SDL_LoadBMP( "tunnel_map.bmp" );
     Image = SDL_ConvertSurface(Image, screen->format, SDL_HWSURFACE);
     rBuffer.x = 0;
     rBuffer.y = 0;
     rBuffer.w = bBuffer->w;
     rBuffer.h = bBuffer->h;
     // 忽视大多数事件, 包括 鼠标动作, 并取消光标
     SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
     SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
     SDL_ShowCursor( SDL_DISABLE );
     Tunnel.Set( 320, 240 ); // 通道将填充整个的缓冲区
     Tunnel.Precalc( 16 ); //内部的圆圈直径
     while (SDL_PollEvent(NULL)==0) {
      float fTime = Tunnel_GetTime();
      //在修改前,必须锁定表面,特别当缓冲区处于图形硬件内存中时
      SDL_LockSurface(bBuffer);
      SDL_LockSurface(Image);
      Tunnel.Draw(bBuffer, Image, 180*sin(fTime), fTime*100);
      SDL_UnlockSurface(bBuffer); // 在更新以后你可以开锁
      SDL_UnlockSurface(Image);
      // 把缓冲区中的数据输出到屏幕绘图区域并强迫进行重画
      SDL_BlitSurface( bBuffer, NULL, screen, &rBuffer );
      SDL_UpdateRect( screen, 0, 0, 0, 0 );
     }
     Tunnel.Free();
    }

     


    图 2. 演示旋转和扭曲的2D通道


      4. 对另外一些游戏引擎的探索

      让我们看一下另外一些开源的游戏引擎。

      a) ALLEGRO(Allegro低级游戏开发例程)

      Allegro是一个开源的可移植的库,主要针对视频游戏和多媒体编程。Allegro由Shawn Hargreaves(近来称为Climax)创建,现在成长为一个能够跨越许多操作系统如Linux,Windows,MacOS,MS-DOS和许多另外的流行平台等的游戏系统。

      除了具有一个高级的2D图形库,它能容易地存取鼠标,键盘,游戏杆和高精度定时器中断。Allegro并没有包装或替换OpenGL,但是通过参观他们广阔的开发站点(http://www.allegro.cc/),你能学习怎样把OpenGL集成到Allegro游戏程序中。

      大约有700种不同的游戏工程,与Allegro一起发行,其中最为杰出的两类是街机游戏和谜题游戏。我特别地喜欢经典的街机游戏Zaxxon(见图3)的重制品。


    图3.酷毙的Zaxxon的重制品


      b) Irrlicht:点燃快速实时的3D引擎

      这个Irrlicht 引擎是一个跨平台,高性能实时引擎,用C++写成。你可以选择Direct3D,OpenGL或基于软件的着色技术。高端特点包括动态阴影,粒子系统,人物动画,进门和出门技术和碰撞检测(见图4)。Irrlicht支持Windows和Linux并提供到语言Java,Perl,Ruby等的绑定。业界先驱Nikolaus Gebhardt在他的朋友的少部分帮助下完成的这个引擎工。


    图4.在Irrlicht中的一个十分逼真的场景


      c) ClanLib:为多玩家游戏设计的引擎

      ClanLib提供了一个平台独立的接口来书写游戏-它们有一个共同的到低级库如DirectX和OpenGL的接口。借助于ClanLib,你只需编写少量代码即可在Windows,Linux和OSX系统上开发游戏程序。ClanLib包括一个广泛的声音库,2D碰撞检测,动画,GUI框架和网络库。图5显示了游戏XenoHammer中的一个场景。


    图5.XenoHammer屏幕快照
    用C++实现跨平台游戏开发之Allegro引擎

    要:本文重点讨论开源游戏开发库Allegro(Allegro低级游戏例程),同时涉及到一些深度技术并提供了一个简单的示例程序,帮你进一步确定它是否是适合你的开发平台。

      一、 一个适于多环境的引擎

      Allegro最开始被研发于八十年代后期古老的Atari ST平台上,随后被快速地移植到流行的DJGPP环境(一个在九十年代早期流行的32位的MS-DOS扩展程序)。此后,Allegro被移植到最为流行的Windows C++开发环境中,包括VS,MinGW,Cygwin和Borland C++。另外的支持它的平台包括Linux,BeOS,QNX,Mac OSX以及几乎任何其它带有X11库的Unix平台上。

      Allegro能着色到各种类型的位图和硬件加速的环境中,例如DirectX,XWindows,SVGAlib,FreeBE/AF,CGDirectDisplay,QuickDraw,等等。Allegro并不想提供它自己的3D环境或模拟器,但是OpenGL可以被容易地集成,这是通过使用AllegroGL库-它提供了一个类似于GLUT的接口(包括扩展管理)-实现的。

      二、 性能概要

      在进一步使用API开发前,让我们看一下Allegro提供的总体功能:

      ·具体到像素级的绘图函数,包括平坦阴影,gouraud阴影,纹理贴图,z缓冲的多边形和圆绘制,填充,贝塞尔样条曲线,图案填充,精灵,blitting(位图复制),位图计算缩放和旋转,半透明/光效果以及比例字体支持的文本输出

      ·FLI/FLC(在计算机生成的动画方面,这种格式比MPEG有更高的压缩性能)动画播放器

      ·播放后台MIDI音乐,可达64种同时的声音效果,并能录制样本波形和MIDI输入(声音平台支持,包括WaveOut,DirectSound,OSS,ESD,CoreAudio和QuickTime,等等)

      ·容易地存取鼠标,键盘,游戏杆等设备,还支持高分辨率定时器中断,包括一个DOS版本的垂直折回中断模拟器

      ·读/写LZSS压缩文件的例程

      ·数学函数,包括定点算术,表查找和3D矢量/矩阵/四元数操作

      ·GUI对话框管理器和文件选择器

      ·内建地支持16位和UTF-8格式的Unicode字符

      三、 使用引擎

      使用Allegro进行开发,就象在许多其它游戏场合下一样,游戏的总体结构都包括游戏开始前的初始化,游戏循环以及游戏完成后的清理。初始化意味着既包含Allegro启动代码也包含在开始的位置实现基本地装载或生成你的游戏级别。在创建你的初始化代码时,启动Allegro基本上没有什么代价付出(见图1).

      如果你需要很多屏幕相关的真实性能,建议你首先礼貌地用get_gfx_mode_list()函数查询一下最大可用方式:

    #include <allegro.h> //必须放于系统头文件的引用之后
    set_color_depth(32); // 缺省情况下使用8位颜色
    if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) {
     abort_on_error("Couldn’t set a 32 bit color resolution");
    }


      set_gfx_mode()的最后两个参数用于指定虚拟缓冲区的大小-我们的图形屏幕存储于其中。这可以使创建一个卷边游戏-其中地形是连续移动的-变得容易。例如,你可能要使虚拟缓冲区,比方说,宽出20%以留出足够的空间来平滑卷动新的精灵和地形。

     四、 一个完整的Allegro实例

      本教程将使用Kee-Yip Chan的SnookerClone演示程序,它是基于James Lohr的另一个具有相同名字的演示程序。图1显示了演示程序的基本屏幕快照。


    图1.Kee-Yip Chan的"SnookerClone"演示程序

      这个工程向你展示了许多不同的Allegro技术,包括动画,键盘输入和鼠标输入,碰撞和游戏物理知识(例如重力)。它利用了三个主要的元素:一个有8个扶手的旋转的车轮,一个用箭头键来控制的大红球,还有一些从顶部往下坠落的蓝球。车轮以接触方式推动红球,而当红球碰上蓝球时,它们之间相互影响。

      下列是完整的Allegro演示程序的代码:

    1 #include <allegro.h>
    2 vector<Point> g_points; //aka球上点的列表
    3 vector<Joint> g_joints; //物理对象列表,如车轮和缓冲器
    4 kVec g_accControl;
    6 int main(void)
    7 {
    8  allegro_init(); // 初始化allegro.
    9  install_keyboard(); // 启动键盘.
    10 install_mouse(); // 启动鼠标.
    11 install_timer(); //过程show_mouse()所需要;
    13 // 创建一个800x600的非全屏窗口.
    14 set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0);
    16 set_window_title("Kee-Yip Chan’s Snooker Clone");
    17 text_mode(-1); // 文本将被画在透明的背景之上
    19 BITMAP* buffer = create_bitmap(SCREEN_W, SCREEN_H);
      //创建一张位图用于双缓冲.
    21  // 初始化数据.
    22 create_joints(g_joints); //注册车轮、地板和缓冲器的硬编码的屏幕位置
    25 // 创建顶点以组成aka球: 玩家所用球和三个蓝球
    26 // 的位置, 速度, 大小和质量.
    27 g_points.push_back(Point(kVec(100, 300),kVec(0, 0),16, 10));
    // 玩家.
    28 g_points.push_back(Point(kVec(50, 40), kVec(0, 0),12, 5));
    // 中等的球.
    29 g_points.push_back(Point(kVec(80, 40), kVec(0, 0) 12, 5));
    //中等的球.
    30 g_points.push_back(Point(kVec(110, 40),kVec(0, 0),6, 1));
    // 小球.
    32 //主循环,在按ESC键后退出
    33 while(!key[KEY_ESC]) { //检查输入.
    34  if(key[KEY_UP])
    35   g_accControl.y = -0.07; //Jet pack.向上加速
    36  if(key[KEY_LEFT])
    37   g_accControl.x = -0.07; //左走.向左加速
    38  if(key[KEY_RIGHT])
    39   g_accControl.x = 0.07; //右走.向右加速
    41   static bool leftMousePressed = false,
        rightMousePressed = false;
    42  if(mouse_b & 1) { //鼠标左键按下
    43   if(!leftMousePressed){
    44    leftMousePressed = true; // 创建一个新球.
    45    g_points.push_back(Point(kVec(mouse_x, mouse_y),kVec(0, 0), 12, 5));
    46   }
    47  }
    48  if(!(mouse_b & 1))
    49  //保证不重复鼠标按键
    50  //否则,就会出现许多的新球
    51  leftMousePressed = false;
    52  if(mouse_b & 2) { //鼠标右键按下
    53   if(!rightMousePressed){
    54    rightMousePressed = true; // 创建一个新球
    55    g_points.push_back(Point(kVec(mouse_x, mouse_y),kVec(0, 0), 6, 1));
    56   }
    57  }
    58  if(!(mouse_b & 2))
    59   //保证不重复鼠标按键
    60   //否则,就会出现许多的新球.
    61   rightMousePressed = false;
    63   doPhysics();
    65   // 着色:如果我们能再次使用缓冲区,则清除它;
        //否则,旧图像将滞留显示
    66   //用白色进行清除.
    67   clear_to_color(buffer, makecol(255, 255, 255));
    68   for(unsigned i = 0; i < g_points.size(); i++) {
         //画点.
    69    //画一个实心球
    70    circlefill(buffer, //画向缓冲区
    71    g_points[i].position.x,g_points[i].position.y,// aka 球的中心点的位置
    72    g_points[i].size, // 半径.
    73    (i == 0) ? makecol(255, 0, 0) : makecol(0, 0, 255)); //红色如果是玩家;否则为蓝色
    75    // 画一个轮廓球.
    76    circle(buffer, //画向缓冲区
    77     g_points[i].position.x,g_points[i].position.y, // aka 球的中心点的位置.
    78     g_points[i].size, // 半径.
    79     makecol(0, 0, 0)); //红色如果是玩家;否则为蓝色.
    81   }
    83   // 画接合点
    84   for (unsigned i = 0; i < g_joints.size(); i++)
    85    line(buffer, //画向缓冲区
    86     g_joints[i].p1.x, g_joints[i].p1.y, // 点 1.
    87     g_joints[i].p2.x, g_joints[i].p2.y, // 点 2.
    88     makecol(0, 0, 0)); // 黑颜色.
    89    );
    91   // 打印指令.
    92   textout(buffer, font, "Left Mouse Button - new big ball Right Mouse Button - new small ball",
    93     125, 1, makecol(0, 0, 0));
    95   textout(buffer, font, "Arrow Keys - move red ball",
    96     300, 592, makecol(0, 0, 0));
    98   show_mouse(buffer); // 画鼠标光标.
    100   draw_sprite(screen, buffer, 0, 0);// 把缓冲区中的数据画向屏幕.
    101  } // while循环结束
    103  return 0;
    105 }END_OF_MAIN();

      33-101行包括了典型的游戏编程循环模式。游戏继续进行直到玩家按下ESC键退出为止。34-39行支持同时进行的键盘输入,因为你可以按下向上和向左箭头键来获取粗略的斜向运动。

      在41-61行,鼠标动作被捕获到全局变量mouse_b(用于按钮),mouse_x和mouse_y。如果你一直在使用一滚轮鼠标,你还可以使用变量mouse_z。我们对反向弹跳逻辑进行了一点硬编码以确保每次鼠标按下事件只有一个球下落。

      第63行调用doPhysics(),其目的是旋转车轮的线段,更新球位置,检测球碰撞和适当地改变它们的方向矢量。这个模块(350行的数学代码)有点深入了些,但它确实是一个一流的实现,值得你深入研究。

      余下的代码,65-101行,开始着色,在典型的示例程序中这属于常规实现部分。这里的着色用典型的双缓冲区技术,下一次屏幕变化被计算出来并进行脱屏绘制并在最的一毫秒进行缓冲交换(第100行)。这确保了视觉的连续性又减少了烦人的闪烁-对象看上去是随机地绘制的。在着色代码部分,对line()和circlefill()的调用是相当直接的:circlefill()以x,y,半径和填充颜色作为参数。

      textout_ex()函数的功能稍强于textout()(示于92-96行),允许你指定前景和背景颜色。Allegro提供例程以直接从GRX格式.fnt文件,8x8或8x16 BIOS格式.fnt文件,位图图象以及数据文件格式中装入字体。作为选择,你能导入一种大范围的Unicode字体,这可以通过写一个.txt脚本-它为每一范围的字符指定相应的不同的源文件-来实现。如果你想要支持TrueType,那么你需要AllegroTTF或相同功能的插件。
    最后,在第100行的draw_sprite()实现一个覆盖性复制新生成的位图到第14行创建的屏幕对象上。覆盖性复制意指只有非透明的颜色像素被复制。在本例中,我确信它已被退化成一个"blit"(块复制)转储。

      五、 Allegro的音频

      这个snooker演示程序只涉及到了一些最基本的图形和I/O函数,但是并没有用到Allegro的音频开发包。该包中的MIDI混频,音响效果和录音API,其效果达到或超过几乎每一个我所见过的专业的声音库。Allegro音频应用软件大量存在,包括WinCab-一个MP3和OGG Vorbis音乐唱片机,还有LouTronic Rhythm Box-一个鼓声生成合成器,它具有可全面融合到一起的snare鼓,低音鼓和hi hat的效果。下面我们简单地回顾Allegro音频API的一小部分。

      每一个使用音频的程序都应该调用reserve_voices()来指定数字和MIDI声音驱动程序分别使用的声音的数目。接下去,你能控制这些音频轨道的混合.

      你可以非常容易地象下面这样插入一个音轨:

    MIDI *midFile = load_midi("myfile.mid’);
    play_midi(midFile, TRUE);//连续循环

      对于更复杂的需要,你可以安装三个钩子函数之一,它们可以使你拦截MIDI玩家事件。如果被设置为非NULL,这些例程将在每次MIDI消息,元事件和系统独占的数据块中被分别调用。

      Allegro的数字音频系统被设计为从最基本的配置到可高度扩展的。你能容易安装读取器和写入器来处理新的或者不同的音频文件类型, 例如:

    register_sample_file_type("mp3",load_mp3,NULL);//安装MP3读取器

      当正播放数字音频时,你可以随时编辑它。下列代码改变将在播放一个样本参数时改变该样本(用于操作循环播放的声音):

    void adjust_sample(const SAMPLE *spl, int vol, int pan, int freq, int loop);

      你能改变音量,平移音频数据并清除循环标志,在下次执行到循环末尾时,这将停止该样本。如果在播放相同样本的好几个副本,这会调整它遇到的第一个副本。如果该样本没有播放,对它没有任何影响。

     

    用C++实现跨平台游戏开发之Irrlicht引擎

      Irrlicht引擎是一个用C++书写的高性能实时的3D引擎,可以应用于C++程序或者.NET语言中。通过使用Direct3D(Windows平台),OpenGL 1.2或它自己的软件着色程序,可以实现该引擎的完全跨平台。尽管是开源的,该Irrlicht库提供了可以在商业级的3D引擎上具有的艺术特性,例如动态的阴影,粒子系统,角色动画,室内和室外技术以及碰撞检测等(见图1)。


    图1.Irrlicht 3D引擎

      Irrlicht是一个德国神话故事中的一种动物的名字,它能够发光和飞翔,可以在大部分的沼泽地附近发现它。单词"Irrlicht"是两个德国单词("irr"意思是疯狂的;而"Licht"意思是光)的组合。在英语中,它被译为"鬼火"。

      Irrlicht十分幸运地为一个巨大的活跃的开发团队以大量的工程所支持。然而,因为Irrlicht主要由游戏名家Nikolaus Gebhardt所设计,所以该游戏在设计上十分连贯。你可以在网上到处发现有Irrlicht的增强程序,如可选用的地形生成器,入口生成器,输出器,world层生成器,相关教程和编辑器等。而且,它独立地创建了到Java,Perl,Ruby,BASIC,Python,LUA甚至更多种语言的绑定。而最为重要的是,它是完全自由的。

      二、 Irrlicht特性

      在深入分析API之前,请让我更具体地介绍一下Irrlicht提供给了3D游戏开发者哪些功能:

      ·一个可以运行于Linux以及Windows 98,ME,NT,2000和XP(MacOS在计划之中)等操作系统之上的引擎

      ·针对Direct3D 8生成器或Direct3D 9生成器(可选)提供了Anti-aliasing支持

      ·可换肤的GUI环境(包括一个很酷的具有金属质地的带阴影的皮肤),给一些老式的对话框加上漂亮的外观

      ·场景管理系统,它允许无缝的室内/室外过渡

      ·角色动画系统,带有骨骼和变形目标动画功能

      ·一个特殊的效果系统,包括粒子效果(雨,烟,火,雪,等等),告示板,灯光贴图,环境,地图,模板缓冲区阴影,雾,纹理动画,视差贴图,凹凸贴图,还有更多

      ·内建的材质支持,包括支持Pixel and Vertex Shaders版本1.1到3.0,ARB Fragment and Vertex程序以及HLSL(GLSL正在计划中)

      ·.NET语言绑定,这使得引擎可用于所有的.NET语言例如C#,Visual Basic.NET以及Delphi.NET

      ·一内建的平台独立的软件生成器,特性有:z-缓冲,Gouraud阴影,alpha混合和透明性,还有快速的2D绘图(见图2)

      ·你久已期待的2D绘图功能,例如alpha混合,基于关键色的位图复制,字体绘制,以及混合3D与2D图形

      ·能直接导入常见的建模文件格式:Maya,3DStudio Max,COLLADA,DeleD,Milkshape,Quake 3 levels,Quake2 models,DirectX,Pulsar,My3DTools,FSRad以及Cartography Shop

      ·能直接从BMP,PNG,Photoshop,JPEG,Targa和PCX导入纹理

      ·快速而易用的碰撞检测与响应

      ·为快速的3D运算和容器模板库进行了优化处理

      ·直接读取档案(可能是压缩的,如.zip文件)

      ·集成了快速的XML分析器

      ·为实现容易的本地化开发提供Unicode支持


    图2:基于Irrlicht的游戏Yet Another Space Shooter(YASS),这里显示的是一个静态游戏帧中的令人吃惊的着色效果
      三、 在Irrlicht中的特殊效果

      在本文的例子中,我将向你展示怎样使用模板缓冲区影子技术,还有粒子系统,告示板,动态光以及水表面场景结点等技术。参见图3。


    图3.结合动态的光和水进行的场景着色

      Irrlicht引擎自动地检查是否你的硬件支持模板缓冲;而如果不支持,则不启动阴影。在这个演示程序中,在方法createDevice()中的’shadows’标志被置位,以产生从一个动画角色投下的动态影子。如果这个实例程序在你的PC上运行太慢,可以把这个标志设置为false或者干脆再买一块更好些的图形加速卡。

      为能够使用Irrlicht.DLL文件,你需要链接到Irrlicht.lib库文件。你可以在工程设置对话框中设置这个选项;但是为了容易实现,你可以使用一个pragma预编译注释命令。方法createDevice()负责实例化根对象-它使用引擎完成一切事情。参数如下:

      ·deviceType:设备类型。当前你可选取Null设备以及软设备,如DirectX8,DirectX9或OpenGL。

      ·windowSize:要创建的窗口的大小或全屏幕模式。这个例子中使用512x384。

      ·bits:每像素位数(当在全屏幕情况时)。仅允许值为16或者32。

      ·fullscreen:指定是否你想使设备运行于全屏幕方式。

      ·stencilbuffer:指定是否你想使用模板缓冲区以用于绘制阴影。

      ·vsync:指定是否你想启动vsync(仅在全屏幕情况),可选。

      ·eventReceiver:一个接收事件的对象,可选。

      为适合于本实例环境,你将装载一个3D Studio Max文件(一幢房子)。该房子看起来并没有什么特别的,但是Irrlicht引擎能为你创建一个相当酷的纹理贴图。只需使用造型操纵器并为之创建一个planar纹理贴图即可:

    #include <irrlicht.h>
    #include <iostream>
    using namespace irr;
    #pragma comment(lib, "Irrlicht.lib")
    int main()
    {
     //让我们假定用户在本例中使用OpenGL
     //当然,也可以指定DirectX 8, 9, 等等.
     video::E_DRIVER_TYPE driverType = video::EDT_OPENGL;
     //创建设备,如果创建失败立即退出。
     IrrlichtDevice *device = createDevice(driverType,
     core::dimension2d(640, 480), 16, false, true);
     if (device == 0)
      return 1;
     video::IVideoDriver* driver = device->getVideoDriver();
     scene::ISceneManager* smgr = device->getSceneManager();

      我对从这个导入文件产生的发射光线颜色的效果并不满意。下列代码显示怎样实现这些步骤:

    scene::IAnimatedMesh* mesh = smgr->getMesh("room.3ds");
    smgr->getMeshManipulator()->makePlanarTextureMapping(
    mesh->getMesh(0), 0.008f);
    scene::ISceneNode* node = 0;
    node = smgr->addAnimatedMeshSceneNode(mesh);
    node->setMaterialTexture(0, driver->getTexture("wall.jpg"));
    node->getMaterial(0).EmissiveColor.set(0,0,0,0);

      四、 水动画

      你将添加的第一个特殊的效果是水动画。为此,WaterSurfaceSceneNode导入一个造型文件并使之象水表面一样地波动。如果你让这个场景结点使用一种相当好的材质如MT_REFLECTION_2_LAYER,那么它看起来相当酷:

    mesh = smgr->addHillPlaneMesh("myHill",
    core::dimension2d(20,20),
    core::dimension2d(40,40), 0, 0,
    core::dimension2d(0,0),
    core::dimension2d(10,10));
    node = smgr->addWaterSurfaceSceneNode(mesh->getMesh(0),3,300,30);
    node->setPosition(core::vector3df(0,7,0));
    node->setMaterialTexture(0,driver->getTexture("water.jpg"));
    node->setMaterialTexture(1,driver->getTexture("stones.jpg"));
    node->setMaterialType(video::EMT_REFLECTION_2_LAYER);

      作为输入造型,你可以创建一个陡峭的平面造型,但是你也可以为此使用任何其它的造型。你甚至能重用room.3ds输入文件(它看上去确实很奇怪)。该实例还用一个普通的石头纹理模型来绘制所有另外的表面。

      五、透明的告示板和灯光

      第二个特殊的效果是很基本的但是非常有用:一个透明的告示板,伴之有一个动态的灯光。为产生这种效果,你只需要产生一个灯光场景结点,并让它四处飞行;而且,为了让它看起来更酷一些,可以把一个告示板场景结点依附到它上面:

    //创建灯光
    node = smgr->addLightSceneNode(0, core::vector3df(0,0,0),
    video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 600.0f);
    scene::ISceneNodeAnimator* anim = 0;
    anim = smgr->createFlyCircleAnimator(core::vector3df(0,150,0),250.0f);
    node->addAnimator(anim);
    anim->drop();
    // 把告示板依附到灯光
    node = smgr->addBillboardSceneNode(node, core::dimension2d(50, 50));
    node->setMaterialFlag(video::EMF_LIGHTING, false);
    node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
    node->setMaterialTexture(0,driver->getTexture("particlewhite.bmp"));

     

     六、 粒子系统

      下面介绍的这个特别效果更有趣:一个粒子系统。在Irrlicht引擎中,粒子系统既是组件化的,也是可扩展的,但是仍然易于使用。你只需要简单地把粒子发射器放到一个粒子系统场景结点,这样以来粒子看上去没有产生源。这些发射器可以据需要进行灵活配置,并经常带有许多参数,如粒子方向,粒子数量,以及粒子颜色等。

      当然,发射器类型有区别(例如,一个点发射器能够使粒子从一个固定的点上发出粒子)。如果该引擎提供的粒子发射器还不能满足你的要求,你可以容易地创建你自己的发射器。这只需简单地从IParticleEmitter接口派生一个新类并使用setEmitter()方法把它依附到粒子系统上去即可。

      下一个实例将创建一个盒子粒子发射器。你可能已经猜出,它从一个跳跃的盒中随机生成粒子。由参数来定义盒子,粒子的方向,每秒产生粒子的最小和最大数目,颜色以及粒子的最小和最大生命周期。

      一个完全由发射器组成的粒子系统将是令人生厌的,因为缺乏真实感。因此,Irrlicht支持粒子影响器-它负责在粒子到处飞扬时予以修整。一旦添加到粒子系统上,它们就能模仿另外的更真实的效果,象重力或风。在本例中的粒子影响器只是简单地修改粒子的颜色来产生一种淡出效果。

      可能你已经猜出,粒子影响器是通过派生IParticleAffector接口实现的,然后通过使用addAffector()方法把它添加到粒子系统上去。在你为该粒子系统设置了一种好看的材质后,你就有了一个看上去相当酷的野外宿营火的效果。通过调整材质,纹理,粒子发射器,还有影响器参数,你能容易地创建烟雾,下雨,爆炸,下雪等效果:

    scene::IParticleSystemSceneNode* ps = 0;
    ps = smgr->addParticleSystemSceneNode(false);
    ps->setPosition(core::vector3df(-70,60,40));
    ps->setScale(core::vector3df(2,2,2));
    ps->setParticleSize(core::dimension2d(20.0f, 10.0f));
    scene::IParticleEmitter* em = ps->createBoxEmitter(
    core::aabbox3d(-7,0,-7,7,1,7),
    core::vector3df(0.0f,0.03f,0.0f),
    80,100,
    video::SColor(0,255,255,255), video::SColor(0,255,255,255),
    800,2000);
    ps->setEmitter(em);
    em->drop();
    scene::IParticleAffector* paf =ps->createFadeOutParticleAffector();
    ps->addAffector(paf);
    paf->drop();
    ps->setMaterialFlag(video::EMF_LIGHTING, false);
    ps->setMaterialTexture(0, driver->getTexture,"particle.bmp"));
    ps->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA);

      七、 影子投射

      最后但也不容忽视一个问题是,你需要为一个动画角色产生一个动态的影子。为此,你装载一个Quake2.md2模型文件并把它放到你的world上去。为了创建影子,你只需要调用方法addShadowVolumeSceneNode()。你可能通过调用ISceneManager::setShadowColor()来控制影子的颜色;注意,这仅是全局可调整的,并影响所有的影子。好,下面就是你的产生动态影子效果的代码:

    mesh = smgr->getMesh("../../media/faerie.md2");
    scene::IAnimatedMeshSceneNode* anode = 0;
    anode = smgr->addAnimatedMeshSceneNode(mesh);
    anode->setPosition(core::vector3df(-50,45,-60));
    anode->setMD2Animation(scene::EMAT_STAND);
    anode->setMaterialTexture(0, driver->getTexture("../../media/Faerie5.BMP"));
    anode->addShadowVolumeSceneNode();
    smgr->setShadowColor(video::SColor(220,0,0,0));

      八、 游戏循环

      最后,你能进入由device->run()方法控制的游戏循环。该循环将不断运行,直到通过获取一个关闭窗口事件(例如在Windows操作系统下的ALT-F4击键)来退出设备。你必须在一个beginScene()和endScene()命令对之间绘制每样东西。beginScene()用指定的一种颜色清屏,如果需要的话,可以同时清除深度缓冲区。然后你就可以让场景管理器和GUI环境来绘制它们的内容。随着调用endScene(),每一样东西都被绘制到屏幕上去。在本例中,你还可以动态地在标题栏上显示帧每秒(FPS)数,这对于严肃的游戏开发者是十分重要的事情:

    scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
    camera->setPosition(core::vector3df(-50,50,-150));
    int lastFPS = -1;
    while(device->run())
    {
     driver->beginScene(true, true, 0);
     smgr->drawAll();
     driver->endScene();
     int fps = driver->getFPS();
     if (lastFPS != fps)
     {
      core::stringw str = L"Campfire FX example [";
      str += driver->getName();
      str += "] FPS:";
      str += fps;
      device->setWindowCaption(str.c_str());
      lastFPS = fps;
     }
    }
    device->drop();

      结束循环后,你必须删除先前用createDevice()方法创建的Irrlicht设备。通过使用Irrlicht引擎,你应该删除所有你用以’create’开头的方法或函数创建的所有对象。你可以通过简单地调用device->drop()来删除该设备对象。

      九、你可能喜欢的Irrlicht插件

      正如在前面所介绍的,Irrlicht有一群勤奋的独立开发人员并为之产生了大量的插件,也用之开发了相当多的游戏。这些开发者中提出的许多的改进被再次集成到Irrlicht的随后的发行版本中。下面我列举其中的几个例子,我想这会吸引许多颇有前程的开发者感兴趣:

      ·OCTTools,是一套用于Irrlicht的工具,由Murphy McCauley所创建,用于操作OCT文件相关的:输出器,加载器,甚至更多。

      ·ICE(Irrlicht通用引擎)是一个开发框架,它提供了一个工程的轮廓实现,从而加快了新工程的开发。

      ·MIM,由Murphy McCauley所创建,是一个非常有用的基于XML的文件格式,可用于Irrlicht的加载器,转换器及其各种工具。

      ·My3D是一个开发工具包,它能够使你把来自于各种3D包(3DStudio MAX,Giles,等等)中的灯光贴图场景直接输出到Irrlicht中。

      ·Dusty引擎允许程序员创建"任务"-这些"任务"可以完成程序员想做的任何事情。之后,这些任务被添加到一棵普通的任务树上去,而每个任务可以有它们希望数目的孩子任务。任务"组"允许游戏设计者在一棵完整的树上执行普通的操作,例如暂停,继续或破坏等。

      ·Irrlicht RPG(Erring Light)是一个3D 绕行走游戏引擎,最初是针对RPG类游戏开发的。

      ·2D 图像和精灵类组成了一个很有用的库,它扩展了Irrlicht的2D能力。

      ·Zenprogramming站点,提供第一个针对Irrlicht的非正式的外部地形生成器,此处也提供很多相关的教程。

     

     

               

    再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

    展开全文
  • C++游戏系列:目录

    千次阅读 2016-04-14 07:26:08
    C++游戏系列1:角色类 C++游戏系列2:给角色装备武器 C++游戏系列3:用多文件组织角色类 C++游戏系列4:杀伤距离有限制 C++游戏系列5:不止有一件武器 C++游戏系列6:自己动起来 C++游戏系列7:小结一下 C++...

    C++游戏系列1:角色类
    C++游戏系列2:给角色装备武器
    C++游戏系列3:用多文件组织角色类
    C++游戏系列4:杀伤距离有限制
    C++游戏系列5:不止有一件武器
    C++游戏系列6:自己动起来
    C++游戏系列7:小结一下
    C++游戏系列8:……(待续)

    展开全文
  • C++游戏系列:文件夹

    2018-04-10 20:29:00
    C++游戏系列1:角色类 C++游戏系列2:给角色装备武器 C++游戏系列3:用多文件组织角色类 C++游戏系列4:杀伤距离有限制 C++游戏系列5:不止有一件武器 C++游戏系列6:自己动起来 C++游戏系列7:小结一下 C++...

    C++游戏系列1:角色类
    C++游戏系列2:给角色装备武器
    C++游戏系列3:用多文件组织角色类
    C++游戏系列4:杀伤距离有限制
    C++游戏系列5:不止有一件武器
    C++游戏系列6:自己动起来
    C++游戏系列7:小结一下
    C++游戏系列8:……(待续)

    展开全文
  • C++游戏编程入门教程

    2010-02-17 21:56:28
    C++游戏编程入门教程C++游戏编程入门教程C++游戏编程入门教程C++游戏编程入门教程
  • C++游戏编程PDF,教你如何高效地使用C++开发游戏和使用最流行的技术.
  • 如何编写 C++ 游戏引擎

    千次阅读 2018-07-30 14:17:20
    如何编写 C++ 游戏引擎 原创: 伯乐在线 CPP开发者 6月5日 (点击上方公众号,可快速关注) 编译:伯乐在线 - 李大萌 英文:Jeff Preshing http://blog.jobbole.com/113960/ 最近我在用 C++游戏引擎,再用这...

    如何编写 C++ 游戏引擎

    原创: 伯乐在线 CPP开发者 6月5日
    (点击上方公众号,可快速关注)

    编译:伯乐在线 - 李大萌 英文:Jeff Preshing
    http://blog.jobbole.com/113960/

    最近我在用 C++ 写游戏引擎,再用这个引擎做了一个移动端小游戏跳一跳(Hop Out)。下面是截自我的 iPhone6 的一个小片段。

    跳一跳是我想玩的游戏类型:3D卡通外观的复古街机游戏。目标是改变每个填充块的颜色,就像Q * Bert一样。

    Hop Out仍在开发中,但引擎的功能已经很完善了,所以我想在这里分享一些关于引擎开发的技巧。

    你为什么想要写一个游戏引擎?可能有很多原因:

    你是个修理工,喜欢从头开始建立系统,直到系统完成。

    关于游戏开发你想了解更多。我在游戏行业工作了14年,现在我仍然在不停的琢磨。我甚至不确定我是否可以从头开始编写一个引擎,因为它与大型工作室的编程工作的日常职责大不相同。我想知道答案。

    你喜欢控制。对完全按照你想要的方式组织代码,知道一切都在哪里,感到满意。

    你可以从AGI(1984),id Tech 1(1993),Build(1995)等经典游戏引擎以及Unity和Unreal等行业巨头那里获得灵感。

    你相信我们这个游戏产业应该试着去揭开引擎发展的序幕。我们并没有掌握制作游戏的艺术。还离得很远!我们对这个过程的研究越多,改进的机会就越大。

    2017年的游戏平台 – 手机,游戏机和电脑 – 非常强大,而且在很多方面都非常相似。游戏引擎的开发并不是像过去一样,在脆弱和怪异的硬件上挣扎。在我看来,更多是关于自己制造出来的复杂性的斗争。创造一个怪物很容易!这就是为什么本文建议围绕着保持事情可控的原因。我把它分成三部分:

    使用迭代方法
    在统一事物前要三思
    请注意,序列化是一个很大的课题
    这个建议适用于任何类型的游戏引擎。我不会告诉你如何编写着色器,八叉树是什么,或者如何添加物体。这些事儿,都是我假设你已经知道而且应该知道 – 这很大程度上取决于你想要制作的游戏类型。相反,我故意选择了一些似乎没有被广泛承认或提及的观点 – 这些是我在试图揭开一个主题神秘面纱时最感兴趣的一些观点。

    使用迭代方法

    我的第一条建议是使一些东西(任何东西),快速运行起来,然后迭代。

    如果可能的话,从一个示例应用程序开始,初始化设备并在屏幕上绘制一些东西。就我而言,我下载了SDL,打开了Xcode-iOS / Test / TestiPhoneOS.xcodeproj,然后在我的iPhone上运行了testgles2示例。

    瞧!我使用OpenGL ES 2.0,生成了一个可爱的旋转立方体。

    下一步,是下载一个其他人制作的马里奥3D 模型。我写了一个快速和粗糙的OBJ文件加载器 – 文件格式并不太复杂 – 并且修改了例程,来呈现Mario,而不是一个立方体。我还集成了SDL_Image来帮助加载纹理。

    然后我实现了一个双摇杆控制器用来操控马里奥(我本来想要创建的是一个双摇杆设计游戏,并不是马里奥。)

    接下来,我想探索骨骼动画,所以我打开了Blender,做了一个触手模型,并且用一个前后摆动的双骨架来操纵它。

    此时,我放弃了OBJ文件格式,编写了一个Python脚本来从Blender导出自定义的JSON文件。这些JSON文件描述了皮肤网格,骨架和动画数据。在C ++ JSON库的帮助下将这些文件加载到游戏中。

    一旦这个完成,我回到了Blender,并做了更详细的角色设计。 (这是我创造的第一个被操纵的3D人,我为他感到骄傲。)

    在接下来的几个月里,我采取了以下几个步骤:

    开始将向量和矩阵函数分解成我自己的3D数学库。
    用CMake项目替换.xcodeproj。
    在Windows和iOS上运行引擎,因为我喜欢在Visual Studio下工作。
    开始将代码移动到单独的“引擎”和“游戏”库中。随着时间的推移,我把它们分成更细粒度的库。
    写了一个单独的应用程序将我的JSON文件转换为游戏可以直接加载的二进制数据。
    最终从iOS版本中删除所有SDL库。 (Windows版本仍然使用SDL。)
    重点是:在开始编程之前,我没有对引擎架构进行设计。这是一个经过深思熟虑的选择。相反,我只是写了实现下一个特性的最简单的代码,然后我会查看代码,看看会出现什么自然生成的架构。我说的“引擎架构”是指组成游戏引擎的模块集,这些模块之间的依赖关系,以及用于与每个模块交互的 API。

    这里写图片描述

    这是一个迭代的方法,因为它关注于较小的可交付成果。它在编写游戏引擎时效果非常好,因为在每个步骤中,你都有一个正在运行的程序。如果在将代码合成到新模块中时出现问题,可以随时将做的更改与以前工作的代码进行比较。显然,我假设你在使用某种源代码管理工具。

    你可能会认为这种方法浪费了很多时间,因为总是在编写糟糕的代码,之后需要清理。但是大部分的清理操作都是将代码从一个.cpp文件移动到另一个,将函数声明提取到.h文件中,或者直接进行简单的修改。决定事情应该去哪是难点,但是这在已经有代码的时候会更容易决定。

    我认为用相反的方法:试图设计出一个能够提前完成所有需求的架构,会浪费更多的时间。我最喜欢的两篇关于系统过度设计风险的文章是 Tomasz Dąbrowski 的《泛化的恶性循环》和 Joel Spolsky 的《不要让架构太空人吓到你》。

    我并不是说在用代码处理问题之前,不应该在纸上进行设计。我也不是说你不应该事先决定你想要的功能。比如,我从一开始就知道我想让我的引擎在后台线程中加载所有资源。我只是没有尝试设计或实现该功能,直到我的引擎首先加载一些资源。

    迭代的方法给了我一个比我以前盯着一张白纸冥思苦想更优雅的架构。我的引擎的iOS版本现在是 100% 原始代码,包括自定义数学库,容器模板,反射/序列化系统,渲染框架,物理模块和音频混合器。我可以编写每一个模块,但是你可能没有必要自己写所有这些东西。你可能会发现适合自己引擎的许多优秀的开源代码库。 GLM、Bullet Physics 和 STB 头文件只是一些有趣的例子。

    在整合事物太多之前要三思

    作为程序员,我们尽量避免代码重复,喜欢代码遵循统一的风格。不过,我认为不要让这些本能凌驾于每一个决定之上。

    偶尔要抵制一下 DRY 原则

    举个例子,我的引擎包含了几个“智能指针”模板类,与 std :: shared_ptr 类似。每一个指针作为一个原始指针的包装,有助于防止内存泄漏。

    <> 是用于具有单个所有者的动态分配的对象。
    Reference<> 使用引用计数来允许一个对象拥有多个所有者。
    audio :: AppOwned <> 被音频混音器以外的代码调用,允许游戏系统拥有音频混音器使用的对象,例如当前播放的语音。
    audio :: AudioHandle <> 使用音频混音器内部的引用计数系统。
    这样可能看起来像其中一些类复制了其它的功能,违反 DRY(不要重复自己)的原则。事实上,在开发早期,我尽可能地重用现有的Reference <>类。但是,我发现音频对象的生命周期是由特殊规则来管理的:如果一个音频语音已经完成了一个样本的播放,并且游戏没有指向该语音的指针,那么该语音会被立即到删除排队等待。如果游戏持有指针,则不应删除这个语音对象。如果游戏持有一个指针,但指针的所有者在语音结束之前被销毁,这段语音应该被取消,而不是增加Reference <>的复杂性,我决定引入单独的模板类,这样更为实用。

    95% 的时间都在重用现有的代码。但是,如果你开始感到麻痹,或者发现自己增加了一件简单的事情的复杂性,那就问自己,代码库中的东西是否应该是两件事。

    可以使用不同的调用规则

    我不喜欢Java的一件事是,它强迫你在一个类中定义每个函数。在我看来,这是无稽之谈。这可能会使你的代码看起来更加一致,但是它也鼓励过度工程,并且不适合我前面描述的迭代方法。

    在我的 C++ 引擎中,一些函数属于类,有些则不属于类。例如,游戏中的每个敌人都是一个类,可能就像你预料的那样,大部分敌人的行为都是在这个类内部实现的。另一方面,在我的引擎中投射的球体是通过调用 sphereCast() 函数来执行的,这是物理命名空间中的一个函数。 sphereCast() 不属于任何类 – 它只是物理模块的一部分。我构建了一个系统来管理模块之间的依赖关系,这使得我的代码组织得很好。将这个函数包装在一个任意的类中不会以任何有意义的方式改善代码的组织。

    然后是动态调度,这是一种多态的形式。我们经常需要为一个对象调用一个函数,而不知道该对象的确切类型。 C ++程序员的第一本能是用虚函数定义抽象基类,然后在派生类中重写这些函数。这是有效的,但这只是一种技术。还有其他动态调度技术,不会引入额外的代码,或带来其他好处:

    C ++ 11引入了std :: function,这是存储回调函数的一个简便方法。也可以编写自己的std :: function版本,这样在调试中不会那么痛苦。
    许多回调函数可以用一对指针来实现:一个函数指针和一个类型不确定的参数。它只需要在回调函数中进行明确的转换。你在纯C语言库中经常看到。
    有时候,底层类型实际上是在编译时已知的,你可以绑定这个函数调用而不用额外的运行开销。 Turf是我在游戏引擎中使用的一个库,它非常依赖这种技术。例如看到turf:: Mutex,这只是针对特定平台类的定义。
    有时,最直接的方法是自己构建和维护一个原始函数指针表。我在我的音频混音器和序列化系统中使用了这种方法。Python解释器也大量使用这种技术,如下所述。
    你甚至可以将函数指针存储在散列表中,使用函数名称作为关键字。我使用这种技术来调度输入事件,如多点触控事件。这是记录游戏输入并用重放系统回放的策略的一部分。
    动态调度是一个很大的课题。我只是想表明,有很多方法来实现它。你编写的可扩展底层代码越多(这在游戏引擎中很常见),越会发现替代方法越多。如果你不习惯这种编程,C语言编写的Python解释器是一个很好的学习资源。它实现了一个强大的对象模型:每个PyObject都指向一个PyTypeObject,每个PyTypeObject都包含一个用于动态分配的函数指针表。如果你想直接跳转到其中的话,定义新类型的文档是一个很好的起点。

    注意序列化是一个大问题

    序列化是将运行时对象转换为字节序列的操作。换句话说,就是保存和加载数据。

    对于许多游戏引擎来说,游戏内容以各种可编辑的格式创建,例如.png,.json,.blend或专有格式,然后最终转换为特定于平台的可以快速加载到引擎的游戏格式。流水线中的最后一个应用通常被称为“炊具”。炊具可能被集成到另一个工具,甚至分布在几台机器上。通常,炊具和一些工具是与游戏引擎本身一起开发和维护的。

    这里写图片描述

    在建立这样的流水线时,每个阶段的文件格式的选择取决于你。你可以定义自己的一些文件格式,这些格式可能会随着添加引擎功能而变化。渐渐地可能会发现有必要保持某些程序与以前保存的文件兼容。不管什么格式,你最终都需要用C++来序列化它。

    用C ++实现序列化有无数种方法。一个相当明显的方式是将加载和保存函数添加到要序列化的C ++类。可以通过在文件头中存储版本号来实现向后兼容,然后将这个数字传递给每个加载函数。这是可行的,尽管这样代码可能维护起来比较繁琐。

    void load(InStream& in, u32 fileVersion) {
            // 加载预期的成员变量
            in >> m_position;
            in >> m_direction;
    
            // 仅当正在加载的文件版本是2或更大时才加载新的变量
            if (fileVersion >= 2) {
                in >> m_velocity;
            }
        }

    通过反射(特别是通过创建描述C ++类型布局的运行时数据),可以编写更灵活,不容易出错的序列化代码。想要快速了解反射如何进行序列化,请看一下开源项目Blender是如何实现的。

    这里写图片描述

    从源代码构建Blender时,有许多步骤。首先,编译并运行一个名为makesdna的自定义实用程序。该实用程序解析Blender源代码树中的一组C语言头文件,然后以SDNA的自定义格式输出所有C定义类型的汇总。这个SDNA数据作为反射数据,链接到Blender本身,并保存在Blender写入的每个.blend文件中。从这一刻开始,每当Blender加载一个.blend文件,就会将.blend文件的SDNA与链接到当前版本的SDNA进行比较,并使用通用序列化代码来处理差异。这个策略使Blender具有令人印象深刻的向前和向后兼容性。你仍然可以在最新版本的Blender中加载1.0版本的文件,也可以在旧版本中加载新的.blend文件。

    像Blender一样,许多游戏引擎及其相关工具都会生成并使用自己的反射数据。有很多方法可以做到这一点:可以像Blender一样解析自己的C / C ++源代码来提取类型信息。你可以创建一个单独的数据描述语言,并编写一个工具来从该语言生成C ++类型定义和反射数据。可以使用预处理器宏和C ++模板在运行时生成反射数据。一旦你有反射数据可用,有无数的方法来编写一个通用的序列化器。

    显然,我省略了很多细节。在这篇文章中,我只想表明有很多不同的方法来序列化数据,其中一些非常复杂。程序员不会像其他引擎系统那样讨论序列化,尽管大多数其他系统依赖于它。例如,在GDC 2017给出的96个程序设计讲座中,我数了一下,共有31次关于图形,11次关于在线,10次关于工具,4次关于AI,3关于物理模块,2关于音频的 – 但只有一个直接涉及到序列化。

    至少,试着想一想你的需求会有多复杂。如果你正在制作一个像Flappy Bird这样的小游戏,只有少数资源.,那么你可能不需要想太多的序列化。你可以直接从PNG加载纹理,这样很好处理。如果你需要一个向后兼容的紧凑的二进制格式,但不想自己开发,可以看看第三方库,比如Cereal或者Boost.Serialization。我不认为Google协议缓冲区是序列化游戏资产的理想选择,但是值得研究。

    编写一个游戏引擎,即使是一个小游戏引擎,也是一个很大的任务。关于这个我可以说的还有很多,但是对于这个长度的帖子来说,这真的是我认为最有用的建议:迭代地工作,抵制统一代码的冲动,并且知道序列化是一个大问题,你需要选择一个合适的策略。根据我的经验,如果忽视这些事情,每一件事情都可能成为一个绊脚石。

    我喜欢比较这些东西,真的很想听到其他开发人员的意见。如果你已经写了一个引擎,你的经验是否让你有什么相同的结论吗?如果你没有写,或者只是在构思,我也对你的想法也很感兴趣。你认为什么是好的学习资源?哪些部分对你来说看起来很神秘?你可以在下面评论或在Twitter上给我留言!

    看完本文有帮助?请分享给更多人
    关注「CPP开发者」,提升C/C++技能

    阅读原文

    展开全文
  • C++游戏(大富翁)

    热门讨论 2010-08-21 09:54:39
    大富翁 C++ 游戏编程 对于许多刚刚入门C++的同学来说很有帮助的,可以参考一下
  • 3D射击游戏很容易出现作弊行为,只有很好的了解其工作原理才能从根本上改善射击类游戏环境,扬汤止沸,...课程适合有一定C++基础并对游戏安全感兴趣的朋友,临渊羡鱼不如归而结网,让我们一起畅游在C++编程的欢乐世界!
  • C++游戏开发案例实战PDF下载

    千次阅读 2018-09-07 19:23:14
    C++游戏开发案例实战链接 https://pan.baidu.com/s/1vyuTvDxy5uAu66vF014VVg
  • 这是我多年来招聘培训C++游戏程序员的一点想法。一直想汇总一下。我在H3D Studio的核心技术人员和游戏制作管理人员全部是SMTH BBS游戏制作版成员。从99年开始截止BEGINER的历任版主都在H3D STUDIO里工作过。在这里我...
  • C++游戏开发》笔记十一 平滑动画 源代码 欢迎大家阅读配套博文 http://blog.csdn.net/u011371356/article/details/9430645
  • C++游戏系列7:小结一下

    千次阅读 2016-04-14 07:24:03
    C++游戏系列”是在和2015级同学学习C++过程中,想找一个应用背景而开始写的,同时,也作为同学们的实践项目,借这样一个连续的项目,即时体现学习到的知识点和技术,将正在学的内容和与当前不少同学有体会的应用...
  • C/C++游戏编程开发

    千次阅读 2017-03-25 12:12:26
    C/C++游戏编程开发,采用的是Win32/64下编程,利用的开发工具是VS2008,本套教程针对那些喜欢游戏开发的人是非常不错的教程,学习要求,有C/C++编程功底,可以不是很高,但是至少也要学习到函数这个地步,才能进行本...
  • 以前曾发过C++版的超级玛丽,经过作者近段时间的完善,本游戏已接近成熟,希望与喜欢C++游戏编程的朋友一起切磋学习。源码包中有已经导出生成的EXE可执行文件以及全部源代码还有一个DOC技术文档。 游戏界面实现...
  • C++游戏编程8步云

    万次阅读 多人点赞 2011-09-17 00:13:55
    C++游戏编程8步云  http://www.cplusplus.com/articles/1w6AC542/> 第一步 选择游戏库   要想编写一款游戏你必须选择一个游戏库,除非你要编写自己的游戏库。下面列出了一些游戏库的名称和网站,它们都提供了...
  • 《Visual C++游戏编程基础》源码

    热门讨论 2009-11-26 17:22:31
    包含了《Visual C++游戏编程基础》这本书的所有源码。如果有谁要这本书的话留下邮箱我发给他~
  • C++游戏服务器开发常用工具介绍在软件开发过程中需要使用的工具类型实属众多,从需求建模到软件测试,从代码编译到工程管理,这些工具都对项目有着不可替代的作用。庄子有云,“吾生也有涯,而知也无涯,以有涯随无...
  • C++游戏编程pdf

    2018-02-28 09:53:00
    下载地址:网盘下载内容简介······本书从游戏开发的角度出发,把C++应用到游戏软件领域。介绍一些C++的实战经验,用常规的C++技术解决游戏开发者经常遇到的问题。重点讲述已经在实际的项目中应用的技术,而...
  • C/C++作为元老级的编程语言,任时光更迭依旧屹立不倒,哪怕如今...一个益智类的VC++小游戏,源码分享给大家,用鼠标点击方格,可看到图像,具体是一款什么游戏还不太清楚,不过源代码是完全可以顺利编译的。 游...
  • C++游戏Loading界面

    2015-09-05 20:17:56
    一个简单的游戏Loading界面的设计,千里之行,始于足下~
  • 作为IT行业里的技术管理人员,我接触到了不少程序员,特别是C++游戏程序员。这里我谈谈自己对于目前国内C++游戏程序员发展前景的一些个人看法。 这是我多年来招聘培训C++游戏程序员的一点想法。一直想汇总一下。我...
  • c++游戏服务器框架

    2019-12-25 10:50:40
    1、skynet是一个开源的,轻量级的,为在线游戏服务器打造的框架 https://github.com/cloudwu/skynet 2、muduo是一个基于 Reactor 模式的 C++ 网络库 https://github.com/chenshuo/muduo/ 3、boost asio是一个...
  • 【游戏开发】C++游戏编程实例

    万次阅读 多人点赞 2018-09-11 09:44:18
    网络游戏开发分为:服务器编程、客户端编程、人工智能、数据库管理、游戏策划、美工设计、音乐特效等。 大型游戏往往需要团队合作开发,因此面向对象的编程思想在网络游戏中得到了广泛应用。 游戏开发基本流程:...
  • 上海C++游戏服务器群活动PPT下载

    千次阅读 2014-12-05 12:46:25
    下载页面:http://download.csdn.net/download/jq0123/8227519上海C++游戏服务器群 2014.11.9 沙龙讲义。 自我介绍 -------- 巨人网络 万王之王3 冒牌天神 ZTJ 金庆的专栏 跨区的概念 跨区的作用?人气 互动 单区...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 20,114
精华内容 8,045
关键字:

c++游戏

c++ 订阅