Playing SDL - Easy

Surely, everyone had the idea to write some kind of graphic game or program. But there is not always time or desire to master graphics in programming. I hope this article helps you learn how to write (or just write) a simple but very funny game.
Finished project


It will be a little-known Flood-It. The idea is extremely simple:
It is required to paint over the entire field in one color, despite the fact that you can paint only the entire part of one color adjacent to the upper left square.

Initialization



Each SDL program should begin with a very important thing - initializing the necessary subsystems and setting the basic parameters. In our example, we only need to initialize the video.
This process takes place using the SDL_Init command,
which takes as a parameter the constants (separated by a logical “or”) that are responsible for one or another part. So, for the video subsystem you need to write
SDL_Init(SDL_INIT_VIDEO)



If you need other systems, you can use this list:

  • SDL_INIT_AUDIO
  • SDL_INIT_VIDEO
  • SDL_INIT_TIMER
  • SDL_INIT_CDROM
  • SDL_INIT_JOYSTICK
  • SDL_INIT_EVERYTHING - initialization of all subsystems
  • SDL_INIT_NOPARACHUTE - do not catch fatal signals
  • SDL_INIT_EVENTTHREAD - run the event manager in a separate thread


Oh, if everything was so simple here. In fact, this may not always succeed, and you need to crash if it fails. And for this, you just need to monitor the value returned by SDL_Init - in case of failure, a negative number is always returned.

if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "Unable to init SDL");
        return 1;
    }



Not too informative. It’s useful for users (and us) to know what caused the problem. SDL_GetError () will always return the text of the problem. Using this function we will make the error message more pleasant

if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
        printf( "Unable to init SDL: %s", SDL_GetError());
        return 1;
}


The surface



Well, now that we are ready to start creating, we need to figure out how this happens. Images are stored on surfaces (surfaces), with which you can do many useful things - lay on top of each other, draw on them and so on.
The part that is visible on the screen will also require a surface. It is not difficult to set this surface, for this there is the SDL_SetVideoMode command, which will set the size of
this surface (and therefore the program screen), the number of bits per color, as well as all sorts of important parameters, including hardware / software acceleration and much more.

There is also one useful parameter SDL_DOUBLEBUF that adds a buffer to this surface. All actions will not be displayed on the screen until the necessary moment. This will speed up our program well (although it is not demanding at all, it’s more pleasant and cultured).

So, creating a surface as follows

SDL_Surface * screen = SDL_SetVideoMode(550, 420, 16, SDL_HWSURFACE | SDL_DOUBLEBUF); /// 550x420 — таким будет размер нашего окна. А цвет будет 16-битным. Видео с аппаратным ускорением из-за параметра SDL_HWSURFACE
// Если не поддерживается аппаратное ускорение, то может SDL_SWSURFACE(программное ускорение)



again, we may not get the desired result. We will again display an error message and end execution if there is no surface.

If (!screen)
{
    printf("Can't set videomode: %s", SDL_GetError());
    return 1;
}



Images



Now that we have taken into account all the possible problems, nothing bad should happen.
The 14x14 playing field will consist of blocks of 6 colors. Each block is nothing more than a simple picture. Frustrating, but SDL can only work with BMP format images. However, this problem is solved by connecting the SDL_Image library, but in our example we do not have colossal volumes of images, and BMP is enough for us.
You can upload the image to the surface in a similar way:

int InitImages()
{
    for (int i = 0; i < 6; i++) // У нас будет 6 цветов
    {
        char path[20];
        for (int j = 0; j < 20; j++)
            path[j] = 0;
        sprintf(path, "Block%d.bmp", i);
        block[i] = SDL_LoadBMP(path); // Загружаем BMP по заданному пути в block[i]
        if (!block[i])
            return -1;
    }
     return 1;
}



And if something goes wrong during the image loading process, then a negative value will be returned (and then we know what to do).
The image after loading is presented by the type we already know - surface. Therefore, we will store blocks in an array of block surfaces. It looks like we have everything to bring the playing field. Except for one ... There is a surface with an image, there is a screen surface, but how to transfer another surface (or part) to screen?

For these purposes, there is SDL_BlitSurface, which can rewrite a rectangle from one surface with coordinates x1, y1 and dimensions w, h to another surface in place of x2, y2. Somehow a lot of parameters, and besides, the coordinates are not transmitted in prime numbers. Since we will only display everything on the screen surface, we will write a small procedure

void DrawImage(SDL_Surface * img, int x, int y, int w, int h, int sx, int sy)
{
    SDL_Rect desc; // координаты, куда нужно наложить часть.
    desc.x = x;
    desc.y = y;
    SDL_Rect src; // накладываемый прямоугольник.
    src.x = sx;
    src.y = sy;
    src.w = w;
    src.h = h;
    SDL_BlitSurface(img, &src, screen, &desc);
}



Let's analyze the parameters passed:
img - the surface, part of which we will add. X, Y are the coordinates to which you want to display. SX, SY, W, H - parameters of the displayed rectangle (angle coordinates and size). The magic of the transmitted values ​​is that the coordinates must be set in the SDL_Rect type (from the rectangle), which has 4 values ​​- X, Y, W, H. Well, after setting the coordinates in the new type, overlapping is performed.

Now, it's time to create and, most importantly, draw a playing field. Let's create the GenMap field generation procedure, which fills the map with random numbers from 0 to 5 (denoting color).

void GenMap()
{
    for (int i = 0; i < maps; i++)
        for (int j = 0; j < maps; j++)
            map[i][j] = rand() % 6;
}



We add another procedure that displays the image in its rightful place according to the coordinates of the block (for the block X, Y it will be a rectangle with 30 * X, 30 * Y, 30 * (X + 1), 30 * (Y + 1), for blocks 30x30 pixels).

void DrawBlock(int x, int y)
{
    DrawImage(block[map[x][y]], 30 * x, 30 * y, 30, 30, 0, 0); // блок в координаты 30*x, 30*y размером 30x30
}



And at the same time, we’ll create the whole field

void DrawMap()
{
    for (int i = 0; i < maps; i++) // maps(map size) — размер игрового поля.
        for (int j = 0; j < maps; j++)
            DrawBlock(i, j);
}



Time to check what happened. We generate a field, deduce, and ... Nothing! How so? It seems that everything is correct, but ... Screen buffer, do not forget to display it. It is done simply

    GenMap();
    DrawMap();
    SDL_Flip(screen);



It is SDL_Flip that will perform the desired action with screen. And now you can see the result:
Result

Great, everything works.
This, perhaps, is worth stopping in this article. Continued here .

Also popular now: