對2D遊戲引擎設計的一些思考(轉)
對2D遊戲引擎設計的一些思考(轉)[@more@] 前不久用模擬器玩了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 { for(register int j=0;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 { unsign
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-951846/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 遊戲設計-Roguelike類遊戲的一些思考遊戲設計
- 對設計與設計師“價值”的一些思考
- 【設計模式總結】對常用設計模式的一些思考設計模式
- 我對SLG遊戲製作的一些思考遊戲
- 角色扮演遊戲引擎的設計原理與分析(轉)遊戲引擎
- 一些做產品設計的思考
- 針對小手指的設計思考
- 面向協議程式設計的一些思考協議程式設計
- 物件導向程式設計的一些思考物件程式設計
- 關於設計評審的一些思考
- 對ThreadLocal的一些思考thread
- 對於人生的一些思考
- 轉自OGRE的一些遊戲程式設計的連結遊戲程式設計
- 一名遊戲設計師的思考——遊戲性遊戲設計師
- 對優秀程式設計師的思考程式設計師
- 2D遊戲如何提升遊戲體驗? 2D關卡設計的六大正規化遊戲
- 遊戲設計左道,BattlePass新思考遊戲設計BAT
- 遊戲設計思考:隨機性遊戲設計隨機
- 學習憤怒的小鳥:對Android遊戲的一些思考Android遊戲
- 對程式設計師職業的一些建議--轉程式設計師
- 近期關於快取設計的一些思考快取
- 設計思維思考——遊戲中的幸福感設計遊戲
- Android 2D遊戲引擎AndEngine快速入門教程Android遊戲引擎
- 【遊戲設計隨筆06】關於《塞爾達傳說》的迷宮設計(dungeons design)的一些思考遊戲設計
- 遊戲開發者的思考:什麼是遊戲設計的核心?遊戲開發遊戲設計
- 如何用遊戲設計調動玩家的思考?遊戲設計
- 內容型遊戲的體驗設計思考遊戲
- [思考]對話式設計漫談
- 中文程式設計之思考 (轉)程式設計
- 體驗引擎:遊戲設計全景探秘遊戲設計
- 面對物件的思考 (轉)物件
- 《王者榮耀世界》開發團隊:我們對戰鬥設計的一些思考
- 鏟子騎士:2D遊戲,3D引擎打造遊戲3D
- 對React setState的一些思考與心得React
- 對格式化字串的一些思考字串
- 對提高HBase寫效能的一些思考
- 對於最近的一些理解和思考
- 對自己目前狀況的一些思考