338 lines
12 KiB
C++
338 lines
12 KiB
C++
#include "background.h"
|
|
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
|
|
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
|
|
#include <algorithm> // for clamp, max
|
|
#include "asset.h" // for Asset
|
|
#include "moving_sprite.h" // for MovingSprite
|
|
#include "param.h" // for param
|
|
#include "resource.h" // for Resource
|
|
#include "screen.h"
|
|
#include "sprite.h" // for Sprite
|
|
#include "texture.h" // for Texture
|
|
|
|
// Constructor
|
|
Background::Background()
|
|
: renderer_(Screen::get()->getRenderer()),
|
|
|
|
buildings_texture_(Resource::get()->getTexture("game_buildings.png")),
|
|
top_clouds_texture_(Resource::get()->getTexture("game_clouds1.png")),
|
|
bottom_clouds_texture_(Resource::get()->getTexture("game_clouds2.png")),
|
|
grass_texture_(Resource::get()->getTexture("game_grass.png")),
|
|
gradients_texture_(Resource::get()->getTexture("game_sky_colors.png")),
|
|
|
|
rect_({0, 0, gradients_texture_->getWidth() / 2, gradients_texture_->getHeight() / 2}),
|
|
src_rect_({0, 0, 320, 240}),
|
|
dst_rect_({0, 0, 320, 240}),
|
|
base_(rect_.h),
|
|
color_(Color(param.background.attenuate_color.r, param.background.attenuate_color.g, param.background.attenuate_color.b)),
|
|
alpha_color_text_(param.background.attenuate_alpha),
|
|
alpha_color_text_temp_(param.background.attenuate_alpha)
|
|
|
|
{
|
|
// Inicializa variables
|
|
{
|
|
gradient_rect_[0] = {0, 0, rect_.w, rect_.h};
|
|
gradient_rect_[1] = {rect_.w, 0, rect_.w, rect_.h};
|
|
gradient_rect_[2] = {0, rect_.h, rect_.w, rect_.h};
|
|
gradient_rect_[3] = {rect_.w, rect_.h, rect_.w, rect_.h};
|
|
|
|
const int top_clouds_texture_height = top_clouds_texture_->getHeight() / 4;
|
|
const int bottom_clouds_texture_height = bottom_clouds_texture_->getHeight() / 4;
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
top_clouds_rect_[i] = {0, i * top_clouds_texture_height, top_clouds_texture_->getWidth(), top_clouds_texture_height};
|
|
bottom_clouds_rect_[i] = {0, i * bottom_clouds_texture_height, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_height};
|
|
}
|
|
}
|
|
|
|
// Crea los sprites
|
|
{
|
|
const int top_clouds_y = base_ - 165;
|
|
const int bottom_clouds_y = base_ - 101;
|
|
|
|
top_clouds_sprite_a_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_Rect){0, top_clouds_y, rect_.w, top_clouds_texture_->getHeight()});
|
|
top_clouds_sprite_b_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_Rect){rect_.w, top_clouds_y, rect_.w, top_clouds_texture_->getHeight()});
|
|
|
|
bottom_clouds_sprite_a_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_Rect){0, bottom_clouds_y, rect_.w, bottom_clouds_texture_->getHeight()});
|
|
bottom_clouds_sprite_b_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_Rect){rect_.w, bottom_clouds_y, rect_.w, bottom_clouds_texture_->getHeight()});
|
|
|
|
buildings_sprite_ = std::make_unique<Sprite>(buildings_texture_, 0, 0, buildings_texture_->getWidth(), buildings_texture_->getHeight());
|
|
gradient_sprite_ = std::make_unique<Sprite>(gradients_texture_, 0, 0, rect_.w, rect_.h);
|
|
grass_sprite_ = std::make_unique<Sprite>(grass_texture_, 0, 0, grass_texture_->getWidth(), grass_texture_->getHeight() / 2);
|
|
}
|
|
|
|
// Inicializa objetos
|
|
{
|
|
constexpr float top_clouds_speed = 0.1f;
|
|
constexpr float bottom_clouds_speed = 0.05f;
|
|
|
|
top_clouds_sprite_a_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
|
|
top_clouds_sprite_a_->setVelX(-top_clouds_speed);
|
|
|
|
top_clouds_sprite_b_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
|
|
top_clouds_sprite_b_->setVelX(-top_clouds_speed);
|
|
|
|
bottom_clouds_sprite_a_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
|
|
bottom_clouds_sprite_a_->setVelX(-bottom_clouds_speed);
|
|
|
|
bottom_clouds_sprite_b_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
|
|
bottom_clouds_sprite_b_->setVelX(-bottom_clouds_speed);
|
|
|
|
buildings_sprite_->setY(base_ - buildings_sprite_->getHeight());
|
|
grass_sprite_->setY(base_ - grass_sprite_->getHeight());
|
|
}
|
|
|
|
// Crea la textura para componer el fondo
|
|
canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
|
|
SDL_SetTextureBlendMode(canvas_, SDL_BLENDMODE_BLEND);
|
|
|
|
// Crea la textura para atenuar el fondo
|
|
color_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
|
|
SDL_SetTextureBlendMode(color_texture_, SDL_BLENDMODE_BLEND);
|
|
setColor(color_);
|
|
SDL_SetTextureAlphaMod(color_texture_, alpha_color_text_);
|
|
}
|
|
|
|
// Destructor
|
|
Background::~Background()
|
|
{
|
|
SDL_DestroyTexture(canvas_);
|
|
SDL_DestroyTexture(color_texture_);
|
|
}
|
|
|
|
// Actualiza la lógica del objeto
|
|
void Background::update()
|
|
{
|
|
// Actualiza el valor de alpha_
|
|
updateAlphaColorText();
|
|
|
|
// Actualiza las nubes
|
|
updateClouds();
|
|
|
|
// Calcula el frame de la hierba
|
|
grass_sprite_->setSpriteClip(0, (10 * (counter_ / 20 % 2)), 320, 10);
|
|
|
|
// Calcula el valor de alpha_
|
|
alpha_ = std::max((255 - (int)(255 * transition_)), 0);
|
|
|
|
// Incrementa el contador
|
|
++counter_;
|
|
|
|
// Compone todos los elementos del fondo en la textura
|
|
fillCanvas();
|
|
}
|
|
|
|
// Dibuja el gradiente de fondo
|
|
void Background::renderGradient()
|
|
{
|
|
// Dibuja el gradiente de detras
|
|
gradients_texture_->setAlpha(255);
|
|
gradient_sprite_->setSpriteClip(gradient_rect_[(gradient_number_ + 1) % 4]);
|
|
gradient_sprite_->render();
|
|
|
|
// Dibuja el gradiente de delante con una opacidad cada vez menor
|
|
gradients_texture_->setAlpha(alpha_);
|
|
gradient_sprite_->setSpriteClip(gradient_rect_[gradient_number_]);
|
|
gradient_sprite_->render();
|
|
}
|
|
|
|
// Dibuja las nubes de arriba
|
|
void Background::renderTopClouds()
|
|
{
|
|
// Dibuja el primer conjunto de nubes, las de detras
|
|
top_clouds_texture_->setAlpha(255);
|
|
top_clouds_sprite_a_->setSpriteClip(top_clouds_rect_[(gradient_number_ + 1) % 4]);
|
|
top_clouds_sprite_b_->setSpriteClip(top_clouds_rect_[(gradient_number_ + 1) % 4]);
|
|
top_clouds_sprite_a_->render();
|
|
top_clouds_sprite_b_->render();
|
|
|
|
// Dibuja el segundo conjunto de nubes, las de delante
|
|
top_clouds_texture_->setAlpha(alpha_);
|
|
top_clouds_sprite_a_->setSpriteClip(top_clouds_rect_[gradient_number_]);
|
|
top_clouds_sprite_b_->setSpriteClip(top_clouds_rect_[gradient_number_]);
|
|
top_clouds_sprite_a_->render();
|
|
top_clouds_sprite_b_->render();
|
|
}
|
|
|
|
// Dibuja las nubes de abajo
|
|
void Background::renderBottomClouds()
|
|
{
|
|
// Dibuja el primer conjunto de nubes, las de detras
|
|
bottom_clouds_texture_->setAlpha(255);
|
|
bottom_clouds_sprite_a_->setSpriteClip(bottom_clouds_rect_[(gradient_number_ + 1) % 4]);
|
|
bottom_clouds_sprite_b_->setSpriteClip(bottom_clouds_rect_[(gradient_number_ + 1) % 4]);
|
|
bottom_clouds_sprite_a_->render();
|
|
bottom_clouds_sprite_b_->render();
|
|
|
|
// Dibuja el segundo conjunto de nubes, las de delante
|
|
bottom_clouds_texture_->setAlpha(alpha_);
|
|
bottom_clouds_sprite_a_->setSpriteClip(bottom_clouds_rect_[gradient_number_]);
|
|
bottom_clouds_sprite_b_->setSpriteClip(bottom_clouds_rect_[gradient_number_]);
|
|
bottom_clouds_sprite_a_->render();
|
|
bottom_clouds_sprite_b_->render();
|
|
}
|
|
|
|
// Compone todos los elementos del fondo en la textura
|
|
void Background::fillCanvas()
|
|
{
|
|
// Cambia el destino del renderizador
|
|
auto temp = SDL_GetRenderTarget(renderer_);
|
|
SDL_SetRenderTarget(renderer_, canvas_);
|
|
|
|
// Dibuja el gradiente de fondo
|
|
renderGradient();
|
|
|
|
// Dibuja las nubes de arriba
|
|
renderTopClouds();
|
|
|
|
// Dibuja las nubes de abajo
|
|
renderBottomClouds();
|
|
|
|
// Dibuja los edificios
|
|
buildings_sprite_->render();
|
|
|
|
// Dibuja la hierba
|
|
grass_sprite_->render();
|
|
|
|
// Deja el renderizador apuntando donde estaba
|
|
SDL_SetRenderTarget(renderer_, temp);
|
|
}
|
|
|
|
// Dibuja el objeto
|
|
void Background::render()
|
|
{
|
|
// Fondo
|
|
SDL_RenderCopy(renderer_, canvas_, &src_rect_, &dst_rect_);
|
|
|
|
// Atenuación
|
|
SDL_RenderCopy(renderer_, color_texture_, &src_rect_, &dst_rect_);
|
|
}
|
|
|
|
// Vuelve a cargar las texturas
|
|
void Background::reloadTextures()
|
|
{
|
|
buildings_texture_->reLoad();
|
|
top_clouds_texture_->reLoad();
|
|
bottom_clouds_texture_->reLoad();
|
|
grass_texture_->reLoad();
|
|
gradients_texture_->reLoad();
|
|
}
|
|
|
|
// Ajusta el valor de la variable
|
|
void Background::setCloudsSpeed(float value)
|
|
{
|
|
clouds_speed_ = value;
|
|
}
|
|
|
|
// Ajusta el valor de la variable
|
|
void Background::setGradientNumber(int value)
|
|
{
|
|
gradient_number_ = value % 4;
|
|
}
|
|
|
|
// Ajusta el valor de la variable
|
|
void Background::setTransition(float value)
|
|
{
|
|
transition_ = std::clamp(value, 0.0f, 1.0f);
|
|
}
|
|
|
|
// Establece la posición del objeto
|
|
void Background::setPos(SDL_Rect pos)
|
|
{
|
|
dst_rect_ = pos;
|
|
|
|
// Si cambian las medidas del destino, hay que cambiar las del origen para evitar deformar la imagen
|
|
src_rect_.x = 0;
|
|
src_rect_.y = rect_.h - pos.h;
|
|
src_rect_.w = pos.w;
|
|
src_rect_.h = pos.h;
|
|
}
|
|
|
|
// Ajusta el valor de la variable
|
|
void Background::setSrcRect(SDL_Rect value)
|
|
{
|
|
src_rect_ = value;
|
|
}
|
|
|
|
// Ajusta el valor de la variable
|
|
void Background::setDstRect(SDL_Rect value)
|
|
{
|
|
dst_rect_ = value;
|
|
}
|
|
|
|
// Establece el color_ de atenuación
|
|
void Background::setColor(Color color)
|
|
{
|
|
color_ = color;
|
|
|
|
// Colorea la textura
|
|
auto temp = SDL_GetRenderTarget(renderer_);
|
|
SDL_SetRenderTarget(renderer_, color_texture_);
|
|
|
|
SDL_SetRenderDrawColor(renderer_, color_.r, color_.g, color_.b, 255);
|
|
SDL_RenderClear(renderer_);
|
|
|
|
SDL_SetRenderTarget(renderer_, temp);
|
|
}
|
|
|
|
// Establece la transparencia de la atenuación
|
|
void Background::setAlpha(int alpha)
|
|
{
|
|
// Evita que se asignen valores fuera de rango
|
|
alpha_ = std::clamp(alpha, 0, 255);
|
|
|
|
// Guarda el valor actual y establece el nuevo valor
|
|
alpha_color_text_temp_ = alpha_color_text_;
|
|
alpha_color_text_ = alpha_;
|
|
}
|
|
|
|
// Actualiza el valor de alpha_
|
|
void Background::updateAlphaColorText()
|
|
{
|
|
if (alpha_color_text_ == alpha_color_text_temp_)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
alpha_color_text_ > alpha_color_text_temp_ ? ++alpha_color_text_temp_ : --alpha_color_text_temp_;
|
|
SDL_SetTextureAlphaMod(color_texture_, alpha_color_text_temp_);
|
|
}
|
|
}
|
|
|
|
// Actualiza las nubes
|
|
void Background::updateClouds()
|
|
{
|
|
// Aplica la velocidad calculada a las nubes
|
|
top_clouds_sprite_a_->setVelX(clouds_speed_);
|
|
top_clouds_sprite_b_->setVelX(clouds_speed_);
|
|
bottom_clouds_sprite_a_->setVelX(clouds_speed_ / 2);
|
|
bottom_clouds_sprite_b_->setVelX(clouds_speed_ / 2);
|
|
|
|
// Mueve las nubes
|
|
top_clouds_sprite_a_->update();
|
|
top_clouds_sprite_b_->update();
|
|
bottom_clouds_sprite_a_->update();
|
|
bottom_clouds_sprite_b_->update();
|
|
|
|
// Calcula el offset de las nubes
|
|
if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth())
|
|
{
|
|
top_clouds_sprite_a_->setPosX(top_clouds_sprite_a_->getWidth());
|
|
}
|
|
|
|
if (top_clouds_sprite_b_->getPosX() < -top_clouds_sprite_b_->getWidth())
|
|
{
|
|
top_clouds_sprite_b_->setPosX(top_clouds_sprite_b_->getWidth());
|
|
}
|
|
|
|
if (bottom_clouds_sprite_a_->getPosX() < -bottom_clouds_sprite_a_->getWidth())
|
|
{
|
|
bottom_clouds_sprite_a_->setPosX(bottom_clouds_sprite_a_->getWidth());
|
|
}
|
|
|
|
if (bottom_clouds_sprite_b_->getPosX() < -bottom_clouds_sprite_b_->getWidth())
|
|
{
|
|
bottom_clouds_sprite_b_->setPosX(bottom_clouds_sprite_b_->getWidth());
|
|
}
|
|
} |