#include "background.h" #include // for SDL_BLENDMODE_BLEND #include // for SDL_PIXELFORMAT_RGBA8888 #include // for max, min #include // for basic_string #include "asset.h" // for Asset #include "moving_sprite.h" // for MovingSprite #include "param.h" // for param #include "sprite.h" // for Sprite #include "texture.h" // for Texture // Constructor Background::Background(SDL_Renderer *renderer) : renderer(renderer) { // Carga las texturas buildingsTexture = new Texture(renderer, Asset::get()->get("game_buildings.png")); topCloudsTexture = new Texture(renderer, Asset::get()->get("game_clouds1.png")); bottomCloudsTexture = new Texture(renderer, Asset::get()->get("game_clouds2.png")); grassTexture = new Texture(renderer, Asset::get()->get("game_grass.png")); gradientsTexture = new Texture(renderer, Asset::get()->get("game_sky_colors.png")); // Inicializa variables gradientNumber = 0; alpha = 0; cloudsSpeed = 0; transition = 0; counter = 0; rect = {0, 0, gradientsTexture->getWidth() / 2, gradientsTexture->getHeight() / 2}; srcRect = {0, 0, 320, 240}; dstRect = {0, 0, 320, 240}; base = rect.h; color = {param.background.attenuateColor.r, param.background.attenuateColor.g, param.background.attenuateColor.b}; alphaColorText = alphaColorTextTemp = param.background.attenuateAlpha; gradientRect[0] = {0, 0, rect.w, rect.h}; gradientRect[1] = {rect.w, 0, rect.w, rect.h}; gradientRect[2] = {0, rect.h, rect.w, rect.h}; gradientRect[3] = {rect.w, rect.h, rect.w, rect.h}; const int topCloudsTextureHeight = topCloudsTexture->getHeight() / 4; const int bottomCloudsTextureHeight = bottomCloudsTexture->getHeight() / 4; for (int i = 0; i < 4; ++i) { topCloudsRect[i] = {0, i * topCloudsTextureHeight, topCloudsTexture->getWidth(), topCloudsTextureHeight}; bottomCloudsRect[i] = {0, i * bottomCloudsTextureHeight, bottomCloudsTexture->getWidth(), bottomCloudsTextureHeight}; } // Crea los sprites const int topClouds_y = base - 165; const int bottomClouds_y = base - 101; const float topCloudsSpeed = 0.1f; const float bottomCloudsSpeed = 0.05f; topCloudsSprite_A = new MovingSprite(0, topClouds_y, rect.w, topCloudsTexture->getHeight(), -topCloudsSpeed, 0.0f, 0.0f, 0.0f, topCloudsTexture); topCloudsSprite_B = new MovingSprite(rect.w, topClouds_y, rect.w, topCloudsTexture->getHeight(), -topCloudsSpeed, 0.0f, 0.0f, 0.0f, topCloudsTexture); bottomCloudsSprite_A = new MovingSprite(0, bottomClouds_y, rect.w, bottomCloudsTexture->getHeight(), -bottomCloudsSpeed, 0.0f, 0.0f, 0.0f, bottomCloudsTexture); bottomCloudsSprite_B = new MovingSprite(rect.w, bottomClouds_y, rect.w, bottomCloudsTexture->getHeight(), -bottomCloudsSpeed, 0.0f, 0.0f, 0.0f, bottomCloudsTexture); buildingsSprite = new Sprite(0, 0, buildingsTexture->getWidth(), buildingsTexture->getHeight(), buildingsTexture); gradientSprite = new Sprite(0, 0, rect.w, rect.h, gradientsTexture); grassSprite = new Sprite(0, 0, grassTexture->getWidth(), grassTexture->getHeight() / 2, grassTexture); // Inicializa objetos topCloudsSprite_A->setSpriteClip(0, 0, topCloudsTexture->getWidth(), topCloudsTexture->getHeight()); topCloudsSprite_B->setSpriteClip(0, 0, topCloudsTexture->getWidth(), topCloudsTexture->getHeight()); bottomCloudsSprite_A->setSpriteClip(0, 0, bottomCloudsTexture->getWidth(), bottomCloudsTexture->getHeight()); bottomCloudsSprite_B->setSpriteClip(0, 0, bottomCloudsTexture->getWidth(), bottomCloudsTexture->getHeight()); buildingsSprite->setPosY(base - buildingsSprite->getHeight()); grassSprite->setPosY(base - grassSprite->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 colorTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect.w, rect.h); SDL_SetTextureBlendMode(colorTexture, SDL_BLENDMODE_BLEND); setColor(color); SDL_SetTextureAlphaMod(colorTexture, alphaColorText); } // Destructor Background::~Background() { delete buildingsTexture; delete topCloudsTexture; delete bottomCloudsTexture; delete grassTexture; delete gradientsTexture; delete topCloudsSprite_A; delete topCloudsSprite_B; delete bottomCloudsSprite_A; delete bottomCloudsSprite_B; delete buildingsSprite; delete gradientSprite; delete grassSprite; SDL_DestroyTexture(canvas); SDL_DestroyTexture(colorTexture); } // 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 grassSprite->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++; fillCanvas(); } // Dibuja el gradiente de fondo void Background::renderGradient() { // Dibuja el gradiente 2 gradientsTexture->setAlpha(255); gradientSprite->setSpriteClip(gradientRect[(gradientNumber + 1) % 4]); gradientSprite->render(); // Dibuja el gradiente 1 con una opacidad cada vez menor gradientsTexture->setAlpha(alpha); gradientSprite->setSpriteClip(gradientRect[gradientNumber]); gradientSprite->render(); } // Dibuja las nubes de arriba void Background::renderTopClouds() { // Dibuja el primer conjunto de nubes topCloudsTexture->setAlpha(255); topCloudsSprite_A->setSpriteClip(topCloudsRect[(gradientNumber + 1) % 4]); topCloudsSprite_A->render(); topCloudsSprite_B->setSpriteClip(topCloudsRect[(gradientNumber + 1) % 4]); topCloudsSprite_B->render(); // Dibuja el segundo conjunto de nubes topCloudsTexture->setAlpha(alpha); topCloudsSprite_A->setSpriteClip(topCloudsRect[gradientNumber]); topCloudsSprite_A->render(); topCloudsSprite_B->setSpriteClip(topCloudsRect[gradientNumber]); topCloudsSprite_B->render(); } // Dibuja las nubes de abajo void Background::renderBottomClouds() { // Dibuja el primer conjunto de nubes bottomCloudsTexture->setAlpha(255); bottomCloudsSprite_A->setSpriteClip(bottomCloudsRect[(gradientNumber + 1) % 4]); bottomCloudsSprite_A->render(); bottomCloudsSprite_B->setSpriteClip(bottomCloudsRect[(gradientNumber + 1) % 4]); bottomCloudsSprite_B->render(); // Dibuja el segundo conjunto de nubes bottomCloudsTexture->setAlpha(alpha); bottomCloudsSprite_A->setSpriteClip(bottomCloudsRect[gradientNumber]); bottomCloudsSprite_A->render(); bottomCloudsSprite_B->setSpriteClip(bottomCloudsRect[gradientNumber]); bottomCloudsSprite_B->render(); } // Compone todos los elementos del fondo en la textura void Background::fillCanvas() { // Cambia el destino del renderizador SDL_Texture *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 buildingsSprite->render(); // Dibuja la hierba grassSprite->render(); // Deja el renderizador apuntando donde estaba SDL_SetRenderTarget(renderer, temp); } // Dibuja el objeto void Background::render() { // Fondo SDL_RenderCopy(renderer, canvas, &srcRect, &dstRect); // Atenuación SDL_RenderCopy(renderer, colorTexture, &srcRect, &dstRect); } // Vuelve a cargar las texturas void Background::reloadTextures() { buildingsTexture->reLoad(); topCloudsTexture->reLoad(); bottomCloudsTexture->reLoad(); grassTexture->reLoad(); gradientsTexture->reLoad(); } // Ajusta el valor de la variable void Background::setCloudsSpeed(float value) { cloudsSpeed = value; } // Ajusta el valor de la variable void Background::setGradientNumber(int value) { gradientNumber = value % 4; } // Ajusta el valor de la variable void Background::setTransition(float value) { value = std::min(value, 1.0f); value = std::max(value, 0.0f); transition = value; } // Establece la posición del objeto void Background::setPos(SDL_Rect pos) { this->dstRect = pos; // Si cambian las medidas del destino, hay que cambiar las del origen para evitar deformar la imagen this->srcRect.x = 0; this->srcRect.y = rect.h - pos.h; this->srcRect.w = pos.w; this->srcRect.h = pos.h; } // Ajusta el valor de la variable void Background::setSrcRect(SDL_Rect value) { srcRect = value; } // Ajusta el valor de la variable void Background::setDstRect(SDL_Rect value) { dstRect = value; } // Establece el color de atenuación void Background::setColor(color_t color) { this->color = color; // Colorea la textura SDL_Texture *temp = SDL_GetRenderTarget(renderer); SDL_SetRenderTarget(renderer, colorTexture); 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::min(alpha, 255); alpha = std::max(alpha, 0); // Guarda el valor actual alphaColorTextTemp = alphaColorText; // Establece el nuevo valor alphaColorText = alpha; } // Actualiza el valor de alpha void Background::updateAlphaColorText() { if (alphaColorText == alphaColorTextTemp) { return; } else { alphaColorText > alphaColorTextTemp ? alphaColorTextTemp++ : alphaColorTextTemp--; SDL_SetTextureAlphaMod(colorTexture, alphaColorTextTemp); } } // Actualiza las nubes void Background::updateClouds() { // Aplica la velocidad calculada a las nubes topCloudsSprite_A->setVelX(cloudsSpeed); topCloudsSprite_B->setVelX(cloudsSpeed); bottomCloudsSprite_A->setVelX(cloudsSpeed / 2); bottomCloudsSprite_B->setVelX(cloudsSpeed / 2); // Mueve las nubes topCloudsSprite_A->move(); topCloudsSprite_B->move(); bottomCloudsSprite_A->move(); bottomCloudsSprite_B->move(); // Calcula el offset de las nubes if (topCloudsSprite_A->getPosX() < -topCloudsSprite_A->getWidth()) { topCloudsSprite_A->setPosX(topCloudsSprite_A->getWidth()); } if (topCloudsSprite_B->getPosX() < -topCloudsSprite_B->getWidth()) { topCloudsSprite_B->setPosX(topCloudsSprite_B->getWidth()); } if (bottomCloudsSprite_A->getPosX() < -bottomCloudsSprite_A->getWidth()) { bottomCloudsSprite_A->setPosX(bottomCloudsSprite_A->getWidth()); } if (bottomCloudsSprite_B->getPosX() < -bottomCloudsSprite_B->getWidth()) { bottomCloudsSprite_B->setPosX(bottomCloudsSprite_B->getWidth()); } }