Hi everyone, Vlad here.
Let me start by saying that the title is a bit misleading. For starters it is not an actual bout but more a decision making process. It also gives the impression I’ll write more about this or that I have some kind of plan about this subject. I don’t, it just happens that I think I’ll travel this road again.
The game design for this game states that:
1. The player’s objective is to reach the top of the “structure” (named just to make sense) where the action rolls;
2. The “structure” has several “floors” (again just for easier comprehension);
3. The player can fall to the previous “floor”;
4. It is guaranteed that the player will see at least three “floors”;
One thing that I know for sure is that we will be blitting all graphics and that the player token has three different blit objects and two of those rotate thus negating copyPixels and putting the dreadful draw method to work.
Another thing I know is that each “floor” is a tilemap, also blitted and that each tile is 64×64.
And now the assumptions begin. How big is each “floor”? I have no idea but let’s say that a rather large “floor” has 50×50 tiles. If the player will see at least three floors and on later stages all “floors” are rather large we are talking about 7,500 tiles to be rendered with a astonishing number of 30,720,000 pixels to be copied… each frame.
The “floor” where the player is will only render the tiles on screen (88 max) but the other two lower “floors” can potentially be fully rendered given the camera specs. Even if all three “floors” only rendered tiles on screen (which won’t happen by design) there would still be 7,500 objects to manage and that’s tiles only since we need to add to this all the remaining entities: player, enemies, decorations, effects, etc, but to make it worse the bottom two levels will be zoomed and probably in full view which means not only that all their blit objects will be visible but also that at least 5,000 of those objects will use draw instead of copyPixels… Did the headache kicked in already or is it just pure performance insanity?
One of the great things about copyPixels is that it only renders the intersection between the target bitmapData rectangle and the source rectangle positioned at the destination point. What this means is that if we have 1,000 objects to render but only one actually has an intersecting rectangle, most of the processing time is running the array, vector or list and – more important and processor heavy – calling the functions that will in the end render.
The draw method also does this with a matrix… more on this later.
The solution was to write a BlitTileMap class that builds the tilemap in one big texture before it is used. While it uses much more RAM this class allows to address pretty much every problem stated earlier.
First and foremost the number of objects managed and therefor the performance lost with running their container (in our case, a linked list) and calling functions. From a potential 7,500+ we now have 3. The other issue that this addresses is the number of pixels it will render or try to render, from potentially 30,000,000+ to the worst case scenario of 1,050,000. And last but not least, considering the lower “floors” will be zoomed out, instead of using draw to render 5,000+ objects it will render… 2!
But the draw method also has a funny and helpful consequence. The smaller the scale, the faster draw executes which in terms of performance is relevant considering the zoom out will be achieved through scale. Less objects taking less time to render will be (I hope) quite a performance boost.
Did I just write all this? Wow!… Later!