Canvas 的 drawImage 方法真的是同步的吗?

Posted

技术标签:

【中文标题】Canvas 的 drawImage 方法真的是同步的吗?【英文标题】:Is Canvas' drawImage method truly syncronous? 【发布时间】:2013-10-20 05:20:03 【问题描述】:

我正在使用画布为我的游戏实现菜单系统(出于某些性能原因,我不能使用 html/CSS 来制作菜单)。我使用 JSON 配置了菜单,并且 menuComponent 对象是使用它们各自的属性(x、y、宽度、高度、imagePath 等)创建的。我有一个菜单加载器,然后它遍历组件对象并调用组件对象的绘制方法(当然,所有图像都等待它们的 onload 事件首先触发)。

无论如何,我希望我的图像按照调用它们的绘制方法的顺序绘制,以便它们以正确的顺序重叠。大多数情况下,这种行为是正确的,但有时它们会以错误的顺序绘制。

我的问题是 - 我可以相信 Canvas 按照为这些图像调用 drawMethod 的顺序绘制图像吗?假设我有图像 A,例如 10MB,图像 B 是 10kb。如果我调用绘制图像 A 和 然后 绘制图像 B,那么图像 B 是否有可能首先加载,因为它是一个较小的图像?

我试图让我的代码变得聪明(在我的组件对象中嵌套组件并递归调用绘图方法)所以我的代码中可能存在一些竞争条件,我只是想确认上述行为是正确的。如果我添加逻辑来强制我的对象等到设置了 ready 标志,那么它似乎可以工作。但不幸的是,这会减慢我的菜单加载时间。

【问题讨论】:

drawImage 是,但加载图像不是(同步)。 简单的答案是:是的,Canvas 是同步的。 “If I add logic to force my objects to wait until a ready flag is set then it seems to work.”我相信你刚刚在那里回答了你自己的问题。预加载所有图像,然后然后开始绘图。 我害怕这个。目前,所有对象都在旋转,直到它们准备好自己绘制,这意味着用户可以看到正在为更复杂的菜单绘制单独的菜单组件块。我认为按照您的建议,为 all 加载的图像设置一个全局 ready 标志会更好。加载页面可能会有半秒到一秒的延迟,但至少所有内容都会立即绘制。为了理智,我可能只是将逻辑提取到一个对象中。谢谢大家! @user2872979 为避免用户看到部分加载,您可以隐藏所有页面并显示加载屏幕直到它显示 在菜单之间有一个加载屏幕并不是最好的用户体验:) 我认为半秒是可以忍受的。如果超过这个值,那么我会考虑优化我的代码。 【参考方案1】:

伙计,我遇到了同样的问题,并且已经坚持了大约三天。我想到了一件有趣的事情。请看一下这段代码 sn-p 并把你的想法告诉我。

final ResourceManager rm = new ResourceManager(1000, 1000);
rm.loadImgResource(LandCardResources.INSTANCE.getMeadow(), "meadow", 0, 0);
rm.loadImgResource(LandCardResources.INSTANCE.getHellHorseKnight(), "knight", 150, 150);

资源管理器是一个表示 BackBufferCanvas 的对象,它在其上下文中保存所有图像(如简单的图像精灵)。构造函数还负责将此 Backbuffer 添加到 RootPanel,因此我们可以确定一切都按预期工作。之后,我将我的主画布添加到根目录,尝试使用完美工作的 ResourceManager 实例从 backBufferCanvas 上绘制。

canvas.setWidth(500 + "px");
canvas.setHeight(500 + "px");
canvas.setCoordinateSpaceWidth(500);
canvas.setCoordinateSpaceHeight(500);
RootPanel.get().add(canvas);
rm.drawImageFromMetaDb(ctx, 0, 0, 100, 100, 0, 0, 100, 100);
rm.drawImageFromMetaDb(ctx, 150, 150, 100, 100, 50, 50, 100, 100);

而且它永远不会起作用。但是,例如,如果我使用负责 rm.drawImage 的处理程序将 Button 添加到 rootPanel .....单击此按钮时它将完美工作。无法真正理解为什么会发生这种情况,因为 backBufferCanvas 是在 mainCanvas 之前附加的,所以逻辑必须已经延迟。

【讨论】:

【参考方案2】:

正式回答这篇文章-

最后,我简化了我的解决方案,使用一个 menuLoader 对象,该对象为每个要绘制的图像(包含 x、y、imagePath、就绪标志)提供一组哈希值。我调用了一个创建组件方法,该方法在默认情况下将就绪标志设置为 false 来构建这些散列。我为每个图像设置了一个 onload 事件,以将其各自的就绪标志设置为 true。

创建组件完成执行后,我使用 setInterval 进行旋转,直到所有标志都设置为 true。一旦满足这个条件,我就会再次遍历我的哈希数组并为每个图像调用 draw 方法。

【讨论】:

以上是关于Canvas 的 drawImage 方法真的是同步的吗?的主要内容,如果未能解决你的问题,请参考以下文章

Canvas的drawImage方法使用

canvas中的drawImage

canvas.drawImage()方法详解

canvas画图中drawImage使用

Canvas drawImage:尝试裁剪和拉伸

画布:drawImage 方法失败且没有错误