譯介丨構建一個通用的輕量級 2d 遊戲引擎(part 1)

  • 原文連結:點擊跳轉
  • 作者:Sébastien Bénard,《死亡細胞》的主創
  • 譯者:mnikn
  • 1. 簡介

    如果你對要做什麼事情沒什麼想法的話,是很難去構建一個 2d 的平台類遊戲引擎的。因此第一原則是從簡單入手。你知道 KISS 原則嗎?Keep It Short and Simple:這就是我們接下來要做的事情。

    我的大部分遊戲都是從一個簡單的畫布開始的,最終成長為一個 2d platformer 或者 top-down 風格的遊戲。即使是《死亡細胞》底層也是用同樣的引擎。順帶一提,platformer 和 top-down 的遊戲引擎區別只在於,platformer 相較於 top-down 多添加了重力的因素而已。

    在這篇文章我使用 Haxe 來實現代碼:如果你不知道 Haxe 是什麼的話,簡單來說 Haxe 是一種跨平台語言,能夠編譯生成多個平台的包,包括 Flash、C 和 iOS/Android。不過 Haxe 的基本語法很簡單並且通用,所以你可以很容易把這些代碼轉換成任意語言。

    我會先創造一個簡易輕量的 Entity 類作為基礎,隨後再慢慢拓展。傳統的做法,不過其中也會有一些 tricky。

    第一版本的 Entity 類代碼如下:

    2. 坐標系統

    首先我會嘗試去構建一個專注於易用性的坐標系統。

    通常我會基於網格(grid)去構建系統: 例如關卡就是一系列空單元格(player 可以行走的單元格) 帶上一些牆壁單元格。

    其中 cx,cy 是當前單元格的網格坐標,xr,yr 表示在單元格內的位置(按比例表示,0 到 1.0)。xx,yy 就是根據 cx,cy + xr,yr 算出來的位置結果值。

    有了這樣一個系統做事情就方便了很多。例如,檢查一個 Entity 右邊的碰撞情況變得很簡單:檢查下 cx+1,cy 坐標就好。同樣你可以使用 xr 來檢測當前單元格右方是否有 Entity。

    為了簡化這一過程,我們抽離出一個方法 hasCollision(cx,cy),當對於參數上有碰撞時返回 true,否則為 false。

    xx,yy 結果值只會在 update 循環函數結束時更新。

    注意: 有時候更新 sprite.x 和 sprite.y 會有細微的性能損耗:當你改變這些值時,大量的東西會根據自身內部邏輯去做更新。例如坐標一更新,對象又要重新渲染。所以有時候你不會想直接操作 sprite.x,出於性能考慮我會用結果變量 xx。

    同時這會讓跨平台開發變得更加容易,Entity 更多專注於邏輯而不是圖形。

    同時有時候你想要根據 xx,yy 來初始化 cx,cy 和 xr,yr。

    3. 在 X 坐標上移動

    每一幀中 xr 都會添加上 dx 的值。

    如果 xr 大於 1 或者小於 0(例如,Entity 已經超出了它當前單元格的邊界),那麼 cx 坐標會對應進行更新。

    為了讓移動更加順滑,你應該要在 dx 上添加摩擦係數(效果會比簡單加個 if 判斷要好)。

    在主循環代碼里面,當對應的事件觸發時(按鈕觸發或者其他情況),你只需要簡單改下 dx 的值,就能讓 entity 移動。

    4. X 坐標的碰撞檢測

    基於這個系統,檢測和管理碰撞變得非常簡單:

    5. X 坐標上的處理完成!

    以下是處理 X 坐標的完整代碼,這已經是極簡版了:)

    6. Y 坐標又要怎麼處理?

    大部分情況下都是 CV 大法。可能處理方式和 X 坐標有點不同,具體要看你的遊戲類型是什麼。例如 platformer 來說,當發生 Entity 腳下檢測到碰撞時,你可能希望 yr 的上限值是 0.5 而不是 0.7。

    譯者的話

    翻譯水平有限可能會有錯漏,有問題的話麻煩指出。這篇文章里面的思路,無論是打算自己從零開始,還是使用一個通用的遊戲引擎,都很有參考價值。而且作者的官網里面都是寶藏!他做了一些免費開源的工具,在我看來這些工具質量比市面上大多數收費的工具都要好,建議關注一波。

    來源:機核