【2D遊戲引擎】WIP反思

WIP(Working In Progress)是我初學遊戲引擎開發時候開發的一個2D遊戲引擎,當時計劃爲它實現相似Unity同樣的編輯器,具備和Unity類似的工做流,可是因爲水平不夠,走了不少彎路,閉門造車,作了不少錯誤的設計,致使不少地方反人類和難以維護,加之時間有限,因此已經中止了對它的繼續開發。因爲中止了開發,又不想把全部資料都所有搞丟,因此把在開發中學到的東西,和一些本身的思考都記錄一下。以便後能夠參考。ios

他最後能夠實現這些功能,不過實現起來遠比成熟的引擎蛋疼得多:c++

  • 腳本遊戲編程
  • 基本的2D遊戲(我曾經用這個東西作過flappy bird和一個簡單的RPG遊戲(因爲沒有寫編輯器,製做起來很是耗時特別是幀動畫和佈置場景的時候))
  • 一些2Ddemo(以前上課的幾個做業一直用這個作)
  • 簡單的OpenGL shader
  • 簡單的3D呈現

 

當時就選擇了腳本流,由於以前接觸過一段時間的Lua,因此腳本語言也直接選擇了Lua。腳本的嵌入採用了很簡單的思想,沒有去導出c++類,而是簡單實現了lua中的類,再把全部的c++對象都映射爲一個lua對象中的指針,這樣作的效率也許不高,可是後來也沒有遇到什麼大問題,只是有的時候會不方便,而比較棘手的就是對象銷燬問題,我在哪些對象須要自動銷燬,那些對象不須要上,想了好久,最終也沒有理出一個徹底完全的方案。另外,個人腳本系統僅僅是執行遊戲邏輯,我在主循環中使用一個函數每幀都調用Lua腳本的入口函數,從而驅動整個腳本系統。git

至於基於組件的遊戲對象,和數據驅動基本上全靠Lua和XML。場景保存到XML文件中的,每一個場景中的對象就是一個XML結點,而讀取場景則選擇了在lua中實現,一切的一切都全仰仗於這個函數:github

function System.genertate_component_by_name(component_name)
    s = "local _ = require \""..component_name.."\";return _:new()"
    return loadstring(s)
end

也就是說全靠lua的loadstring函數。個人每個組件都是一個Lua腳本,這些腳本繼承於一個基類,固然也都是Lua實現的,這些,我都是借鑑自Unity的腳本系統中我看得懂的部分,因此部分看起來和Unity的很相似。雖然簡單,可是應該說,我從此次實現嘗試中學到的東西仍是很多,至少解了了一些頗有用的概念。對Lua的瞭解也深刻了一步。算法

渲染是我此次嘗試中最失敗的部分,由於首先我並不熟悉OpenGL,並且在此以前我基本只使用Opengl的老渲染管線渲染圖像。因此最開始的時候,個人渲染系統中導出都是glbegin,glend,後來隨着個人深刻學習,我將那些地方所有改爲了gldrawelements或者gldrawarray來渲染,可是思想依然是固定渲染管線的思想。在個人渲染系統中,每次渲染一個四邊形,都會綁定一個紋理上去,而後把這個東西的頂點數據和紋理座標以及紋理id打包存到一個容器v中,直到一幀結束,將v中的全部東西所有取出來,一個一個的調用drawelements,然而這對渲染的效率並無什麼提高,屢次drawcall依然是屢次drawcall,固定管線依然是固定管線,對於所謂的多線程也徹底沒什麼用處。後來我準備在這個系統上開刀,試圖把全部的drawcall合併,然而這將會直接致使整個系統的重寫。後來逐漸深刻學習了Opengl,想使用可編程管線來渲染3D網絡,強制加入了Shader功能,然而這樣的行爲並很差,並且不少時候若是2D3D一塊兒渲染會產生問題,也就是說,這個渲染系統僅僅只支持2D渲染,若是想渲染3D圖形,對不起只能用OpenGL,連封裝都沒有……而當時使用在渲染2D對象的時候,幸虧用了mesh的概念,而不是直接拉四個點去……macos

場景管理其實那時候是沒有那個概念的,2D遊戲計算量沒到,固然不會去考慮場景管理優化之類的,Scene類惟一有的功能就是分了3個層,一個層用來裝object,一個用來裝UI,剩下的用來裝volumes。由於當時考慮到,object的更新和UI的更新並非同樣頻繁的,至於volumes,原本是想用來存放一些阻擋體積,碰撞體積,就和UE裏面的volume差很少的,可是因爲一些硬傷,這些東西知道最後也沒有可以加進去。編程

關於物理,我並不太懂物理,wip當前僅支持基本的剛體物理,物理部分主要是個人一個同窗幫助我完成的,我僅僅介入他寫好的功能。物理上,我遇到的問題就是更新。物理引擎爲我提供的東西主要就是一個body,我把這個body做爲個人object的一個組件。因而在更新的時候,我就要不斷地將當前的位置寫入body更新後在寫出到object,這樣作我一直以爲特別低效。不過還好這個東西並不會涉及到lua交互而是批量更新。網絡

動畫方面,我實現了幀動畫,以及嘗試嵌入了spine這個骨骼動畫插件。幀動畫就是很簡單的將一張紋理上的各個區域一直作變換,不停的播放。幀動畫我實現了一個叫作clip的文件,這個文件記錄一個動畫clip的每一幀的信息,包括uv和幀數等等。然而在實際使用的時候,沒有編輯器,手動修改大批這樣的數據是及其痛苦的。關於骨骼動畫,我使用了spine來嵌入,可是這個嵌入因爲渲染部分的設計問題,效果並非很好,因爲個人每個對象渲染出來都是一個矩形區域,因此我只能先將骨骼動畫結果渲染到一個fbo上,而後由這個fbo渲染到矩形上,而問題就在於這個矩形區域又和碰撞矩形掛鉤,而一個骨骼動畫對象在運動時每每須要一張最大的矩形來容納他的全部運動範圍,因此這個矩形應該儘可能可以框住整個運動對象,可是碰撞卻不是,骨骼動畫的碰撞須要拆分到各個部件來計算!因此不管我怎麼修改骨骼動畫的嵌入方式,也沒法改善碰撞和渲染的耦合,惟一的方案就是重寫。而這也是我放棄了wip的主要緣由之一。後來我心血來潮在其中本身實現了一個骨骼動畫系統,可是這個系統的設計是不完備的,也就是它只能播放骨骼動畫,而沒有考慮動畫數據來源。多線程

聲音部分其實我不是很懂,我使用了OpenAL來驅動聲音,而聲音文件解析則採用了libogg。聲音我基本上參考來參考去實現了流播放和總體加載播放的基本能力。剩下的研究就很少了。app

其實在整個實現中遇到的最大問題仍是文本渲染,首先我徹底不懂文字的造型什麼的,因此我使用了freetype,藉助freetype造型好文字後,我則將其加載到紋理進行渲染。這個系統應該是最不完善的一個系統把。

UI系統原本最開始是沒有的,可是我有段時間跟着老師作東西,作了個基於of的簡uii系統。想了一下直接就把能用的控件移植到引擎中來了。UI部分仍是基於回調的UI,思想比較老舊,可是基本能用。我在demo裏面就展現了幾個可用的UI控件。

其餘的一些比較基礎的庫,算法數據機構上我一開始還在考慮要不要使用stl仍是使用boost,可是後來發現一使用起stl就停不下來。數學庫,則是我以前參考UE的數學庫本身半抄半寫的,由於老是讀書少瞎想多,因此當年還真的特別擔憂徹底本身瞎寫數學庫會拉低效率,而後想到UE的源代碼,因而乎想到,UE用的方法應該不會低效吧,抄一個算了,也能學習學習,因而有段時間我就真的專心的去抄數學庫了,不過剛好那段時間在學習3D數學,仍是獲益很多。而後是圖片的解析我沒有本身去折騰,而是採用了freeimage,這個庫惟一的缺點就是大,其餘的是還很方便全面。最後關於內存管理本身實現了一個簡單的內存分配器,可是比較搞笑的是,這個管理器,我在我本身寫的這些代碼中並無怎麼使用,反而是我同窗寫的物理引擎用的多……可是後來出事了,在macos上這個內存管理器不能使用。

後來,我也曾今思考過將這個引擎移植到安卓或者ios上,有至關一段時間我都在作嘗試,和一個懂蘋果開發的同窗搞了幾天,解決了無數傻逼問題,最後在macos上跑了出來,可是卻終究沒有在osx上跑出來,安卓上,我也本身嘗試了一下,感受是還不如基於安卓重寫來的快……

總之一句話,讀書少而瞎想多

當初在作這個東西的時候,因爲太年輕想的是將這個東西作成一個2D交互應用開發套件,最好的效果是能作作成一 個和Unity2D同樣的東西。而當時看過的惟一一本書就是《Game Engine Architecture》,知道一個遊戲引擎大概有哪些東西,可是這些東西具體怎麼實現,則徹底是一篇空白。儘管在後來的開發中,參考了cocos2d 和UE4,可是對原代碼的解讀都只是淺嘗則止,沒有深刻的理解,每每是拿到一個概念,本身望文生義就亂實現。好比當時不知從什麼地方瞭解到了多線程渲染這 個概念,因而想固然的設計了wip的多線程渲染系統,可是就是這個所謂的多線程系統致使如今整個渲染系統都像一隻面目全非的怪獸。

 WIP的Github

OSC鏡像

相關文章
相關標籤/搜索