Continuando com nossa série de artigos traduzido do site lazyfoo, agora veremos como renderizar clips contidos em uma única imagem.
Algumas vezes você quer renderizar apenas parte de uma textura. Em várias situações jogos preferem manter múltiplas imagem na mesma folha ao invés de ter que usar um monte de texturas. Usando a renderização de clips, podemos definir uma parte da textura a ser renderizada ao invés de renderizar ela inteira.
//Texture wrapper class class LTexture { public: //Initializes variables LTexture(); //Deallocates memory ~LTexture(); //Loads image at specified path bool loadFromFile( std::string path ); //Deallocates texture void free(); //Renders texture at given point void render( int x, int y, SDL_Rect* clip = NULL ); //Gets image dimensions int getWidth(); int getHeight(); private: //The actual hardware texture SDL_Texture* mTexture; //Image dimensions int mWidth; int mHeight; };
Aqui fazemos uma pequena alteração na função de renderização da classe da textura. A função agora aceita um retângulo que define qual parte da textura queremos renderizar. Damos a esse argumento o valor padrão NULL no caso de querermos renderizar a textura inteira.
//Scene sprites SDL_Rect gSpriteClips[ 4 ]; LTexture gSpriteSheetTexture;
Nesse artigo, iremos usar essa folha de imagens:
E renderizar cada unidade em um canto da tela diferente:
Assim, iremos precisar de uma imagem de textura e 4 retângulos para definir as unidades, que são variáveis que você declara.
void LTexture::render( int x, int y, SDL_Rect* clip ) { //Set rendering space and render to screen SDL_Rect renderQuad = { x, y, mWidth, mHeight }; //Set clip rendering dimensions if( clip != NULL ) { renderQuad.w = clip->w; renderQuad.h = clip->h; } //Render to screen SDL_RenderCopy( gRenderer, mTexture, clip, &renderQuad ); }
Aqui temos a nova função de renderização da classe da textura que suporta a renderização de clips. É basicamente a mesma da função antiga mas com duas mudanças.
Em primeiro lugar, como quando ao recortar a textura estaremos usando as dimensões de um retângulo ao invés de usar a textura inteira. iremos ter que ajustar a largura/altura do retângulo de destino (aqui chamado de renderQuad) para o tamanho do retângulo a ser recortado.
Em segundo lugar, iremos passar o retângulo a ser recortado para SDL_RenderCopy como retângulo fonte. Esse retângulo define qual parte da textura você quer renderizar. Quando o retângulo fonte é NULL, a textura inteira é renderizada.
bool loadMedia() { //Loading success flag bool success = true; //Load sprite sheet texture if( !gSpriteSheetTexture.loadFromFile( "11_clip_rendering_and_sprite_sheets/dots.png" ) ) { printf( "Failed to load sprite sheet texture!\n" ); success = false; } else { //Set top left sprite gSpriteClips[ 0 ].x = 0; gSpriteClips[ 0 ].y = 0; gSpriteClips[ 0 ].w = 100; gSpriteClips[ 0 ].h = 100; //Set top right sprite gSpriteClips[ 1 ].x = 100; gSpriteClips[ 1 ].y = 0; gSpriteClips[ 1 ].w = 100; gSpriteClips[ 1 ].h = 100; //Set bottom left sprite gSpriteClips[ 2 ].x = 0; gSpriteClips[ 2 ].y = 100; gSpriteClips[ 2 ].w = 100; gSpriteClips[ 2 ].h = 100; //Set bottom right sprite gSpriteClips[ 3 ].x = 100; gSpriteClips[ 3 ].y = 100; gSpriteClips[ 3 ].w = 100; gSpriteClips[ 3 ].h = 100; } return success; }
A função de carregamento de imagem carrega a textura e então define os retângulo a ser recortada para cada unidade da textura carrega com sucesso.
//While application is running while( !quit ) { //Handle events on queue while( SDL_PollEvent( &e ) != 0 ) { //User requests quit if( e.type == SDL_QUIT ) { quit = true; } } //Clear screen SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF ); SDL_RenderClear( gRenderer ); //Render top left sprite gSpriteSheetTexture.render( 0, 0, &gSpriteClips[ 0 ] ); //Render top right sprite gSpriteSheetTexture.render( SCREEN_WIDTH - gSpriteClips[ 1 ].w, 0, &gSpriteClips[ 1 ] ); //Render bottom left sprite gSpriteSheetTexture.render( 0, SCREEN_HEIGHT - gSpriteClips[ 2 ].h, &gSpriteClips[ 2 ] ); //Render bottom right sprite gSpriteSheetTexture.render( SCREEN_WIDTH - gSpriteClips[ 3 ].w, SCREEN_HEIGHT - gSpriteClips[ 3 ].h, &gSpriteClips[ 3 ] ); //Update screen SDL_RenderPresent( gRenderer ); }
Finalmente, no loop principal temos que renderizar a mesma textura 4 vezes, mas renderizamos uma parte diferente da folha em locais diferentes a cada renderização.
Baixe o código fonte e os arquivos de mídia desse artigo aqui.