1
\$\begingroup\$

I just started making a game for Android and I'm already having some issues regarding performance.

You can imagine the game as being some kind of Tower Defense game with a top-view, and the enemies can move in all directions, so I need to be able to make the sprites rotate in all directions.

I'm currently using a sprite-sheet with transparency for the enemies and using canvas.rotate() to make all the enemies face a given target.

When there are 60 enemies on screen, it takes about 25ms to rotate and draw the enemies, but if I remove the rotation part, it takes about 7 ms. In itself, it doesn't seem too bad, but there are going to be many more enemies at once on screen eventually, with projectiles, other entities, etc. and I'm drawing the background tile by tile (around 80 tiles), so that's 80 more bitmaps to draw, although at the moment it's only 4 different bitmaps being drawn multiple times.

Here is part of the code that draws and rotates the enemies:

In the "render" method in a SurfaceView, called in the gameloop:

for (Enemy enemy : level.getListEnemies()) {
        if (enemy.isVisibleInView(level.getCamera(), screenWidth, screenHeight)) {
            enemy.draw(level.getCamera(), level.getAngle(enemy), canvas, paint);
        }
    }

Enemy.draw:

public void draw(Camera camera, float angle, Canvas canvas, Paint paint) {
    float x1 = this.getPosX() - level.getCamera().getOffSetX() - this.getSizeX() / 2;
    float x2 = this.getPosX() - level.getCamera().getOffSetX() + this.getSizeX() / 2;
    float y1 = this.getPosY() - level.getCamera().getOffSetY() - this.getSizeY() / 2;
    float y2 = this.getPosY() - level.getCamera().getOffSetY() + this.getSizeY() / 2;

    // Rectangles declared in the constructor, change depending on which frame to draw
    drawingLocation.set((int) x1, (int) y1, (int) x2, (int) y2);
    imageSubset.set((int) (frameId * getSizeX()), 0, (int) (frameId * getSizeX() + getSizeX()), (int) getSizeY());

    canvas.save();

    canvas.rotate(angle, x1 + sizeX / 2, y1 + sizeY / 2);
    canvas.drawBitmap(knightAttack, imageSubset, drawingLocation, paint);

    // Heath bars
    paint.setColor(Color.RED);
    canvas.drawRect(new Rect((int) x1, (int) (y2) + 10, (int) x2 + 10, (int) y2 + 14), paint);

    paint.setColor(Color.GREEN);
    canvas.drawRect(new Rect((int) x1, (int) (y2) + 10, (int) (x1 + (((x2 + 10) - x1)) * this.currentHealth / this.maxHealth), (int) y2 + 14), paint);

    canvas.restore();

    // Change frame in the image every SPRITEFRAMELENGTH
    if(frameCount++ % SPRITEFRAMELENGTH == 0){
        frameId++;

        if(frameId > MAXFRAMEID){
            frameId = 0;
            frameCount = 0;
        }           
    }       
}

Those times I mentionned earlier are by using:

SurfaceView.getHolder().setFormat(PixelFormat.RGB_565);

And creating the images (once, all the enemies use the same image reference):

BitmapFactory.Options op = new BitmapFactory.Options();
op.inPreferredConfig = Bitmap.Config.RGB_565;

Bitmap image = (Bitmap)BitmapFactory.decodeResource(context.getResources(), imageId, op);

if(resizeWidth != 0 && resizeHeight != 0) {
    image = Bitmap.createScaledBitmap(image, resizeWidth, resizeHeight, true);
}

But I noticed that if I don't specify RGB_565, it is much slower because of transparency, especially for the background, which don't have transparency. What's even weirder is that using RGB_565 works properly on my Galaxy Nexus, but on my friend's S3, some images (with transparency) are not displayed at all. I'm using 4.2.1 and he's on 4.1.1.

So, how can I rotate my images more efficiently? Would using OpenGL improve performance a lot or would it be about the same? Is there a better solution?

\$\endgroup\$
  • 1
    \$\begingroup\$ OpenGL will help significantly. \$\endgroup\$ – Vaughan Hilts Oct 9 '13 at 16:16
  • \$\begingroup\$ @VaughanHilts Thanks for the answer. I had read about that in some articles but I wanted to have some kind of confirmation that it would help in my particular case. I will use OpenGL, thanks. \$\endgroup\$ – Adam Smith Oct 9 '13 at 16:24
  • \$\begingroup\$ Have you considered rendering with a Matrix yet? (Documentation can be found here if needed). I'm not sure that this will solve your problem, but I would be willing to bet that the Android team has embedded tons of optimizations regarding Bitmap transformations into that class already. You would basically have to leverage the drawBitmap(Bitmap, Matrix, Paint) method and manipulated the Matrix objects as needed. \$\endgroup\$ – Squagem Oct 12 '13 at 20:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.