文章分类 | 推荐文章 | 最新文章 | 热点文章 | 最新软件 | 精品软件 | 下载排行 | 推荐下载 | 免费看大片 | WPS | 杀毒软件
清风网络
首 页 软件下载 网络学院 数码学院
QQ 电脑入门 游戏 操作系统 图形处理 办公软件 媒体动画 精文荟萃 工具软件 网络编程 程序开发 网络技术 认证考试 网站建设 文章专栏
当前位置:清风网络学院程序开发其他语言对2D游戏引擎设计的一些思考
精品推荐
特别推荐
·控制面板知多少
·给你十条学习Ruby语言的理由
·分页管理机制
·Perl 语言的重要价值体现
·经验技巧:分享两条Delphi开发经验
·Java编程思想:面向对象的逻辑思维方法
·Samba系统简介
热点TOP10
·AIX 5L 学习大纲/简易教程(2)(未经许可,请勿COPY)
·DENX U-Boot及Linux使用手册
·EZ-USB 68013A开发指南
·图象处理中的边缘检测------canny算子
·Visual C++ ADO数据库编程入门
·利用 wordXP 实现自动排班
·UDT协议-基于UDP的可靠数据传输协议
·XPCOM--LINUX下的组件开发技术
·MyEclipse JSF 快速入门中文版(上)
·samba和openldap结合实战
·AIX 5L 学习大纲/简易教程(1)(未经许可,请勿COPY)
·Microsoft Windows XP Embedded 开发工具概述
·eMbedded Visual C++开发入门
·在VC6中创建wxWidgets项目[附图]
·数值计算程序大放送-线性代数方程组
·列表视图控件
·visual studio 2005 简体中文团队开发版 SQL server 2005简体中文版下载
·Visual Studio 2005:在 Visual C++ 中开发自定义的绘图控件
·汇编语言工具下载
·多文档界面(MDI)

对2D游戏引擎设计的一些思考

日期:2007年5月2日 作者: 查看:[大字体 中字体 小字体]



  前不久用模拟器玩了SFC上的一个经典SLG——圣龙战记后,突然对它出色的表现有了浓厚的兴趣,尤其是在那种硬件平台下,仅仅3M的游戏竟然能够有如此出色的表现!不仅是画面表现得极致,而且整个游戏的系统,情节相对当今的大多数游戏来说,实在是有过之而无不及!~实在是佩服万分~!

  确实,现在的硬件条件都比以前好多了,做一个游戏也越来越简单了(虽然我没有在DOS下写过程序,但是经过两年多的编程,对各个方面都有些了解,仍能体会到在DOS下写游戏的痛苦:)), 现在各种各样的游戏开发包也越来越多了,不说别的,就直接用DirectX SDK吧,做一个小的游戏比如飞机类也不会花几天时间(以前我花了3天做过一个^_^),开发简单了,自然有些东西就不那么讲究了,比如说现在的商业游戏的容量,无论是什么都先比光盘多少,你的3CD,我来5CD,除去里面"免费赠送"的一些"原声大蝶" 阿,"官方资料"阿之类的东西,一个游戏至少也有1个G,(大概是现在的硬盘在大家的眼中不怎么值钱了吧,可能商家是这么认为的,也可能是大众心理:东西越多越好嘛:)),真正有用的数据有多少?估计也只有商家才清楚~先不说某些游戏连压缩都没压缩过就裸用一大堆的24Bit BMP( 没错,就是标准的位图)来做游戏中的资源(仅仅做了一个未压缩的资源包,很轻松就能提取出全部资源:)),画面看起来效果好么?确实,不过那没有什么,反正就是美工的表现嘛!还对机器要求至少有PIII 500、128M以上的RAM~真是Faint!

  赫赫,也许大多数人不在乎上面提到的东西~可是作为一个游戏开发者,一个游戏程序设计者,就要在能力范围内对游戏程序做尽可能的优化(先不提商业制作的一些"无奈"的原因的阻碍),就比如说星际,大概是我所见到的PC上的商业游戏中做的最好的一个了:)

  好了,废话了一大堆,下面来谈谈点正式的。
  如今2D PC游戏上,最流行的就是16位色的显示方式(主要是从速度和内存消耗以及显示质量这些方面上来综合),16位色上基本上是565的显示方式(我到现在还从来没有见到一台555显示的机器或一块555的显卡),所以我只讨论16bit下565 模式。

  下面的方法是由于'调色板'而来的灵感~
  (先申明,这种方法绝对不适合主流技术,基于上面我所说的游戏----圣龙战记,可以做类似的游戏~不适合基于象素的游戏,对TILE类游戏比较实用)

  由于TILE类游戏用到的TILE颜色相对都比较固定,颜色种类比较少,所以我们可以选取一个固定的调色板,里面能容纳大部分的TILE颜色,这样所有TILE的数据都可以用这个调色板的索引来表示,当然为了方便,256种颜色最好不过,这样每个点只占8位(也许有人会说,这样不就干脆创建一个8位色的游戏不就行了?嘿嘿,稍安勿躁,马上解释),在内存消耗上就有了很大的优势~如果再压缩一下,嘿嘿........

  从速度上来说,由于游戏里面需要大量的特效,比如最常用的半透明效果,色彩饱和效果、阴影效果、灰度化等等效果,所以从这方面来考虑。

  由于只用到了256色,混合后的颜色也在256种颜色内,所以考虑用查表方式,
  这256种颜色从16Bit 565模式共65536种颜色的色彩空间中提取出来,这样就算是32级的Alpha混合也就只占用256*256*32*8bit=2M的内存。
  但是用16级或者12级我就觉得够了,这样就有 256*256*16*8Bit = 1M 或者 256*256*12*8Bit = 768K
  色彩饱和表就只需要 256*256*8Bit = 64K

  阴影表也就只要 256*256*8Bit = 64K
  灰度表只要 256*8Bit = 0.256K
  一共加起来也就1M左右,呵呵够少吧!
  如下:
    static unsigned char BDI_AlphaBlendTable[16][256][256]; //16级Alpha混和表
    static unsigned char BDI_AdditiveTable[256][256];       //Additive表
    static unsigned char BDI_SubTable[256][256];            //阴影表
    static unsigned char BDI_GrayTable[256];                //灰度表

  那么,哪256种颜色可以很好的描述大部分图片的颜色呢?
  尝试过几个不同的调色板后,最后发现下面这个调色板效果最好(并且还有附加的优势!稍后看到)
  如下,
    unsigned short wPal[256];
    for(int i=0;i<256;i++)
    {
     wPal[i]=i(i<<8);
    }

  也就是说这个调色板的高8位和低8位是相同的,嘿嘿,想到什么了?(赶快用10秒钟猜猜,下面回答)

  当然这样一来也就不能直接用DirectDraw里面的Blt之类的东西啦~,另外,由于我们的数据保留的是调色板的索引,所以,不能直接Blt到BackSurface上,自己分配一个缓冲区,大小和BackSurface一样大,不过用byte类型就够啦~

  自己写几个Blt吧:

  比如一个Alpha混合的操作:(代码取自我给出的Demo)
    void GBDI::DrawToScreenAdditiveSrcColorKey(unsigned char*pBufDest,int nDestWidth,unsigned char*pBufSour,int nLine,int nRow)
    {
        unsigned char*pDestAddr = pBufDest;
        unsigned char*pSourAddr = pBufSour;
        for(register int i=0;i<nRow;i++)
        {
            for(register int j=0;j<nLine;j++)
            {
                if(*pSourAddr != m_byColorKeyIndex)
                {
                    *pDestAddr = GBDI::BDI_AdditiveTable[*pSourAddr][*pDestAddr];
                    //这个地方极大的节省了大量的数学运算
                }
                pDestAddr++;
                pSourAddr++;
            }
            pBufDest += nDestWidth;
            pBufSour += m_nWidth;
            pDestAddr = pBufDest;
            pSourAddr = pBufSour;
        }
}

上面的操作是经过裁减过后的显示,裁减代码如下:

    RECT rtDest = {m_position.x,m_position.y,m_position.x+pScreen->GetWidth(),m_position.y+pScreen->GetHeight()};
    RECT rtSour = m_rtShowArea;
    if(rtDest.top<0)
    {
        rtSour.top -= rtDest.top;
        rtDest.top = 0;
    }
    if(rtDest.left<0)
    {
        rtSour.left -= rtDest.left;
        rtDest.left = 0;
    }
    if(rtDest.left+rtSour.right-rtSour.left>pScreen->GetWidth())
    {
        rtSour.right = rtSour.left+pScreen->GetWidth()-rtDest.left;
    }
    if(rtDest.top+rtSour.bottom-rtSour.top>pScreen->GetHeight())
    {
        rtSour.bottom = rtSour.top+pScreen->GetHeight()-rtDest.top;
    }

    unsigned char*pBufDest = pScreen->GetBuffer()+pScreen->GetWidth()*rtDest.top+rtDest.left;//目标地址
    unsigned char*pBufSour = m_pData+m_nWidth*rtSour.top+rtSour.left;//源地址
    int nLine = rtSour.right-rtSour.left;
    int nRow = rtSour.bottom-rtSour.top;

  各种参数的含义都比较明显,了解E文的并且写过代码的应该都能看懂,看不懂的如果有兴趣的话,自己去看完整源代码,好了,如何才能在屏幕上正确的显示呢? 这个问题就很简单了,当然最最直接的方法就是:

  for(缓冲区上的每一个点)
    BackSurface上的每一个点 = 缓冲区上的每一个点所代表的调色板的值

嘿嘿,别忘记了,上面说过用到的调色板是什么来的?
低8位和高8位相同!
如果了解mmx的话,就应该知道这一条指令:punpcklbw
哈哈!如何?知道优化的方法了吧?

下面是我的Demo中的代码:
    DDSURFACEDESC2 ddsd;
    ZeroMemory(&ddsd,sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    hr = m_pDSBack->Lock(NULL,&ddsd,DDLOCK_WAIT,NULL);
    while(DD_OK!=hr)
    {
        if(DDERR_SURFACELOST==hr)
            RestoreSurface();
        else
            return;
        hr=m_pDSBack->Lock(NULL,&ddsd,DDLOCK_WAIT,NULL);
    }
    unsigned char*pSourBuf = (unsigned char*)m_pBuffer;

    if(m_bDefaultPal)//如果是采用了默认的调色板(高8位==低8位)
    {
        //由于初学mmx,还不会作mmx指令的优化~代码见笑了~
        unsigned long dwResPitch = ddsd.lPitch-(m_nWidth<<1);
        unsigned char*pBuf = (unsigned char*)ddsd.lpSurface;
        unsigned long dwHeight = m_nHeight;
        unsigned long loopTime = m_nWidth>>5; //一次处理32个索引点
        {
            _asm
            {
                mov esi,pSourBuf;
                mov edi,pBuf;
                mov edx,dwHeight;
rowLoop:
                cmp edx,0;
je end;
                mov ecx,loopTime;
                mmxdraw:
                movq mm0,[esi]; //8个索引点
                movq mm2,[esi+8]; //后8个索引点
                movq mm4,[esi+16];
                movq mm6,[esi+24];
                movq mm1,mm0;
                movq mm3,mm2;
                movq mm5,mm4;
                movq mm7,mm6;
                punpcklbw mm0,mm0; //0-3个索引的值
                punpckhbw mm1,mm1; //4-7
                punpcklbw mm2,mm2; //8-11
                punpckhbw mm3,mm3; //12-15
                punpcklbw mm4,mm4;
                punpckhbw mm5,mm5;
                punpcklbw mm6,mm6;
                punpckhbw mm7,mm7;

                movq [edi],mm0;
                movq [edi+8],mm1;
                movq [edi+16],mm2;
                movq [edi+24],mm3;
                movq [edi+32],mm4;
                movq [edi+40],mm5;
                movq [edi+48],mm6;
                movq [edi+56],mm7;

                add esi,32;
                add edi,64;
                loop mmxdraw;
                dec edx;
                add edi,dwResPitch;
                jmp rowLoop;
end:
                emms;
            }
        }
    }
    else
    {
        unsigned long dwResPitch = (ddsd.lPitch>>1)-m_nWidth;
        unsigned short*pBuf = (unsigned short*)ddsd.lpSurface;
        for(register int i=0;i<m_nHeight;i++)
        {
            for(register int j=0;j<m_nWidth;j++)
            {
                *pBuf = m_pPal[*pSourBuf];
                pBuf++;
                pSourBuf++;
            }
            pBuf += dwResPitch;
        }
    }
    m_pDSBack->Unlock(NULL);

嘿嘿,最后最最重要的一点就是:效果如何呢?
这一点我无权评论,大家可以看看demo再说在我的机器( CII 950 + 256M SDR)上FPS最高能到200左右。

  附带一点,这个Demo中,我运用了类似模拟器上的图层管理的方法,其思想就是分n个layer,每个layer上的图元都有一个高度,高度范围为m,然后每一个layer上的图元全部由m个链表连接起来,画图顺序为:最先画的图层是0号图层,最先画的是0号链表,直到n个layer和m个高度(这样就可以随意关闭或者打开第几个layer,就像模拟器一样,并且很容易的实现流水线渲染具体情况看我的demo代码)。

  最后说明,现在的游戏都使用的是即时计算来进行渲染(包括我正在写的一个engine),并且使用3d加速来做特效上面这种方式虽然简单高效,但是只是在TILE方式下~~有兴趣研究Tile方式的游戏的朋友们不妨try一下~

  好了,就到这里,浪费大家的宝贵时间了,多有得罪~

Demo download
http://www.gameres.com/Articles/Program/Visual/2D/BlueDream.rar

有兴趣的朋友欢迎和我探讨:
game-diy@163.com
OICQ:30784290(难得糊涂)
http://www.gamepp.org/

2003/12/4 night 


[1] [2] 下一页 




上一篇:定时器时间数据转换子程序分析

下一篇:关于飞机射击类游戏的设计原理

对2D游戏引擎设计的一些思考 相关文章:
·孤胆枪手2 - 游戏秘籍
·罪恶都市 - 游戏秘籍
·帝国时代2:征服者 - 游戏秘籍
·《侠盗猎车手-罪恶都市》修改 - 游戏秘籍
·三国群侠传 流程攻略 - 游戏攻略
·3DS Max 7卧室效果图设计:建模篇
·《仙剑奇侠传2》完美补充攻略 - 游戏攻略
·暗黑破坏神2:毁灭之王 符文物品、符石功能、赫拉笛克方块等 - 游戏秘籍
·VB+Access设计图书管理系统
·如何建立一个网站?规划、设计、目的、原则、宣传
对2D游戏引擎设计的一些思考 相关软件:
·美工设计教程
·三国群英传5 宇峻科技 单机游戏
·Dreamweaver 网页设计
·C语言程序设计
·Photoshop CS中文版平面设计师标准案例教程
·Photoshop CS经典创意设计200例
·有关毛泽东的一些问题解答(不完整版)
·Photoshop 7.0 平面 广告 装帧设计100例
·Windows环境下32位汇编语言程序设计
·QQ游戏大厅V2007 Beta 1

特别声明:本站除部分特别声明禁止转载的专稿外的其他文章可以自由转载,但请务必注明出处和原始作者。文章版权归文章原始作者所有。对于被本站转载文章的个人和网站,我们表示深深的谢意。如果本站转载的文章有版权问题请联系编辑人员,我们尽快予以更正。
[打印本页] [关闭窗口] 转载请注明来源:http://www.vipcn.net
| 帮助(?) | 版权声明 | 友情连接 | 关于我们 | 信息发布
Copyright 2007 www.vipcn.net All Rights Reserved. 鄂ICP备05000083号Powered by:viphot