Go:使用 Ebiten 在 2D 視頻游戲中進行圖像渲染

插圖由創(chuàng)作原始 Go Gopher 作品的 Renee French 為“ Go 的旅程”創(chuàng)作。
本文基于 Ebiten 1.10。
Ebiten[1] 是由 Hajime Hosh[2] 用 Go 語言編寫的成熟的 2D 游戲庫。它是 Apple Store 上一些手機游戲如 Bear's Restaurant[3] 或桌面游戲如 OpenDiablo2[4] 的引擎,OpenDiablo2 是 Go 版本暗黑 2 的開源實現?,F在,讓我們深入了解電子游戲中的一些基本概念以及它們在 Ebiten 中的實現。
動畫制作
在電子游戲世界中,Ebiten 通過分離的靜態(tài)圖像來渲染動畫。這些圖像集合被組合成一個更大的圖像,通常稱為“紋理圖集[5]”,也稱為“精靈圖”。這是 網站[6] 上提供的示例:

然后,經過簡單的數學運算,這張圖被加載到內存中,然后被一部分一部分地渲染。在前面的示例中,每個部分的寬度為 32 個像素。渲染每個圖像非常簡單,只需將 X 坐標移動 32 個像素。這是第一步:


渲染動畫時,只需要當前圖像的值即可渲染精靈圖的正確部分。Ebiten 提供了所有的 API 來輕松地渲染它,下面是之前第一步中精靈圖的示例:
screen.DrawImage(
// 在坐標上繪制子畫面的子圖像
// x=0 to x=32 and y=32 to y=64
runnerImg.SubImage(image.Rect(0, 32, 32, 64)).(*ebiten.Image),
// 在該位置之前聲明的變量定義了屏幕上的位置
op,
)
Ebiten 的創(chuàng)建者 Hajime Hosh 還開發(fā)了“ file2byteslice[7]”,該工具可將任何圖像轉換為字符串,并允許將任何文件嵌入到 Go 中。它可以通過注釋 go:generate 與 Go 工具輕松集成,自動將圖像轉儲到 Go 文件中。下面是一個例子:
//go:generate file2byteslice
-package=img
-input=./images/sprite.png
-output=./images/sprite.go -var=Runner_png
現在可以從以下代碼的 img.Runner_png 變量中獲取精靈圖:

然后,必須先對圖像進行解碼,然后再由 Ebiten 加載并在游戲中進行渲染。讓我們轉到另一種渲染較大背景圖像的方法,該圖像由循環(huán)元素組成。
瓷磚背景
渲染背景使用相同的技術,將主要地圖集分為許多小圖像,稱為“瓷磚”。這是網站上提供的紋理圖集的示例:

該圖集可以被 16 像素的圖塊分割 ,這是使用 Tiled[8] 軟件創(chuàng)建的圖塊集合:

每個圖塊將分配一個數字,從 0 開始,逐次加 1。由于每行都有相同數量的圖塊,因此可以通過除法和取模來獲取圖塊的坐標。這是藍色花朵的示例:

藍色花朵的編號為 303,這意味著它們位于第 4 列(303 以每行的圖塊數為模,例如 303%25 = 3)和第 13 行(303 除以每行的圖塊數,例如,303/25 = 12)。
現在,我們可以使用索引數組來構建地圖:

從這張地圖上繪制圖像可以得到主要裝飾:

但是缺少背景。我們必須構建一個表示背景的類似數組。結果如下:

現在,這些圖層已經準備好了,我們只需要迭代兩個圖層就可以得到最終結果:

此示例中的代碼可在 Ebiten 網站[9] 上找到。
生成圖像后,Ebiten 必須管理屏幕更新并將指令發(fā)送到圖形卡片。
屏幕更新
Ebiten 提供了 iOS(使用 Metal)和 Android(使用 OpenGL ES)使用的驅動程序的抽象,這使開發(fā)更加容易。它還允許您定義一個函數,該函數可以更新屏幕并繪制所有更改。但是,出于性能原因,該庫會將源打包在一起,并將這些更改存儲在緩沖區(qū)中,然后再發(fā)送給驅動程序:

該緩沖區(qū)還能夠合并繪圖指令,以減少對 GPU 的調用次數。在上圖中,這三個指令現在可以合并為一個:

這項改進很重要,因為它可以減少發(fā)送指令時的開銷。這是合并指令的性能:

通過逐個發(fā)送指令,性能會大大降低:

Ebiten 還提供了對屏幕刷新的控制,這有助于調整性能。
TPS 管理
Ebiten 的默認 TPS 是 60。但是,這可以用 Ebiten 提供的 API ebiten.SetMaxTPS() 來輕松配置。它有助于減少機器上的壓力。這是具有 25 TPS 的簡單程序:

TPS(每秒 tick 數)與 FPS(每秒幀數)不同。Hajime Hosh[10] 很好地描述了這些差異:
幀代表圖形更新。這取決于用戶顯示屏上的刷新率。那么 FPS 可能是 60、70、120,依此類推。這個數字基本上是不可控制的。Ebiten 可以打開或關閉 vsync。如果關閉了 vsync,則 Ebiten 會嘗試盡可能多地更新圖形,那么 FPS 可以為 1000 左右。tick 表示邏輯更新。TPS 表示每秒調用更新功能的次數。默認情況下固定為 60。游戲開發(fā)人員可以通過 SetMaxTPS 配置 TPS。如果設置了 UncappedTPS,則 Ebiten 會嘗試盡可能多地調用更新函數。
當窗口在后臺運行時,Ebiten 為渲染帶來了另一種優(yōu)化。失去焦點時,游戲將進入休眠狀態(tài),直到重新獲得焦點。它實際上 sleep 了 1/60 秒,然后再次檢查焦點。這是保存的資源的示例:

盡管可以關閉此優(yōu)化,但是運行的系統可能會限制游戲的運行。例如,在 Firefox[11],Chrome[12] 或其他瀏覽器上的后臺標簽中運行時,在瀏覽器中運行的游戲會受到限制。
Ebiten 在 Github[13] 上接受贊助。如果您希望看到更多 Go 編寫的游戲,請隨時貢獻力量。
via: https://medium.com/a-journey-with-go/go-image-rendering-in-2d-video-games-with-ebiten-912cc2360c4f
作者:Vincent Blanchon[14]譯者:alandtsang[15]校對:polaris1119[16]
本文由 GCTT[17] 原創(chuàng)編譯,Go 中文網[18] 榮譽推出
參考資料
Ebiten: https://ebiten.org/
[2]Hajime Hosh: https://github.com/hajimehoshi
[3]Bear's Restaurant: https://daigostudio.com/bearsrestaurant/en/
[4]OpenDiablo2: https://github.com/OpenDiablo2
[5]紋理圖集: https://en.wikipedia.org/wiki/Texture_atlas
[6]網站: https://ebiten.org/examples/animation.html
[7]file2byteslice: https://github.com/hajimehoshi/file2byteslice
[8]Tiled: https://www.mapeditor.org/
[9]Ebiten 網站: https://ebiten.org/examples/tiles.html
[10]Hajime Hosh: https://github.com/hajimehoshi
[11]Firefox: https://hacks.mozilla.org/2018/01/firefox-58-the-quantum-era-continues/
[12]Chrome: https://developers.google.com/web/updates/2017/03/background_tabs
[13]Github: https://github.com/sponsors/hajimehoshi
[14]Vincent Blanchon: https://medium.com/@blanchon.vincent
[15]alandtsang: https://github.com/alandtsang
[16]polaris1119: https://github.com/polaris1119
[17]GCTT: https://github.com/studygolang/GCTT
[18]Go 中文網: https://studygolang.com/
推薦閱讀
