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。