I make a logical game for Android. And everything would be fine if it were not for one BUT ... When drawing using the surfaceview, there is a problem when you need to draw many objects. FPS sags to 25-30. More specifically:

There is a two-dimensional array of cells of the field (targets) and an array of elements of the same size that need to be moved (balls). In the method of drawing the playing field, I first run through the array of cells, and then - through the array of elements.

private void presentField(){ Graphics g = game.getGraphics(); fieldCanvas.drawRect(0,0,fieldBitmap.getWidth(),fieldBitmap.getHeight(),clearPaint); for(int j=0;j<world.getLevel().getSizeJ();j++){ for(int i=0;i<world.getLevel().getSizeI();i++){ drawGameElement(world.getLevel().getField()[i][j],j,i); } } int chipI=0; int chipJ=0; for(int j=0;j<world.getLevel().getSizeJ();j++){ for(int i=0;i<world.getLevel().getSizeI();i++){ fieldCanvas.drawBitmap(elementBitmap,j*200+getBallShiftX(candyElement),i*200+getBallShiftY(candyElement),null); //} if(world.getLevel().getBalls()[i][j].getColor()!= GameElement.ElementColor.CHIP) { drawGameElement(world.getLevel().getBalls()[i][j], j, i); } else { chipI = i; chipJ = j; } } } drawGameElement(world.getLevel().getBalls()[chipI][chipJ],chipJ,chipI); g.drawBitmap(fieldBitmap, dstRect); } 

Here is the method that performs the drawing:

 private void drawGameElement(GameElement element, int x, int y){ Bitmap atlas=null; int candyShiftX=0; int candyShiftY=0; if(element instanceof Target){ if(element.getColor()== GameElement.ElementColor.CHIP){ fieldCanvas.drawBitmap(Assets.chipTarget, x*200,y*200, null); } else { atlas=Assets.targets; } } else if (element instanceof Ball){ candyShiftX=getBallShiftX((Ball) element); candyShiftY=getBallShiftY((Ball) element); if(element.getColor()== GameElement.ElementColor.CHIP){ fieldCanvas.drawBitmap(Assets.chip, (x*200)+candyShiftX,(y*200)+candyShiftY, null); } else { atlas=Assets.candys; } } if(atlas!=null){ atlasRect.left=getPicIdByColor(element.getColor())*200; atlasRect.top=0; atlasRect.right=(getPicIdByColor(element.getColor())*200)+200; atlasRect.bottom=200; fieldDstRect.left=(x*200)+candyShiftX; fieldDstRect.top=(y*200)+candyShiftY; fieldDstRect.right=(x*200)+200+candyShiftX; fieldDstRect.bottom=(y*200)+200+candyShiftY; fieldCanvas.drawBitmap(atlas,atlasRect,fieldDstRect,null); } } 

Since the size of the field at each level is different, I draw the fields and elements not in the main Bitmap, but in the auxiliary one. When I run through both arrays, I draw an auxiliary Bitmap in the main one.

I keep the pictures of the elements and fields in the atlases (except for the field and the element that need to be managed, but I don’t think that this detail is important here).

At the first levels, everything works fine - for example, the field size is 3 by 3, FPS is 60. But when the field size becomes 5 by 6, then the FPS drops by half, or even more.

Does anyone know a way to align the FPS with so many elements?

Here is the Assets class:

 public class Assets { public static Bitmap background; public static Bitmap curtain; public static Bitmap loadingLabel; public static Bitmap playButtonLabel; public static Bitmap aboutButtonLabel; public static Bitmap winLabel; public static Bitmap targets; public static Bitmap candys; //public static Bitmap blueBall; //public static Bitmap redBall; public static Bitmap chip; //public static Bitmap blueTarget; //public static Bitmap redTarget; public static Bitmap chipTarget; public static Bitmap lockedPack; public static Bitmap pack1; public static Bitmap pack2; public static Bitmap lockedLevel; public static Bitmap levels; public static Bitmap escapeLabel; public static Bitmap escapeButtons; public static Bitmap lives; public static Bitmap lowEnergy; public static Bitmap cat; } 

I get the pictures from the Assets folder via AssetManager:

  Assets.targets = g.newBitmap("targets.png"); 

Here is my newBitmap method:

 public Bitmap newBitmap(String fileName) { Bitmap bitmap=null; InputStream in=null; try{ in = assets.open(fileName); bitmap = BitmapFactory.decodeStream(in); if(bitmap==null) throw new RuntimeException("Couldn't load bitmap from asset '"+fileName+"'" ); } catch (IOException ex){ throw new RuntimeException("Couldn't load bitmap from asset '"+fileName+"'" ); } finally { if(in!=null){ try { in.close(); } catch (IOException ex) { ex.printStackTrace(); } } } return bitmap; } 
  • show the Assets class, if this is what I think, it is not at all surprising - Shwarz Andrei Sept
  • @ShwarzAndrei Added to description. - Sergey
  • one
    Well, what I thought, I do not even know where to start, of course, pure java will not give perf for games, but here you can optimize work very much. Starting with .png, watch what's there, if alpha is not needed, it will give a strong performance increase, every time you strain Assets, open a stream, by the way you can't see where you cut bmp, you need to do it once before the game itself, then use, somehow and how many times, it will give a very strong increase, look at the drawing itself, what is there - I am sure that you can ottyunit there, in short, there is work to do, but I didn’t even read and didn’t test it. - Shwarz Andrei
  • @ShwarzAndrei, thanks a lot for the tips! I'm new to this business, so I would like to clarify a couple of details. At the expense of the alpha - it will be removed from only one atlas. You wrote "by the way it is not visible where you cut bmp". I use png. Is there a significant difference in the use of these two formats? Cut at the beginning - the createBitmap method (Bitmap, int, int, int, int)? Instead, I do this in drawing: fieldCanvas.drawBitmap (atlas, atlasRect, fieldDstRect, null); Loading from Asset occurs before the beginning of the level; in each drawing step, no threads are created. - Sergey

0