【问题标题】:HTML5 and Canvas scrolling: trick interesting or useless?HTML5 和 Canvas 滚动:有趣还是无用?
【发布时间】:2017-01-04 07:44:04
【问题描述】:

我已经阅读了有关滚动的所有内容:

Structuring an HTML5 Canvas/JS Game

等等:

(最新的一个令人印象深刻,但即使几乎所有内容都完成了,也没有任何关于滚动的内容。

这就是我的想法,我没有发现任何有价值的东西。一个想法刚刚出现在我的脑海中,我想知道我是否应该花很多时间思考并尝试,或者不(这就是我实际上在这里问的原因)。

我打算做一个带有滚动“à la”马里奥的游戏。

滚动的最大缺点是您必须重新绘制整个背景。 我已经避免了精灵/滚动的两个性能问题:创建两个画布彼此重叠:

  • 背景
  • 精灵

然后只是擦除精灵。

问题与背景有关:我正在将背景的完整副本复制到“可见”画布上。 (注意:闪烁没有问题,因为用 JavaScript 编写是一个阻塞操作,所有现代浏览器都处理垂直同步,所以不需要双缓冲)。

这是我所写内容的旧版本,但您会了解全局:

Test HTML5

现在我想知道滚动:如果我使用适当的 CSS(背景图像作为背景)做一个“背景 div”而不是画布,然后直接在图像上写入图块,然后更改 CSS模拟滚动?它应该更快吗?如果是这样,为什么?有什么好主意吗?

【问题讨论】:

    标签: html canvas scroll game-engine


    【解决方案1】:

    在带有半新式浏览器的半现代+计算机上,最快的做法可能是采用带有背景图像的超长 div,通过调整 scrollLeft 或 scrollTop 属性将溢出设置为隐藏和滚动。这比调整 CSS 属性要快得多,因为它不应该触发 CSS 引擎中的任何回流计算。基本上,任何时候您接触到可能对 CSS 产生影响的 DOM 属性时,都需要重新检查和重新渲染文档的整个(或至少大部分)结构。

    您可以在背景接近时加载它们,以避免加载一个巨大的大量图像。我不相信有任何 100% 万无一失的方法可以跨浏览器将图像从内存中拉出,但是当您滚动到足够远的地方时,在 DOM 或 CSS 中删除对它的引用可能不会受到伤害背景。这样浏览器的垃圾收集器至少可以选择清除内存。

    然而,在依赖 webviews 的泛移动解决方案(如 Cordova/Phonegap)中,这就是我提出这个问题的原因。

    我不知道,但我很确定混合 HTML 和画布对于性能而言是一个糟糕的想法。现在,我有一个不是超级复杂的 android 游戏,在 android web 视图中的 canvas 元素中的 50x50 100px 瓷砖上窒息,其中还混合了一些基本的 HTML,用于控件之类的东西,并将其他几个 canvas 元素与休息。我基本上有一艘鸟瞰船在周围巡航,并使用俗气的辐射圆图形进行扫描,该图形显示了地图战争迷雾风格的元素。在浏览器中效果很好。科尔多瓦应用程序版本中的彻底灾难。

    我怀疑我要实现我的泛移动游戏开发梦想的唯一方法是使用许多 openGL-wrapped-in-a-canvas-API 解决方案之一,并完全放弃我发现的 HTML考虑到我的大部分经验是在 Web UI 中,这对于 UI 实现来说非常方便。 Web 视图 HTML 的另一个一般提示是尽可能避免在内部元素内滚动(所以只要让 body 处理溢出)。在 Android 2 的 webview 中,除了 body 之外的任何内容都无法滚动溢出,而且它似乎仍然会导致 4.1 的视图在我正在开发的应用程序的早期/更简单版本上窒息。

    【讨论】:

    • 供您参考,我已经完全放弃了在 HTML5 中做一些很酷的事情,而实际上我在 Web 开发方面非常出色。但是在一个 HTML 中开发很酷的全设备是不可能的。相反,Unity 为我提供了我需要的一切,除了我必须学习 3D 数学……但实际上,其他一切都简直令人难以置信……而且它有效,它不像网络:总是“工作在-progress”(因此我开始厌倦 Web 和 JavaScript)。
    • 如果你支持移动,我完全同情。但我更应该责怪 Android 而不是 HTML5。
    【解决方案2】:

    我的最终结论:经过多次尝试,包括 Eirk Reppen 的建议,我直接将“原始”写入画布的隐藏部分并使用 CSS:所有网络浏览器都已经处理了图像闪烁和所有这些问题,并且他们已经优化了所有内容.

    所以每次我尝试“优化”时,结果都更糟

    似乎网络浏览器可以正确处理初学者制作的基本内容......也许是因为 99% 的 HTML 内容是由初学者制作的。

    【讨论】:

      【解决方案3】:

      这是一个通过更改 CSS 边距来滚动超大画布的演示,这个演示基于随时间滚动:https://jsfiddle.net/6othtm0c/

      还有这个鼠标拖动的版本:https://jsfiddle.net/ax7n8944/

      HTML:

      <div id="canvasdiv" style="width: 500px; height: 250px; overflow: hidden">
          <canvas id="canvas" width="10000px" height="250px"></canvas>
      </div>
      

      随时间滚动版本的 JS:

      canvas = document.getElementById("canvas");
      context = canvas.getContext('2d');
      
      for (var i = 0; i < 1000; i++) {
          context.beginPath();
          context.arc(Math.random() * 10000, Math.random() * 250, 20.0, 0, 2 * Math.PI, false);
          context.stroke();
      } 
      
      var t0 = window.performance.now();
      setInterval(function(){
          canvas.style.marginLeft = -(window.performance.now() - t0)/5 + "px";
      }, 5);
      

      【讨论】:

      • 在 El Capitan 上,您提供的两个示例都可以在 Safari 9.0.3 上正常运行,但它们都使 Firefox 44.0.2 崩溃。这些是目前(2016 年 4 月结束)这两种浏览器的最新版本。
      • 嗨@Calaf,我刚刚在同事的 El Capitan 上进行了测试,两个 Fiddle 都没有问题。他正在运行版本 46.0 - 我不确定为什么早期版本会崩溃并且无法轻松测试它,但我认为您的版本是 no longer supported
      【解决方案4】:

      最快的滚动是使用 CSS 滚动。因此,您绘制所有背景一次,不仅是可见部分,而且是全部,并隐藏不可见的部分,并使用 css 滚动它(边距或位置)。没有重绘,只有 CSS 更改。这项工作真的最快。但如果所有地图都非常庞大,其他自定义方式可能会更好。

      【讨论】:

      • "其他自定义方式可能会更好。" ;)
      • 因此,如果地图很小,您可以将所有内容预绘制到一些缓存/div/canvas 中并使用 css 移动它(也隐藏边)。如果我们的地图很大,你可以把它分成一些区域,对每个区域做同样的事情,但是你需要以某种方式加入这些区域。或者如果地图主要是 2d,您可以设置刷新地图缓存的关键点,例如向前 500m 和向后 500m。因为每一步生成地图可能真的很慢。
      • 地图很小,我正在做一个无限滚动的黑客,我发现使用 CSS 比使用原始副本时慢得多。奇怪。
      • 难道没有办法在里面流式传输地图数据吗?
      猜你喜欢
      • 2013-08-09
      • 1970-01-01
      • 2015-02-21
      • 2015-08-14
      • 1970-01-01
      • 2018-11-16
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多