(This thread of discussion originated on the wiki but has since been moved to the forums.)
Comment by philomory, Nov 08, 2008
So, I'm in the process of creating a puzzle-game (in ruby) with a tile-based map. Every level is split into a grid (20x14) of tiles, and each tile has something in it, even if that something is simply 'the floor'.
I was profiling my code and rather dismayed (but not surprised) to discover that I spend nearly 80% of my process time drawing the map over and over again, every frame. This is because I have to loop over all 280 tiles every frame and call each one's draw method. I have to call each one every time, even though almost none of them change from frame to frame, because otherwise they are erased. (In fact, if the player is not pressing keys, there is only one in-game object that can be moving, and there can only be one of it on screen at a time).
It'd be very nice if there was a way to get around re-drawing everything all the time, but so far the only way I can think of is to have a pre-generated image for the large set of non-changing tiles, and then draw the rest of the objects over-top of it. The problem with this approach is that I have 100 levels and eventually plan to offer multiple tile-sets, so generating a PNG for each level and packaging it with the game is not going to work.
My basic question is this: Do I have any solution other than RMagic for this? Is there some way (within Ruby) to force Gosu not to erase the previous frame before calling Window#draw for the next one? Because if I could just leave the last frame up and only redraw things that I want changed, it would be a huge improvement in performance.
Otherwise if I want to avoid the redraw issue, it looks like I'll need to use RMagick to construct a 'floor plan' image as I load the level data, which would be fine, but I'd really rather not have to package RMagick and the ImageMagick? library with the game (let alone compiling ImageMagick? for all three platforms (Mac would have to be UB, too, so more like 3.5)).
Byjlnr (dev)
Date 2008-11-09 03:56
Edited 2008-11-09 03:58
Gosu will never be designed for that as it complicates the whole architecture (with regard to double-buffering, scrolling, dirty rectangles etc). What is much more likely is that you will later be able to record macros using a syntax like:
my_macro = record_macro do @my_image.draw(...) end ... my_macro.draw
Drawing 20x14 tiles shouldn't cause any performance issues though :( And right now, there is no way to get around redrawing everything.
Now, the macro you refer to... how would it work? It seems like it's either essentially a proc, and is storing the sequence of drawing steps, or it's a way to generate a Gosu::Image object (or something very much like one) which is composed of many others. I'm hoping it's the latter, since the former wouldn't be very useful. If it does save the result, rather than the list of steps which generated the result, it'd be exactly what I'm looking for.
Say I wrote something akin to this:
--- level_background = record_macro do (0...width).each do |x| (0...height).each do |y| @places[x][y].draw_background(x,y) end end end ---
If I call level_background.draw, would any calls to my tiles' draw_background method be made?
As for the performance issue, it's not that the game doesn't run well. It's perfectly smooth at all times. It's just that it also has my CPU pegged at around 80% or higher at all times (G5 iMac, 1.9 GHz). If you say Gosu shouldn't be doing that, then you are very likely correct, and there is probably something unnecessarily inefficient in my code, which I suppose I will go look for now.
It would be a macro that can be drawn like an Image (sort of, color modulation wouldn't be possible) that is actually just one Ruby call happening. In the background, it would either be an OpenGL VBO or, if that doesn't work, a small, custom macro system (in C++).
I wonder if the overhead comes from Ruby or the bloaty SWIG wrappers for my C++ methods. If it's Ruby, it would also help to finally have Gosu work with Ruby 1.9 on OS X :)
Awesome, that sounds exactly like what I'm looking for.
As for Gosu working with 1.9 on OS X, I actually have some questions about that, too, but I guess now that we have a forum, I should make a new thread for it.