我试图确定在Android SurfaceView上滚动由平铺位图组成的背景的“最佳”方式。我实际上已经成功地这样做了,但想确定是否有更高效的技术,或者我的技术可能不适用于所有Android手机。
基本上,我创建了一个新的,可变的Bitmap,它比SurfaceView的尺寸略大。具体来说,我的Bitmap可以容纳顶部,底部,左侧和右侧的额外线条。我在我的新位图周围创建了一个画布,并绘制了我的位图图块。然后,我可以通过将我的背景位图的“Surfaceview大小”子集绘制到SurfaceHolder的画布,向上滚动到任何方向的图块。
我的问题是:
是否有比将背景位图绘制到SurfaceHolder画布更好的位blit技术?
当我滚动到背景位图的边缘并希望将地图移动一个图块长度时,最佳操作方法是什么? 在我看来,我的选择是:
一个。单独重绘我背景中的所有图块,在一个方向上移动图块长度。 (这使我觉得效率低下,因为它需要很多小的Bitmap绘图)。
湾只需使背景位图如此之大,以至于它将包含整个滚动世界。 (这可能需要一个非常大的位图,但它只需要创建一次。)
℃。复制背景位图,将其绘制到自身上,但在我们滚动的方向上移动了一个图块长度,并使用几个单独的位图绘制绘制新显示的图块行或列。 (这里我假设一个大位图绘制比覆盖相同范围的多个小位图更有效。)
感谢您阅读所有这些内容,我将非常感谢任何建议。
答案 0 :(得分:4)
我最初在我的'Box Fox'平台游戏和RTS中使用了类似的技术,但发现如果滚动得足以重新绘制位图,则会造成相当明显的延迟。
我目前的方法这些游戏类似于你的选项C.我将我的平铺地图图层绘制到一个大位图(大约7x7)的网格上占据比屏幕大的区域。当用户滚动到此网格的边缘时,我将网格中的所有位图移位(将结束位图移动到前面),更改网格的偏移,然后重新绘制新边缘。
我不太确定软件渲染哪个更快(你的选项C或我当前的方法)。我认为如果您更改为OpenGL渲染,我的方法可能会更快,因为您不必在用户滚动时将尽可能多的纹理数据上传到图形卡。
我不建议使用选项A,因为正如您所建议的那样,数百个小位图绘制平铺地图会导致性能下降,并且对于较大的屏幕,它会变得非常糟糕。许多设备甚至可能无法使用选项B,因为很容易得到“位图大小超过VM预算”错误,因为许多手机上的堆空间限制设置得非常低。
此外,如果您不需要在地图/背景上使用透明度,请尝试使用RGB_565位图,因为在软件中绘制速度要快得多,并且占用的内存也会少一些。
顺便说一下,我的手机和10英寸平板电脑的上限为60fps,采用上述方法,用软件渲染,可以平滑地滚动地图。所以你绝对可以获得一些不错的速度。 android软件渲染器。我有一个为我的游戏构建的2D OpenGL包装器,但还没有需要切换到它。
答案 1 :(得分:1)
我认为一种有效的方法是使用 canvas.translate 。
在第一张图纸上,整个画布必须用瓷砖填充。新的Android手机可以轻松快速地完成这项工作。
当滚动背景时,我会使用canvas.translate(scrollX, scrollY),
然后我会逐个绘制个别瓷砖以填补空白,但我会使用
canvas.drawBitmap(tileImage[i], fromRect, toRect, null)
只能绘制需要显示的图块部分,方法是将fromRect和toRect设置为对应于scrollX和scrollY。
所有这一切都将通过数学来完成,并且不会为后台创建新的位图 - 节省一些内存。
编辑: 然而,使用带有surfaceView的canvas.translate存在一个问题,因为它是双缓冲的,而canvas.translate只会同时转换一个缓冲区但不会转换第二个缓冲区,因此在依赖缓冲区时必须考虑这种交替的缓冲区。在surfaceView上保留绘制的图像。
答案 2 :(得分:1)
我在地图应用程序中的解决方案依赖于2级缓存,首先使用位图和位置创建tile对象,这些对象存储在磁盘或Vector中(同步对我来说很重要,多线程HTTP通信遍布全部这个地方)。
当我需要绘制背景时,我会检测到可见区域,并获得我需要的所有图块的列表(这是经过大量优化的,因为它经常被调用)然后从内存中拉出图块或从磁盘加载。即使在较旧的手机上也能获得非常合理的性能,而且平滑的滚动也没有打嗝。
作为一个警告,我允许瓷砖不准备并与加载图像交换它们,我不知道这是否适合你,但如果你在APK中加载所有瓷砖你应该没问题。
答案 3 :(得分:0)
我正在使用您的原始方法绘制透视滚动背景。几天前我完全偶然想出了这个想法,同时用一种简单的技术来进行透视滚动星场模拟。该应用可在此处找到:Aurora2D.apk
只需倾斜您的设备或摇动它以使背景滚动(原谅2个弹跳精灵 - 他们在那里帮助我提供一种有效的方法来显示路径)。如果你找到一个更好的方法,请告诉我,因为我多年来编写了几种不同的方法,而且这个方法似乎更优越。如果您想比较代码,只需发邮件给我。