Are there layers to sdl or something?
by layers I mean like in photoshop we have multiple layer and can draw on one without effecting the other,
for example if I had a main_layer
, a background_layer
& an enemy_layer
where the main player reandering (like moving the character by user), a static background rendering & enemies rendering can take place respectively?
instead of having to clear the entire screen then placing everything back again over and over? i.e. changing a single thing without effecting the other? can someone point me in the right direction?
You can implement your own layer system using render targets.
It's worth noting that there is a point of diminishing return here. If a layer only contains a few sprites, it's probably cheaper to draw each sprite directly to the screen every frame even if they don't move.
Example:
// 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);
You can take this a bit further by creating layers that are larger than screen_width x screen_height
and use the srcrect
parameter of SDL_RenderCopy()
to scroll the layer. With a few background layers, that can be used to get efficient and neat-looking old-school parallax effects.
You will also probably want to encapsulate the notion of a layer into some Layer
class in C++. Here's a rough starting point:
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;
};