簡體   English   中英

我應該使用多個畫布(HTML 5)還是使用div來顯示HUD數據?

[英]Should I use multiple canvases (HTML 5) or use divs to display HUD data?

我正在制作一個游戲,其中健康欄(動畫)和一些其他信息在視覺上代表一些圖標顯示玩家擁有的炸彈數量等。現在,這可以在畫布上完成(通過制作另一個畫布的信息它位於主畫布上,或者可以使用許多div和跨度來完成。這是我第一次制作基於瀏覽器的游戲,所以如果有經驗的人看到這個,請告訴我你的推薦。 我想知道哪種方法會更快。

該游戲也將在移動設備上運行。 謝謝!

沒有直截了當的答案,我建議您使用不同的瀏覽器進行FPS測試,以了解它的用例。 如果你不想這么深入,我建議你只需在canvas中繪制元素,如果你需要隱藏它們,那么從渲染循環中省略drawHUD()調用。

對於<canvas>上的HTML HUD覆蓋,應考慮以下因素

  • 如果<canvas>上有DOM元素,Web瀏覽器合成器是否可以正確執行硬件加速<canvas>

  • 由於處理DOM元素的繼承復雜性,HTML / DOM操作總是比<canvas>操作慢

  • <canvas>像素空間停留在<canvas>內部,如果您嘗試在畫布本身外的<canvas>上繪制元素,則可能難以獲得像素完美的對齊

  • HTML為canvas提供了比canvas drawString()更多的格式化選項 - 是必需的HTML格式

使用畫布。 如果需要,可以使用兩個畫布,一個覆蓋另一個,但使用畫布。

完全觸摸DOM很慢。 使文檔重做其布局,因為移動的DOM元素的大小非常慢。 處理更多事件的取消(或不處理),因為在畫布上有物理上的DOM項目可能是一種痛苦,為什么還要費心去處理?

如果您的HUD不經常更新,那么最快的事情就是在它更改時將其繪制到內存中的畫布,然后在更新幀時始終將該畫布繪制到主畫布。 這樣你的drawHud方法看起來就像這樣:

function drawHUD() {
  // This is what gets called every frame
  // one call to drawImage = simple and fast
  ctx.drawImage(inMemoryCanvas, 0, 0);
}

當然更新HUD信息就像:

function updateHUD() {
  // This is only called if information in the HUD changes
  inMemCtx.clearRect(0, 0, width, height);
  inMemCtx.fillRect(blah);
  inMemCtx.drawImage(SomeHudImage, x, y);
  var textToDraw = "Actually text is really slow and if there's" + 
                   "often repeated lines of text in your game you should be" +
                   "caching them to images instead";
  inMemCtx.fillText(textToDraw, x, y);
}

由於HUD通常包含文本,所以如果您正在使用任何文本,我確實強烈要求緩存它。 更多關於文本性能的信息

Browserquest使用HTML元素顯示他們的HUD,這樣做的好處是您不必擔心重繪等(並且性能會非常好,因為整個瀏覽器引擎都經過優化,可以非常快速地渲染DOM。

他們(browserquest)也為不同的游戲元素使用了幾個分層的畫布元素。 我不知道確切的結構,但我想在哪個畫布上顯示一個元素取決於它需要重繪的頻率。

正如其他人所說,沒有通用的最佳方法,因為它取決於您需要呈現的內容的具體細節,頻率以及可能在圖形組件之間發生的消息傳遞。

盡管DOM回流確實很昂貴,但這種全面警告並不總是適用。 例如,使用position:fixed; 元素避免觸發頁面的回流(如果有非固定子元素,則不一定在元素內)。 重繪是(糾正我,如果這是錯誤的)昂貴,因為它是像素推動,因此本質上不比將相同數量的像素推到畫布更慢。 某些事情可能會更快。 更重要的是,每個都有某些操作比其他操作具有性能優勢。

以下是需要考慮的一些要點:

在許多A級瀏覽器上使用WebGL加速的畫布元素越來越可能。 這適用於2D,其優點是繪圖操作被發送到GPU,這比2D上下文快得多。 然而,這可能在某些目標平台上不可用(例如,在撰寫本文時,它可以在iOS Safari中使用,但在iOS UIWebView中不能用於目標混合移動應用程序。)使用庫來包裝畫布可以抽象這個如果可用,請使用WebGL。 看看pixi.js.

相反,DOM具有CSS3動畫/轉換,這些動畫/轉換通常由GPU自動硬件加速(不依賴於WebGL)。 根據動畫類型的不同,您可以通過這種方式獲得比使用畫布更快的結果,並且通常使用更簡單的代碼。

最終,作為軟件性能的一項規則,理解所使用的算法至關重要。 也就是說,無論使用哪種方法,您如何安排動畫幀? 你有沒有看過探查器,看看哪些東西占用的時間最多? 這種做法非常適合理解影響性能的因素。

我一直在研究一個有多個動畫的應用程序,並將每個組件都實現為DOM和canvas。 我最初感到驚訝的是,DOM版本的性能比畫布(用KineticJS包裝)更高,但我知道這是因為所有的動畫元素都是位置:固定並使用CSS(通過jQuery UI引擎蓋),從而獲得GPU性能。 然而,管理這些元素的代碼感到笨拙(在我的例子中,ymmv)。 使用畫布方法允許更多像素完美渲染,但隨后它失去了使用CSS進行樣式化的能力(技術上也允許像素完美呈現,但實現可能或多或少復雜)。

我通過將最復雜的動畫限制到較低的幀速率來實現了大幅加速,對於我的情況,它與60fps版本無法區分,但在較舊的iPad 2上運行平穩。必須使用requestAnimationFrame和鉗位調用進行限制比期望的幀率。 這對於DOM上的CSS動畫很難做到(盡管這些對於許多事情而言本質上更快)。 接下來我要看的是將多個基於畫布的組件同步到同一個requestAnimationFrame循環(可能是獨立限制,或循環方法,其中每個組件獲得幀速率的一小部分,這可能適用於2-3 (順便提一下,我有一些GUI控件,比如沒有鎖定到任何幀速率的滑塊,因為它們應該盡可能接近60fps並且足夠小/簡單以至於我沒有看到它們的性能問題)。

通過剖析並看到我的代碼中與GUI 無關的一個類有一個特定的方法來調用屬性,我也實現了巨大的速度提升。 有問題的類是不可變的,所以我改變了方法來記住值,並看到CPU使用率下降了一半。 謝謝Chrome DevTools和火焰圖! 總是描述。

大多數情況下,更新的像素數量往往是最大的瓶頸,但如果你能在GPU上完成,你已經有效地重新獲得了代碼的所有CPU。 應該避免DOM重排,但這並不意味着避免使用DOM。 使用DOM(例如文本!)渲染的一些元素要簡單得多,並且可以通過瀏覽器(或OS)的本機代碼比canvas更優化。 最后,如果您可以使用任一方法(DOM或canvas)獲得給定組件的可接受性能,請使用最簡單的代碼來管理該類型的組件。

最好的建議是嘗試不同方法中的孤立部分,使用分析器運行,使用技術來覆蓋或以其他方式推動限制以查看哪種方法可以最快地運行,並且在必要之前不進行優化。 對此規則的警告是您要問的問題:我如何提前知道哪種技術方法可以實現最佳性能? 如果你根據假設的答案選擇一個,你基本上是過早優化,並將忍受這導致的任意痛苦。 如果您正在通過快速原型設計或(甚至更好的)控制實驗來選擇,這些實驗專注於您的應用需求,那么您正在進行研發:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM