1
votes

Ive been having a really baffling slow down issue with the game I am working on probably because I am unsure how to handle graphics (most likely responsible for the slow down) in javascript without using a third party framework like Phaser/ImapactJS/EaselJS etc)*. The following is the low down on how I am approaching my graphics. I would be very thankful for some tips or methods on how to do this right.

  • My game is tile based - using tiles designed at 500x500 px because I want them to display decently on high definition devices.
  • I am using a spritesheet to load all (most of) my tiles before the main loop is run. This image is roughly 4000 x 4000 (keeping it below 4096 because the GPU cant handle texture sizes larger than that).
  • I then use the drawImage function to cycle through and draw each tile on a part of the canvas using information (w, h, x, y) stored in the tile array. I do this on every cycle of the main loop using my drawMap function.
  • The map is currently 6x6 tiles in size
  • A character spritesheet is also loaded and drawn on to the canvas after the map has been drawn. The character displays a different frame of the animation on every cycle of the main loop. There are sets of animations for the character each contained in the same spritesheet.
    • The character sprite sheet is roughly 4000x3500
  • The character is roughly 350x250 px
  • Other objects also use the same sprite sheet. Currently there is only one object.

    Possibly helpful questions:

  • Am I using too many spritesheets or too few?

  • Should I only draw something if it's coordinates are in bounds of the screen?
  • How should I go about garbage collection? Do I need to set image objects to null when no longer in use?

Thanks in advance for input. I would just like to know if I am going about it the right way and pick your brains as how to speed it up enough.

*Note that I plan to port the JS game to cocoonJS which provides graphics acceleration for the canvas element on mobile.

** If interested please visit my Patreon page for fun!

1
I can tell you for sure that you should draw only what is visible on screen.pietrovismara
@Cuz Ive been thinking that might slow it a bit but as far as I know it the canvas element doesnt spend time rendering anything beyond its size.. Though I could be wrong.Walt Wonderwolk

1 Answers

1
votes

You have asked lots of questions here, I'll address the ones I've run into. I would like to start out by saying very clearly,

Use a profiler

Find out whether each thing you are advised to do, by anybody, is making an improvement. Unless we work on your code, we can only give you theories on how to optimise it.

How should I go about garbage collection? Do I need to set image objects to null when no longer in use?

If you are no longer using an object, setting its reference to null will probably mean it gets garbage collected. Having nulls around is not necessarily good but this is not within the scope of this question.

For high performance applications, you want to avoid too much allocation and therefore too much garbage collection activity. See what your profiler says - the chrome profiler can tell you how much CPU time the garbage collector is taking up. You might be OK at the moment.

I then use the drawImage function to cycle through and draw each tile on a part of the canvas using information (w, h, x, y) stored in the tile array. I do this on every cycle of the main loop using my drawMap function.

This is quite slow - instead consider drawing the current on screen tiles to a background canvas, and then only drawing areas which were previously obscured.

For example, if your player walks to the left, there is going to be a lot of tiles on the left hand side of the screen which have come into view; you will need to draw the background buffer onto the screen, offset to account for the movement, and then draw the missing tiles.

My game is tile based - using tiles designed at 500x500 px because I want them to display decently on high definition devices

If I interpret this right, your tiles are 500x500px in diameter, and you are drawing a small number of these on screen. and then for devices without such a high resolution, the canvas renderer is going to be scaling these down. You really want to be drawing pixels 1:1 on each device.

Would you be able, instead, to have a larger number of smaller tiles on screen - thereby avoiding the extra drawing at the edges? Its likely that the tiles around the edges will sometimes draw only a few pixels of one edge, and the rest of the image will be cropped anyway, so why not break them up further?

Should I only draw something if it's coordinates are in bounds of the screen?

Yes, this is a very common and good optimisation to take. You'll find it makes a big difference.

Am I using too many spritesheets or too few?

I have found that when I have a small number of sprite sheets, the big performance hit is when I frequently switch between them. If during one draw phase, you draw all your characters from character_sheet.png and then draw all the plants from plant_sheet.png you'll be ok. Switching between them can cause lots of trouble and you'll see a slow down. You will know this is happening if your profiler tells you that drawImage is taking a big proportion of your frame.