盾怪网教程:是一个免费提供流行杀毒软件教程、在线学习分享的学习平台!

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

时间:2024/12/18作者:未知来源:盾怪网教程人气:

[摘要](i<<8);      也就是说这个调色板的高8位和低8位是相同的,嘿嘿,想到什么了?(赶快用10秒钟猜猜,下面回答)  当然这样一来也就不能直接用DirectDraw里面的Blt之类...
(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 

关键词:对2D游戏引擎设计的一些思考




Copyright © 2012-2018 盾怪网教程(http://www.dunguai.com) .All Rights Reserved 网站地图 友情链接

免责声明:本站资源均来自互联网收集 如有侵犯到您利益的地方请及时联系管理删除,敬请见谅!

QQ:1006262270   邮箱:kfyvi376850063@126.com   手机版