Android:低 FPS 在表面视图中绘制许多位图
Android: Low FPS drawing many bitmaps in a surfaceview
我正在尝试制作弹幕游戏,但 运行 遇到了一些麻烦。大约 500 发子弹后,我无法获得超过 17 fps。所有更新逻辑代码大约需要 1-4 毫秒,而渲染代码大约需要 40 毫秒
现在我的代码是
private void drawEntities(Canvas canvas) {
for (HashMap<UUID, Spatial> h: spatialList) {
for (Spatial spatial: h.values()) {
spatial.render(canvas);
if(spatial.life > 0)
spatial.life--;
else if (spatial.life == 0)
engine.deleteEntity(spatial.owner);
}
}
}
spatialList 是一个数组列表,其中每个索引都是一个 zLevel
显示实际子弹的空间是
public void render(Canvas canvas) {
float angle = (float) (vel.getAngle() * (180 / Math.PI));
matrix.reset();
matrix.setTranslate(pos.x - bullet.getWidth() / 2, pos.y - bullet.getHeight() / 2);
matrix.postRotate(angle + 90, pos.x, pos.y);
canvas.drawBitmap(bullet, matrix, paint);
canvas.drawCircle(pos.x, pos.y, col.getRadius(), paint);
}
我可以提供更多代码,但这些似乎是主要问题。我已经尝试了所有我能想到的方法,但在网上找不到其他方法。我唯一能想到的解决方法是从 surfaceview 切换到 GLSurfaceview,但我真的认为有更好的方法,我只是使用了错误的代码。
编辑:我注意到我的计时器已关闭并移除了画圈,在 运行 再次启用它后我得到 40ms~ 500 左右,这对于合理的性能来说仍然有点太低了。
TLDR; 500 个实体 = 17 fps。
尝试从 render() 方法中删除旋转 and/or drawCircle 部件时的性能。它们都可能非常耗时,因为它们可能包含 sin() / cos() 计算。
如果这有帮助,您将不得不想出如何用更快的东西替换它们,如果没有,那么...
您可能会受到像素填充率的限制。您的测试设备上的显示屏有多大(以像素为单位)?
一件简单的事情就是使用setFixedSize()
to reduce the size of the SurfaceView's Surface. That will reduce the number of pixels you're touching. Example here, video here, blog post here。
这样做通常是个好主意,因为较新的设备似乎正朝着荒谬的像素数方向发展。一款在软件中执行所有渲染的全屏游戏将在 2560x1440 显示器上挣扎,并且在 4K 下表现不佳。 "Limiting" 将游戏设置为 1080p 并让显示缩放器完成繁重的工作应该会有所帮助。根据游戏的性质,您可以将分辨率设置得更低而不会明显降低质量。
另一件事是消除 drawBitmap()
调用,检查你的计时,然后恢复它并消除 drawCircle()
调用,看看一个或另一个是否正在咀嚼大部分时间。
您可能会发现切换到 OpenGL ES 并不是那么糟糕。 Grafika 中的 "hardware scaler exerciser" activity(来自上面链接的视频)显示了一些简单的位图渲染。将 drawCircle()
替换为缩放位图,您可能已经完成了大部分工作。 (请注意,它使用 SurfaceView,而不是 GLSurfaceView,用于 GLES activity。)
我遇到了同样的问题。如果在位图帧缓冲区上进行所有绘制,然后将帧缓冲区绘制到canvas,问题将在很大程度上得到解决。如果您直接在 canvas 上绘图,那么会有一些开销。我环顾四周,找到了这个教程
“http://www.kilobolt.com/day-6-the-android-game-framework-part-ii.html”
查看 AndroidGraphics 和 AndroidFastRenderView 的实现,了解他如何使用 AndroidGraphics 在缓冲区中完成所有实际绘图并将该缓冲区绘制到 AndroidFastRenderView 中的 canvas。
我正在尝试制作弹幕游戏,但 运行 遇到了一些麻烦。大约 500 发子弹后,我无法获得超过 17 fps。所有更新逻辑代码大约需要 1-4 毫秒,而渲染代码大约需要 40 毫秒
现在我的代码是
private void drawEntities(Canvas canvas) {
for (HashMap<UUID, Spatial> h: spatialList) {
for (Spatial spatial: h.values()) {
spatial.render(canvas);
if(spatial.life > 0)
spatial.life--;
else if (spatial.life == 0)
engine.deleteEntity(spatial.owner);
}
}
}
spatialList 是一个数组列表,其中每个索引都是一个 zLevel
显示实际子弹的空间是
public void render(Canvas canvas) {
float angle = (float) (vel.getAngle() * (180 / Math.PI));
matrix.reset();
matrix.setTranslate(pos.x - bullet.getWidth() / 2, pos.y - bullet.getHeight() / 2);
matrix.postRotate(angle + 90, pos.x, pos.y);
canvas.drawBitmap(bullet, matrix, paint);
canvas.drawCircle(pos.x, pos.y, col.getRadius(), paint);
}
我可以提供更多代码,但这些似乎是主要问题。我已经尝试了所有我能想到的方法,但在网上找不到其他方法。我唯一能想到的解决方法是从 surfaceview 切换到 GLSurfaceview,但我真的认为有更好的方法,我只是使用了错误的代码。
编辑:我注意到我的计时器已关闭并移除了画圈,在 运行 再次启用它后我得到 40ms~ 500 左右,这对于合理的性能来说仍然有点太低了。
TLDR; 500 个实体 = 17 fps。
尝试从 render() 方法中删除旋转 and/or drawCircle 部件时的性能。它们都可能非常耗时,因为它们可能包含 sin() / cos() 计算。
如果这有帮助,您将不得不想出如何用更快的东西替换它们,如果没有,那么...
您可能会受到像素填充率的限制。您的测试设备上的显示屏有多大(以像素为单位)?
一件简单的事情就是使用setFixedSize()
to reduce the size of the SurfaceView's Surface. That will reduce the number of pixels you're touching. Example here, video here, blog post here。
这样做通常是个好主意,因为较新的设备似乎正朝着荒谬的像素数方向发展。一款在软件中执行所有渲染的全屏游戏将在 2560x1440 显示器上挣扎,并且在 4K 下表现不佳。 "Limiting" 将游戏设置为 1080p 并让显示缩放器完成繁重的工作应该会有所帮助。根据游戏的性质,您可以将分辨率设置得更低而不会明显降低质量。
另一件事是消除 drawBitmap()
调用,检查你的计时,然后恢复它并消除 drawCircle()
调用,看看一个或另一个是否正在咀嚼大部分时间。
您可能会发现切换到 OpenGL ES 并不是那么糟糕。 Grafika 中的 "hardware scaler exerciser" activity(来自上面链接的视频)显示了一些简单的位图渲染。将 drawCircle()
替换为缩放位图,您可能已经完成了大部分工作。 (请注意,它使用 SurfaceView,而不是 GLSurfaceView,用于 GLES activity。)
我遇到了同样的问题。如果在位图帧缓冲区上进行所有绘制,然后将帧缓冲区绘制到canvas,问题将在很大程度上得到解决。如果您直接在 canvas 上绘图,那么会有一些开销。我环顾四周,找到了这个教程 “http://www.kilobolt.com/day-6-the-android-game-framework-part-ii.html”
查看 AndroidGraphics 和 AndroidFastRenderView 的实现,了解他如何使用 AndroidGraphics 在缓冲区中完成所有实际绘图并将该缓冲区绘制到 AndroidFastRenderView 中的 canvas。