First prototype completed, looking for advice in performance.

Started by
6 comments, last by The_Marlboro_Man 17 years ago
I agree with both of you, I thought there should be something within my code that works wrong. As for the loading of the file "each time", yes and no... Let me explain it with a bit of code:

      SDL_Rect marco; SDL_Rect coordenadas;         //Marco is "frame", the method I use to select the blitable part of the bitmap. Coordenadas is "Coordinates", the place where everything will be.      SDL_Surface *objeto=NULL;         //Objeto is what I´ll blit into "pantalla", the screen surface.      objeto=CargarImagen("juego.bmp");      marco.w=16; marco.h=16;      for(short int contador=0; contador<1200; contador++)                                         {           switch(matriz[contador])    //Matriz is the game matrix.                                                              {                      case 0: marco.x=0; marco.y=0; break;                 case 1: marco.x=48; marco.y=0; break;                 case 2: marco.x=48; marco.y=16; break;                 case 3: marco.x=16; marco.y=0; break;                 case 4: marco.x=32; marco.y=0; break;                 case 5: marco.x=32; marco.y=16; break;                 case 6: marco.x=0; marco.y=16; break;            }                                    coordenadas.x=((contador%40)*16)+80;  //This is the way I get the            coordenadas.y=((contador/40)*16)+48;  //coordinates.            SDL_BlitSurface(objeto, &marco, pantalla, &coordenadas);                      }


Here, this function loads the tileset and checks the whole matrix. Depending on the value of the matrix a certain portion of the tileset is blitted.

The function is called in each gametic (errr... Every iteration of the main game loop, whether something happens or not... I know, lazy!). You can see that I use a "CargarImagen" function (literally "Loadimage") so each time I run the function I load the bmp file again. What I don´t do is loading the bmp for each blitting "tile" of the matrix.

So, do you advise me to load the bmp file only once?. I could load it in the "main game loop" and send the resulting surface along to the function above like maindrawing(pantalla, objeto)... I could also make it a global surface but I´m not sure about globals (I don´t really dig them, not sure why).

Thanks in advance for all replies and suggestions :).
Advertisement
Hello again!. It has been a bit of time since I didn´t posted but I´ve been reading and coding almost on a daily basis to try and learn new things. In the way I´ve been messing with the SDL library to complete the first prototipe for the simplest game I could think about. In this post I will talk a bit about this game, put a link and, of course, ask the questions. First things first: the problem is with the performance. The game runs pretty much slow and I would like to know if SDL is doomed to be that slow or if its just my code. I will talk later about that... Now for the game: here it is, a zip with the dll, the exe and the bmp files: http://www.megaupload.com/es/?d=WDYM4MD7 The game itself is pretty simple and it´s a variation of the "nibbles" thing where two players (two human players, no AI this time :P) have to force the opponent to collide. To spice it up a bit I added some items and the possibility to change speeds. Its controlled with the cursor keys (first player), enter (for the main menu) and WASD (for the second player). In about two tries messing with it everyone should know how to play but just to make things clear, the directions you point at are absolute and if you point in the direction you´re moving towards you´ll accelerate (you´ll brake if you point in the direcction opposite of that you´re moving towards). The main playing field is a 40x30 short int matrix. Each of its elements is checked on each tic to draw the pertinent "tile" so for each gametic we have like... 1200 drawings of a 16x16 surface. I think that this algorithm (so lazy and poor) is the key to the slowdowns in older systems (like a 600mhz, 512 ram computer... I tried that algorithm to force SDL to use lots of blitting for each tic but the tile is loaded only once (once per tic, that´s it :P). I know of a better algorithm but, is mine´s the reason for the slowdowns?. What are the reasonable limits for the SDL trying to aim for older computers compatibility?. Any help and opinions are welcome: I have almost a "game" done so, why not trying to make it a bit better :)?.
When you say the tile is loaded once per tick, what do you mean exactly? If you mean you are literally loading the tile from a file each time before drawing then that would certainly be the cause of the slowdown.

SDL is not, as far as I am aware, known to be particularly slow since it sits quite closely to the underlying graphics API (DirectDraw, OpenGL, whatever) that it wraps.

It does sound to me as if the speed is issues in your code rather than with SDL. You can post relevent sections of code here (in [ source ][ /source ] tags but without the spaces) which may enable people to give you better advice.
It must be your algo not SDL.
Try to write/draw things in groups, not every tile apart)

www.nextdawn.nl
Quote:Original post by The_Marlboro_Man
So, do you advise me to load the bmp file only once?. I could load it in the "main game loop" and send the resulting surface along to the function above like maindrawing(pantalla, objeto)... I could also make it a global surface but I´m not sure about globals (I don´t really dig them, not sure why).


Yep, that's exactly the problem and you have a good instinct for avoiding globals :)

One way to do it is to make an object that represents the "map", and give it the surface as a data member. This way you can also use RAII to clean up the SDL_Surface later.

class Map {  SDL_Surface* objeto;  // The matrix should probably be a member of this class too. BTW, you can make  // the array 2D for no cost in overhead (it will be laid out in memory as a  // single chunk, and indexing operations will be transformed accordingly). The  // compiler is able to do this because the dimensions are known ahead of time.  // Also, you probably should use an enumerated type instead, but I don't know  // what the values mean so you'll have to do that part :)  int matriz[30][40]; // [rows][columns]  public:  Map(): objeto(CargarImagen("juego.bmp")) {    assert(objeto);  }  ~Map() { SDL_FreeSurface(objeto); }  void draw(SDL_Surface* pantalla) {    SDL_Rect marco, coordenadas;    // Initializing the 'marco' doesn't really help because we're going to set    // it before use every time through the loop.    // It doesn't help any to make the loop counter smaller. You should normally    // just use int for everything unless you have a specific reason you need    // a specific size.    for (int y = 0; y < 30; ++y) {      for (int x = 0; x < 40; ++x) {        switch (matriz[y][x]) {               case 0: marco.x=0; marco.y=0; break;          case 1: marco.x=48; marco.y=0; break;          case 2: marco.x=48; marco.y=16; break;          case 3: marco.x=16; marco.y=0; break;          case 4: marco.x=32; marco.y=0; break;          case 5: marco.x=32; marco.y=16; break;          case 6: marco.x=0; marco.y=16; break;        }        coordenadas.x = (x*16)+80;        coordenadas.y = (y*16)+48;        SDL_BlitSurface(objeto, &marco, pantalla, &coordenadas);                      }    }  }  // And other stuff, e.g. the code that puts values into Matriz};// Then in main(), we create a Map and use it each game tick:int main() {  Map m;  // etc. etc.  while (something) {    m.update();    m.draw(pantalla);  }}


This lets us do what a global would do for us (i.e. keep the 'surface' around between calls to draw() and not have to pass it as a parameter), but it also gives us good protection on that access (so we won't accidentally start using 'objeto' in a way that we shouldn't - it "belongs" to the Map), creates an abstraction (we can think of the Map as a new data type), and lets us create more than one (if we should ever need to).
Zahlman, thanks for your time going through my code and giving better ideas for it :). Though I don´t fully understand them I´ll make sure to study the sintax and meaning... As for the matrix, I actually had it like a bidimensional matrix in the main function but passed only a pointer to it to the draw function, to avoid massive copy of data.

Then there´s the object solution... I wish I could understand it a bit better but for now I haven´t studied any Object Oriented Programming (I will make sure to do it shortly, once I get the hang of structures). I think I shall leave it for now until I understand how classes work (and can, thus, convert the whole work to the object paradigm)... To begin with, I´ll "climb" one level and remove the "loadimage" function from each tic, passing it from the main, then I´ll try to see if there´s any advance in performance.

There´s one last question I have before I get to the code again, and I hope you don´t mind: you commented that initializing the "marco" (frame) "doesn't really help because we're going to set it before use every time through the loop". Is that the "Same" problem?. I mean, would it be better to have it "outside" the function as a global or member of a class?.

Thanks a lot!.

PS: Also, is there any reason not to use short int instead of int?. I didn´t plan the count to be high and I thought I could save 8 bites in all these small counters and vars.
Quote:Original post by The_Marlboro_Man
Also, is there any reason not to use short int instead of int?

There is no point in saving a few bits for a counter. And an int is propably faster, because it is the size of the native word.
Took a look at some sites and it seems that, in fact, int fares better than the rest of the data types. I don´t think it could have a significant impact on the game, but I could try and change them.

As for loading the image into a surface once per game and sending a pointer to the surface along to the drawing function it seems that it improved the performance a tiny bit. I wonder how much would it improve with the object approach but so far I think I could try some other things, like improving the drawing algorithm and doing just 3 blits (instead of... 1200).

My next worry lies in the sound, in having all of them loaded at once or loading them when they need to be played. I´ll try and write some small program to compare the options. Thanks a lot for the information :).

This topic is closed to new replies.

Advertisement