裁剪渲染和精灵表
有时你只想渲染纹理的一部分。 很多时候,游戏喜欢将多个图像保留在同一张精灵表上,而不是拥有一堆纹理。 使用剪辑渲染,我们可以定义要渲染的纹理的一部分,而不是渲染整个对象。
//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;
};
在这里,我们对纹理类中的渲染函数做了一个小小的调整。渲染函数现在接受一个矩形,定义我们要渲染纹理的哪一部分。我们给它一个默认参数NULL,以防我们想渲染整个纹理。
//场景精灵
SDL_Rect gSpriteClips[ 4 ];
LTexture gSpriteSheetTexture;
在本教程中,我们将使用此精灵表:
并将每个精灵渲染在不同的角落:
所以我们需要一个纹理图像和4个矩形来定义精灵,这就是你看到的这里声明的变量。
void LTexture::render( int x, int y, SDL_Rect* clip ){
//设置渲染空间并渲染至屏幕
SDL_Rect renderQuad = { x, y, mWidth, mHeight };
//设置素材的渲染尺寸
if( clip != NULL )
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}
//渲染到屏幕
SDL_RenderCopy( gRenderer, mTexture, clip, &renderQuad );
}
这是支持裁剪渲染的纹理类的新渲染函数。它和之前的纹理渲染函数大部分是一样的,但是有两个变化。
首先,当你在裁剪时,你使用的是裁剪矩形的尺寸而不是纹理,我们要将目标矩形(这里称为renderQuad)的宽度/高度设置为裁剪矩形的尺寸。
其次,我们要将裁剪矩形作为源矩形传递给SDL_RenderCopy。源矩形定义了你要渲染的纹理的哪一部分。当源矩形为NULL时,整个纹理将被渲染。
bool loadMedia(){
//Loading success flag
bool success = true;
//加载精灵表纹理
if( !gSpriteSheetTexture.loadFromFile( "11_clip_rendering_and_sprite_sheets/dots.png" ) )
{
printf( "Failed to load sprite sheet texture!\n" );
success = false;
}
else
{
//设置左上角的精灵
gSpriteClips[ 0 ].x = 0;
gSpriteClips[ 0 ].y = 0;
gSpriteClips[ 0 ].w = 100;
gSpriteClips[ 0 ].h = 100;
//设置右上角的精灵
gSpriteClips[ 1 ].x = 100;
gSpriteClips[ 1 ].y = 0;
gSpriteClips[ 1 ].w = 100;
gSpriteClips[ 1 ].h = 100;
//设置左下角的精灵
gSpriteClips[ 2 ].x = 0;
gSpriteClips[ 2 ].y = 100;
gSpriteClips[ 2 ].w = 100;
gSpriteClips[ 2 ].h = 100;
//设置右下角的精灵
gSpriteClips[ 3 ].x = 100;
gSpriteClips[ 3 ].y = 100;
gSpriteClips[ 3 ].w = 100;
gSpriteClips[ 3 ].h = 100;
}
return success;
}
媒体加载函数加载纹理,然后如果成功加载纹理,则为圆形精灵定义裁剪矩形。
//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 );
}
最后在这里的主循环中,我们对同一个纹理渲染了4次,但是我们每次调用都会在不同的地方渲染精灵表的不同部分。
在 这里下载本教程的媒体和源代码。
关注我的公众号:编程之路从0到1