我正在制作一个游戏,其中健康栏(动画)和其他一些信息在视觉上表现为一些图标,显示玩家拥有的炸弹数量等等。现在,这可以在画布上完成(通过制作另一个用于信息的画布位于主画布上,或者可以使用许多div和跨度来完成。这是我第一次制作基于浏览器的游戏,所以如果有经验的人看到这个,请告诉我你的建议。 strong>我想知道哪种方法会更快。
游戏也将在移动设备上运行。谢谢!
答案 0 :(得分:5)
没有直截了当的答案,我建议您使用不同的浏览器对您的用例进行FPS测试。如果你不想这么深入,我建议你只需在canvas中绘制元素,如果你需要隐藏它们,那么就从渲染循环中省略drawHUD()调用。
对于<canvas>
上的HTML HUD覆盖,应考虑以下因素
如果画布上有DOM元素,网页浏览器合成器是否可以正确地进行硬件加速<canvas>
由于处理DOM元素的继承复杂性,HTML / DOM操作总是比<canvas>
操作慢
<canvas>
像素空间停留在<canvas>
内,如果您尝试在画布本身外的<canvas>
上绘制元素,则可能难以获得像素完美的对齐
HTML为文本提供了比canvas drawString()更多的格式化选项 - 是必需的HTML格式
答案 1 :(得分:2)
使用画布。如果需要,可以使用两个画布,一个覆盖在另一个画布上,但使用画布。
完全触摸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通常包含文本,所以如果您使用任何文本,我确实强烈要求缓存它。 More on text performance here
答案 2 :(得分:1)
Browserquest使用HTML元素显示他们的HUD,这样做的好处是您不必担心重绘等等(鉴于整个浏览器引擎都经过优化以呈现,性能会非常好) DOM非常快。
他们(browserquest)也为不同的游戏元素使用了几个分层的canvas元素。我不知道确切的结构,但我想在哪个画布上显示一个元素取决于它需要重绘的频率。
答案 3 :(得分:1)
正如其他人所说,没有通用的最佳方法,因为它取决于您需要呈现的内容的具体细节,频率以及可能在图形组件之间发生的消息传递。
虽然DOM回流确实很昂贵,但这种一揽子警告并不总是适用。例如,使用position:fixed;元素避免触发页面的回流(如果有非固定子元素,则不一定在元素内)。重绘是(纠正我,如果这是错误的)昂贵,因为它是像素推动,因此本质上不比将相同数量的像素推到画布更慢。某些事情可能会更快。而且,每个都有某些操作比其他操作具有性能优势。
以下是需要考虑的一些要点:
越来越多的人可以在许多A级浏览器上使用WebGL加速的画布元素。这适用于2D,其优点是绘图操作被发送到GPU,这比2D上下文快得多。然而,这可能在某些目标平台上不可用(例如,在撰写本文时,它可以在iOS Safari中使用,但在iOS UIWebView中不能用于目标混合移动应用程序。)使用库来包装画布可以抽象这个如果可用,请使用WebGL。看看pixi.js.
相反,DOM具有CSS3动画/转换,这些动画/转换通常由GPU自动硬件加速(不依赖于WebGL)。根据动画类型的不同,您可以通过这种方式获得比使用画布更快的结果,并且通常使用更简单的代码。
最终,作为软件性能的一项规则,理解所使用的算法至关重要。也就是说,无论使用哪种方法,您如何安排动画帧?你有没有看过探查器,看看哪些东西占用的时间最多?这种做法优秀用于理解影响性能的因素。
我一直致力于开发具有多个动画的应用,并将每个组件都实现为DOM和画布。我最初感到惊讶的是,DOM版本的性能比画布(用KineticJS包装)更高,但我知道这是因为所有的动画元素都是位置:固定并使用CSS(通过jQuery UI引擎盖),从而获得GPU性能。然而,管理这些元素的代码感到笨拙(在我的例子中,ymmv)。使用画布方法允许更多像素完美渲染,但随后它失去了使用CSS进行样式化的能力(技术上也允许像素完美呈现,但实现可能或多或少复杂)。
通过将最复杂的动画限制到较低的帧速率,我实现了大幅加速,对于我的情况,它与60fps版本无法区分,但在较旧的iPad 2上运行平稳。需要使用requestAnimationFrame和钳位调用进行限制不比所需的帧率更频繁。这对于DOM上的CSS动画很难做到(尽管这些对于许多事情而言本质上更快)。接下来我要看的是将多个基于画布的组件同步到同一个requestAnimationFrame循环(可能是独立限制,或循环方法,其中每个组件获得帧速率的一小部分,这可能适用于2 -3元素。(顺便提一下,我有一些GUI控件,比如没有锁定到任何帧率的滑块,因为它们应该尽可能接近60fps并且小/简单到足以让我看不到它们的性能问题)。
我还通过剖析并看到我的代码中的一个类 nothing 与GUI有关的一个类经常调用一个特定的方法来计算属性,从而实现了巨大的速度提升。有问题的类是不可变的,所以我改变了方法来记住值,并看到CPU使用率下降了一半。谢谢Chrome DevTools和火焰图!永远简介。
大多数情况下,更新的像素数量往往是最大的瓶颈,但如果你能在GPU上完成,那么你已经有效地重新获得了代码的所有CPU。应该避免DOM重排,但这并不意味着避免使用DOM。一些元素使用DOM(例如文本!)进行渲染要简单得多,并且可以通过浏览器(或OS)的本机代码比画布更优化。最后,如果您可以使用任一方法(DOM或canvas)获得给定组件的可接受性能,请使用最简单的代码来管理该类型的组件。
最好的建议是尝试不同方法中的孤立部分,使用分析器运行,使用技术来覆盖或以其他方式推动限制以查看哪种方法可以最快地运行,并且在必须之前不进行优化。对此规则的警告是您要问的问题:我如何提前知道哪种技术方法可以实现最佳性能?如果您根据假设答案选择一个,那么您基本上是过早地进行优化,并将忍受由此引起的任意痛苦。相反,如果您正在通过快速原型设计或(甚至更好的)控制实验进行选择,这些实验专注于您的应用需求,那么您正在做R&amp; D:)