Source and destination rectangles

Now that we have something drawn to the screen, it is a good idea to cover the purpose of source and destination rectangles, as they will be extremely important for topics such as tile map loading and drawing. They are also important for sprite sheet animation which we will be covering later in this chapter.

We can think of a source rectangle as defining the area we want to copy from a texture onto the window:

  1. In the previous example, we used the entire image so we could simply define the source rectangle's dimensions with the same dimensions as those of the loaded texture.
    Source and destination rectangles
  2. The red box in the preceding screenshot is a visual representation of the source rectangle we used when drawing to the screen. We want to copy pixels from inside the source rectangle to a specific area of the renderer, the destination rectangle (the red box in the following screenshot).
    Source and destination rectangles
  3. As you would expect, these rectangles can be defined however you wish. For example, let's open up our Game.cpp file again and take a look at changing the size of the source rectangle. Place this code after the SDL_QueryTexture function.
    m_sourceRectangle.w = 50;
    m_sourceRectangle.h = 50;

    Now build again and you should see that only a 50 x 50 square of the image has been copied across to the renderer.

    Source and destination rectangles
  4. Now let us move the destination rectangle by changing its x and y values.
    m_destinationRectangle.x = 100;
    m_destinationRectangle.y = 100;

    Build the project again and you will see that our source rectangle location has remained the same but the destination rectangle has moved. All we have done is move the location that we want the pixels inside the source rectangle to be copied to.

    Source and destination rectangles
  5. So far we have left the source rectangle's x and y coordinates at 0 but they can also be moved around to only draw the section of the image that you want. We can move the x and y coordinates of the source to draw the bottom-right section of the image rather than the top-left. Place this code just before where we set the destination rectangle's location.
    m_sourceRectangle.x = 50;
    m_sourceRectangle.y = 50;

    You can see that we are still drawing to the same destination location but we are copying a different 50 x 50 section of the image.

    Source and destination rectangles
  6. We can also pass null into the render copy for either rectangle.
    SDL_RenderCopy(m_pRenderer, m_pTexture, 0, 0);

    Passing null into the source rectangle parameter will make the renderer use the entire texture. Likewise, passing null to the destination rectangle parameter will use the entire renderer for display.

    Source and destination rectangles

We have covered a few different ways that we can use rectangles to define areas of images that we would like to draw. We will now put that knowledge into practice by displaying an animated sprite sheet.

Animating a sprite sheet

We can apply our understanding of source and destination rectangles to the animation of a sprite sheet. A sprite sheet is a series of animation frames all put together into one image. The separate frames need to have a very specific width and height so that they create a seamless motion. If one part of the sprite sheet is not correct it will make the whole animation look out of place or completely wrong. Here is an example sprite sheet that we will use for this demonstration:

Animating a sprite sheet
  1. This animation is six frames long and each frame is 128 x 82 pixels. We know from the previous section that we can use a source rectangle to grab a certain part of an image. Therefore we can start by defining a source rectangle that encompasses the first frame of the animation only.
    Animating a sprite sheet
  2. Since we know the width, height, and location of the frame on the sprite sheet we can go ahead and hardcode these values into our source rectangle. First we must load the new animate.bmp file. Place it into your assets folder and alter the loading code.
    SDL_Surface* pTempSurface = SDL_LoadBMP("assets/animate.bmp");
  3. This will now load our new sprite sheet BMP. We can remove the SDL_QueryTexture function as we are now defining our own sizes. Alter the size of the source rectangle to only get the first frame of the sheet.
    m_sourceRectangle.w = 128;
    m_sourceRectangle.h = 82;
  4. We will leave the x and y position of both rectangles at 0 so that we draw the image from the top-left corner and also copy it to the top-left corner of the renderer. We will also leave the dimensions of the destination rectangle as we want it to remain the same as the source rectangle. Pass both rectangles into the SDL_RenderCopy function:
    SDL_RenderCopy(m_pRenderer, m_pTexture, &m_sourceRectangle, &m_destinationRectangle);

    Now when we build we will have the first frame of the animation.

    Animating a sprite sheet
  5. Now that we have the first frame, we can move on to animating the sprite sheet. Each frame has the exact same dimensions. This is extremely important for this sheet to animate correctly. All we want to do is move the location of the source rectangle, not its dimensions.
    Animating a sprite sheet
  6. Every time we want to move another frame, we simply move the location of the source rectangle and copy it to the renderer. To do this we will use our update function.
    void Game::update()
    {
      m_sourceRectangle.x = 128 * int(((SDL_GetTicks() / 100) % 6));
    }
  7. Here we have used SDL_GetTicks() to find out the amount of milliseconds since SDL was initialized. We then divide this by the amount of time (in ms) we want between frames and then use the modulo operator to keep it in range of the amount of frames we have in our animation. This code will (every 100 milliseconds) shift the x value of our source rectangle by 128 pixels (the width of a frame), multiplied by the current frame we want, giving us the correct position. Build the project and you should see the animation displayed.

Flipping images

In most games, players, enemies, and so on, will move in more than one direction. To allow the sprite to face in the direction it is moving we will have to flip our sprite sheet. We could of course create a new row in our sprite sheet with the frames flipped, but this would use more memory, which we do not want. SDL 2.0 has another render function that allows us to pass in the way we want our image to be flipped or rotated. The function we will use is SDL_RenderCopyEx. This function takes the same parameters as SDL_RenderCopy but also takes specific parameters for rotation and flipping. The fourth parameter is the angle we want the image to be displayed with parameter five being the center point we want for the rotation. The final parameter is an enumerated type called SDL_RendererFlip.

The following table shows the available values for the SDL_RendererFlip enumerated type:

SDL_RendererFlip value

Purpose

SDL_FLIP_NONE

No flipping

SDL_FLIP_HORIZONTAL

Flip the texture horizontally

SDL_FLIP_VERTICAL

Flip the texture vertically

We can use this parameter to flip our image. Here is the revised render function:

void Game::render()
{
  SDL_RenderClear(m_pRenderer);

  SDL_RenderCopyEx(m_pRenderer, m_pTexture,
  &m_sourceRectangle, &m_destinationRectangle,
  0, 0, SDL_FLIP_HORIZONTAL); // pass in the horizontal flip

  SDL_RenderPresent(m_pRenderer);
}

Build the project and you will see that the image has been flipped and is now facing to the left. Our characters and enemies will also have frames specifically for animations such as attack and jump. These can be added to different rows of the sprite sheet and the source rectangle's y value is incremented accordingly. (We will cover this in more detail when we create our game objects.)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.158.165