您可以使用渲染目标实现自己的图层系统。
- 为每一层创建一个纹理渲染目标。
- 绘制到图层的渲染目标以更新它。
- 每一帧,将每一层绘制到屏幕上。您仍然需要事先清除最后一帧。
值得注意的是,这里有一个收益递减点。如果一个图层只包含几个精灵,即使每个精灵不移动,每帧直接将每个精灵绘制到屏幕上可能会更便宜。
例子:
// Given a renderer
SDL_Renderer *renderer = ...;
// *** Creating the layer ***
SDL_Texture *my_layer = SDL_CreateTexture(
renderer,
SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET,
screen_width, screen_height);
// To make transparency work (for non-base layers):
SDL_SetTextureBlendMode(my_layer, SDL_BLENDMODE_BLEND);
// *** Drawing TO the layer ***
SDL_SetRenderTarget(renderer, my_layer);
// For non-base layers, you want to make sure you clear to *transparent* pixels.
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
// ... Draw to the layer ...
// *** Drawing the layer to the screen / window ***
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, my_layer, NULL, NULL);
您可以通过创建大于screen_width x screen_height 的层并使用SDL_RenderCopy() 的srcrect 参数来滚动层,从而更进一步。使用一些背景层,可用于获得高效且外观整洁的老式视差效果。
您可能还希望将层的概念封装到 C++ 中的某个 Layer 类中。这是一个粗略的起点:
class Layer {
public:
Layer(SDL_Renderer *renderer, int w, int h)
: texture_(SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, w, h),
, display_{0, 0, 0, 0}
{
SDL_GetRendererOutputSize(renderer, &display_.w, &display_.h);
w = std::min(w, display_.w);
h = std::min(h, display_.h);
max_scroll_x = w - display_.w;
max_scroll_y = h - display_.h;
SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND);
}
Layer(Layer&& rhs)
: texture_(rhs.texture_)
, display_(rhs.display)
, max_scroll_x(rhs.max_scroll_x)
, max_scroll_y(rhs.max_scroll_y) {
rhs.texture_ = nullptr;
}
Layer& operator=(const Layer& rhs) {
if(texture_) {SDL_DestroyTexture(texture_);}
texture_ = rhs.texture_;
display_ = rhs.display_;
max_scroll_x = rhs.max_scroll_x;
max_scroll_y = rhs.max_scroll_y;
rhs.texture_ = nullptr;
)
Layer(const Layer& rhs) = delete;
Layer& operator=(const Layer& rhs) = delete;
~Layer() {
if(texture_) {SDL_DestroyTexture(texture_);}
}
// Subsequent draw calls will target this layer
void makeCurrent(SDL_Renderer* renderer) {
SDL_SetRenderTarget(renderer, texture_);
}
// Draws the layer to the currently active render target
void commit(SDL_Renderer* renderer, const SDL_Rect * dstrect=nullptr) {
SDL_RenderCopy(renderer, texture_, &display_, dstrect);
}
// Changes the offset of the layer
void scrollTo(int x, int y) {
display_.x = std::clamp(x, 0, max_scroll_x);
display_.y = std::clamp(y, 0, max_scroll_y);
}
private:
SDL_Texture* texture_;
SDL_Rect display_;
int max_scroll_x;
int max_scroll_y;
};