#include "const.h" #include "balloon.h" // Constructor Balloon::Balloon(float x, float y, Uint8 kind, float velx, float speed, Uint16 creationtimer, Texture *texture, std::vector *animation, SDL_Renderer *renderer) { sprite = new AnimatedSprite(texture, renderer, "", animation); disable(); enabled = true; switch (kind) { case BALLOON_1: // Alto y ancho del objeto width = BALLOON_WIDTH_1; height = BALLOON_WIDTH_1; size = BALLOON_SIZE_1; power = 1; // Inicializa los valores de velocidad y gravedad this->velX = velx; velY = 0; maxVelY = 3.0f; gravity = 0.09f; defaultVelY = 2.6f; // Puntos que da el globo al ser destruido score = BALLOON_SCORE_1; // Amenaza que genera el globo menace = 1; break; case BALLOON_2: // Alto y ancho del objeto width = BALLOON_WIDTH_2; height = BALLOON_WIDTH_2; size = BALLOON_SIZE_2; power = 3; // Inicializa los valores de velocidad y gravedad this->velX = velx; velY = 0; maxVelY = 3.0f; gravity = 0.10f; defaultVelY = 3.5f; // Puntos que da el globo al ser destruido score = BALLOON_SCORE_2; // Amenaza que genera el globo menace = 2; break; case BALLOON_3: // Alto y ancho del objeto width = BALLOON_WIDTH_3; height = BALLOON_WIDTH_3; size = BALLOON_SIZE_3; power = 7; // Inicializa los valores de velocidad y gravedad this->velX = velx; velY = 0; maxVelY = 3.0f; gravity = 0.10f; defaultVelY = 4.50f; // Puntos que da el globo al ser destruido score = BALLOON_SCORE_3; // Amenaza que genera el globo menace = 4; break; case BALLOON_4: // Alto y ancho del objeto width = BALLOON_WIDTH_4; height = BALLOON_WIDTH_4; size = BALLOON_SIZE_4; power = 15; // Inicializa los valores de velocidad y gravedad this->velX = velx; velY = 0; maxVelY = 3.0f; gravity = 0.10f; defaultVelY = 4.95f; // Puntos que da el globo al ser destruido score = BALLOON_SCORE_4; // Amenaza que genera el globo menace = 8; break; case HEXAGON_1: // Alto y ancho del objeto width = BALLOON_WIDTH_1; height = BALLOON_WIDTH_1; size = BALLOON_SIZE_1; power = 1; // Inicializa los valores de velocidad y gravedad this->velX = velx; velY = abs(velx) * 2; maxVelY = abs(velx) * 2; gravity = 0.00f; defaultVelY = abs(velx) * 2; // Puntos que da el globo al ser destruido score = BALLOON_SCORE_1; // Amenaza que genera el globo menace = 1; break; case HEXAGON_2: // Alto y ancho del objeto width = BALLOON_WIDTH_2; height = BALLOON_WIDTH_2; size = BALLOON_SIZE_2; power = 3; // Inicializa los valores de velocidad y gravedad this->velX = velx; velY = abs(velx) * 2; maxVelY = abs(velx) * 2; gravity = 0.00f; defaultVelY = abs(velx) * 2; // Puntos que da el globo al ser destruido score = BALLOON_SCORE_2; // Amenaza que genera el globo menace = 2; break; case HEXAGON_3: // Alto y ancho del objeto width = BALLOON_WIDTH_3; height = BALLOON_WIDTH_3; size = BALLOON_SIZE_3; power = 7; // Inicializa los valores de velocidad y gravedad this->velX = velx; velY = abs(velx) * 2; maxVelY = abs(velx) * 2; gravity = 0.00f; defaultVelY = abs(velx) * 2; // Puntos que da el globo al ser destruido score = BALLOON_SCORE_3; // Amenaza que genera el globo menace = 4; break; case HEXAGON_4: // Alto y ancho del objeto width = BALLOON_WIDTH_4; height = BALLOON_WIDTH_4; size = BALLOON_SIZE_4; power = 15; // Inicializa los valores de velocidad y gravedad this->velX = velx; velY = abs(velx) * 2; maxVelY = abs(velx) * 2; gravity = 0.00f; defaultVelY = abs(velx) * 2; // Puntos que da el globo al ser destruido score = BALLOON_SCORE_4; // Amenaza que genera el globo menace = 8; break; case POWER_BALL: // Alto y ancho del objeto width = BALLOON_WIDTH_4; height = BALLOON_WIDTH_4; size = 4; power = 0; // Inicializa los valores de velocidad y gravedad this->velX = velx; velY = 0; maxVelY = 3.0f; gravity = 0.10f; defaultVelY = 4.95f; // Puntos que da el globo al ser destruido score = 0; // Amenaza que genera el globo menace = 0; // Añade rotación al sprite sprite->setRotate(false); sprite->setRotateSpeed(0); if (velX > 0.0f) { sprite->setRotateAmount(2.0); } else { sprite->setRotateAmount(-2.0); } break; default: break; } // Posición inicial posX = x; posY = y; // Valores para el efecto de rebote bouncing.enabled = false; bouncing.counter = 0; bouncing.speed = 2; bouncing.zoomW = 1.0f; bouncing.zoomH = 1.0f; bouncing.despX = 0.0f; bouncing.despY = 0.0f; bouncing.w = {1.10f, 1.05f, 1.00f, 0.95f, 0.90f, 0.95f, 1.00f, 1.02f, 1.05f, 1.02f}; bouncing.h = {0.90f, 0.95f, 1.00f, 1.05f, 1.10f, 1.05f, 1.00f, 0.98f, 0.95f, 0.98f}; // Alto y ancho del sprite sprite->setWidth(width); sprite->setHeight(height); // Posición X,Y del sprite sprite->setPosX((int)posX); sprite->setPosY((int)posY); // Tamaño del circulo de colisión collider.r = width / 2; // Alinea el circulo de colisión con el objeto updateColliders(); // Inicializa variables stopped = true; stoppedCounter = 0; blinking = false; visible = true; invulnerable = true; beingCreated = true; creationCounter = creationtimer; creationCounterIni = creationtimer; popping = false; // Actualiza valores beingCreated = creationCounter == 0 ? false : true; invulnerable = beingCreated == false ? false : true; counter = 0; travelY = 1.0f; this->speed = speed; // Tipo this->kind = kind; } // Destructor Balloon::~Balloon() { delete sprite; } // Centra el globo en la posición X void Balloon::allignTo(int x) { posX = float(x - (width / 2)); if (posX < PLAY_AREA_LEFT) posX = PLAY_AREA_LEFT + 1; else if ((posX + width) > PLAY_AREA_RIGHT) posX = float(PLAY_AREA_RIGHT - width - 1); // Posición X,Y del sprite sprite->setPosX(getPosX()); sprite->setPosY(getPosY()); // Alinea el circulo de colisión con el objeto updateColliders(); } // Pinta el globo en la pantalla void Balloon::render() { if ((visible) && (enabled)) { if (bouncing.enabled) { if (kind != POWER_BALL) { // Aplica desplazamiento para el zoom sprite->setPosX(getPosX() + bouncing.despX); sprite->setPosY(getPosY() + bouncing.despY); sprite->render(); sprite->setPosX(getPosX() - bouncing.despX); sprite->setPosY(getPosY() - bouncing.despY); } } else if (isBeingCreated()) { // Aplica alpha blending sprite->getTexture()->setAlpha(255 - (int)((float)creationCounter * (255.0f / (float)creationCounterIni))); sprite->render(); if (kind == POWER_BALL) { Sprite *sp = new Sprite(sprite->getRect(), sprite->getTexture(), sprite->getRenderer()); sp->setSpriteClip(407, 0, 37, 37); sp->render(); delete sp; } sprite->getTexture()->setAlpha(255); } else { sprite->render(); if (kind == POWER_BALL and !popping) { Sprite *sp = new Sprite(sprite->getRect(), sprite->getTexture(), sprite->getRenderer()); sp->setSpriteClip(407, 0, 37, 37); sp->render(); delete sp; } } } } // Actualiza la posición y estados del globo void Balloon::move() { // Comprueba si se puede mover if (!isStopped()) { // Lo mueve a izquierda o derecha posX += (velX * speed); // Si queda fuera de pantalla, corregimos su posición y cambiamos su sentido if ((posX < PLAY_AREA_LEFT) || (posX + width > PLAY_AREA_RIGHT)) { // Corrige posición posX -= (velX * speed); // Invierte sentido velX = -velX; // Invierte la rotación sprite->switchRotate(); // Activa el efecto de rebote if (kind != POWER_BALL) { bounceStart(); } } // Mueve el globo hacia arriba o hacia abajo posY += (velY * speed); // Si se sale por arriba if (posY < PLAY_AREA_TOP) { // Corrige posY = PLAY_AREA_TOP; // Invierte sentido velY = -velY; // Activa el efecto de rebote if (kind != POWER_BALL) { bounceStart(); } } // Si el globo se sale por la parte inferior if (posY + height > PLAY_AREA_BOTTOM) { // Corrige posY = PLAY_AREA_BOTTOM - height; // Invierte colocando una velocidad por defecto velY = -defaultVelY; // Activa el efecto de rebote if (kind != POWER_BALL) { bounceStart(); } } /* Para aplicar la gravedad, el diseño original la aplicaba en cada iteración del bucle Al añadir el modificador de velocidad se reduce la distancia que recorre el objeto y por tanto recibe mas gravedad. Para solucionarlo se va a aplicar la gravedad cuando se haya recorrido una distancia igual a la velocidad en Y, que era el cálculo inicial */ // Incrementa la variable que calcula la distancia acumulada en Y travelY += speed; // Si la distancia acumulada en Y es igual a la velocidad, se aplica la gravedad if (travelY >= 1.0f) { // Quita el excedente travelY -= 1.0f; // Aplica la gravedad al objeto sin pasarse de una velocidad máxima velY += gravity; std::min(velY, maxVelY); } // Actualiza la posición del sprite sprite->setPosX(getPosX()); sprite->setPosY(getPosY()); } } // Deshabilita el globo y pone a cero todos los valores void Balloon::disable() { beingCreated = false; blinking = false; collider.r = 0; collider.x = 0; collider.y = 0; counter = 0; creationCounter = 0; creationCounterIni = 0; defaultVelY = 0.0f; enabled = false; gravity = 0.0f; height = 0; invulnerable = false; kind = 0; maxVelY = 0.0f; menace = 0; popping = false; posX = 0.0f; posY = 0.0f; power = 0; score = 0; size = 0; speed = 0; stopped = false; stoppedCounter = 0; travelY = 0; velX = 0.0f; velY = 0.0f; visible = false; width = 0; sprite->clear(); } // Explosiona el globo void Balloon::pop() { setPopping(true); sprite->disableRotate(); setStop(true); setStoppedTimer(2000); setInvulnerable(true); menace = 0; } // Actualiza al globo a su posicion, animación y controla los contadores void Balloon::update() { if (enabled) { sprite->MovingSprite::update(); move(); updateAnimation(); updateColliders(); updateState(); updateBounce(); counter++; } } // Actualiza los estados del globo void Balloon::updateState() { // Si está explotando if (isPopping()) { setInvulnerable(true); setStop(true); if (sprite->animationIsCompleted()) { disable(); } } // Si se está creando if (isBeingCreated()) { // Actualiza el valor de las variables setStop(true); setInvulnerable(true); // Todavia tiene tiempo en el contador if (creationCounter > 0) { // Desplaza lentamente el globo hacia abajo y hacia un lado if (creationCounter % 10 == 0) { posY++; posX += velX; // Comprueba no se salga por los laterales if ((posX < PLAY_AREA_LEFT) || (posX > (PLAY_AREA_RIGHT - width))) { // Corrige y cambia el sentido de la velocidad posX -= velX; velX = -velX; } // Actualiza la posición del sprite sprite->setPosX(getPosX()); sprite->setPosY(getPosY()); // Actualiza la posición del circulo de colisión updateColliders(); } creationCounter--; } // El contador ha llegado a cero else { setBeingCreated(false); setStop(false); setVisible(true); setInvulnerable(false); if (kind == POWER_BALL) { sprite->setRotate(true); } } } // Solo comprueba el estado detenido cuando no se está creando else if (isStopped()) { // Si es una powerball deja de rodar if (kind == POWER_BALL) { sprite->setRotate(false); } // Reduce el contador if (stoppedCounter > 0) { stoppedCounter--; } // Quitarles el estado "detenido" si no estan explosionando else if (!isPopping()) { // Si es una powerball vuelve a rodar if (kind == POWER_BALL) { sprite->setRotate(true); } setStop(false); } } } // Establece la animación correspondiente al estado void Balloon::updateAnimation() { std::string creatingAnimation = "blue"; std::string normalAnimation = "orange"; if (kind == POWER_BALL) { creatingAnimation = "powerball"; normalAnimation = "powerball"; } else if (getClass() == HEXAGON_CLASS) { creatingAnimation = "red"; normalAnimation = "green"; } // Establece el frame de animación if (isPopping()) { sprite->setCurrentAnimation("pop"); } else if (isBeingCreated()) { sprite->setCurrentAnimation(creatingAnimation); } else { sprite->setCurrentAnimation(normalAnimation); } sprite->animate(); } // Comprueba si el globo está habilitado bool Balloon::isEnabled() { return enabled; } // Obtiene del valor de la variable float Balloon::getPosX() { return posX; } // Obtiene del valor de la variable float Balloon::getPosY() { return posY; } // Obtiene del valor de la variable float Balloon::getVelY() { return velY; } // Obtiene del valor de la variable int Balloon::getWidth() { return width; } // Obtiene del valor de la variable int Balloon::getHeight() { return height; } // Establece el valor de la variable void Balloon::setVelY(float velY) { this->velY = velY; } // Establece el valor de la variable void Balloon::setSpeed(float speed) { this->speed = speed; } // Obtiene del valor de la variable int Balloon::getKind() { return kind; } // Obtiene del valor de la variable Uint8 Balloon::getSize() { return size; } // Obtiene la clase a la que pertenece el globo Uint8 Balloon::getClass() { if ((kind >= BALLOON_1) && (kind <= BALLOON_4)) { return BALLOON_CLASS; } else if ((kind >= HEXAGON_1) && (kind <= HEXAGON_4)) { return HEXAGON_CLASS; } return BALLOON_CLASS; } // Establece el valor de la variable void Balloon::setStop(bool state) { stopped = state; } // Obtiene del valor de la variable bool Balloon::isStopped() { return stopped; } // Establece el valor de la variable void Balloon::setBlink(bool value) { blinking = value; } // Obtiene del valor de la variable bool Balloon::isBlinking() { return blinking; } // Establece el valor de la variable void Balloon::setVisible(bool value) { visible = value; } // Obtiene del valor de la variable bool Balloon::isVisible() { return visible; } // Establece el valor de la variable void Balloon::setInvulnerable(bool value) { invulnerable = value; } // Obtiene del valor de la variable bool Balloon::isInvulnerable() { return invulnerable; } // Establece el valor de la variable void Balloon::setBeingCreated(bool value) { beingCreated = value; } // Obtiene del valor de la variable bool Balloon::isBeingCreated() { return beingCreated; } // Establece el valor de la variable void Balloon::setPopping(bool value) { popping = value; } // Obtiene del valor de la variable bool Balloon::isPopping() { return popping; } // Establece el valor de la variable void Balloon::setStoppedTimer(Uint16 time) { stoppedCounter = time; } // Obtiene del valor de la variable Uint16 Balloon::getStoppedTimer() { return stoppedCounter; } // Obtiene del valor de la variable Uint16 Balloon::getScore() { return score; } // Obtiene el circulo de colisión circle_t &Balloon::getCollider() { return collider; } // Alinea el circulo de colisión con la posición del objeto globo void Balloon::updateColliders() { collider.x = Uint16(posX + collider.r); collider.y = posY + collider.r; } // Obtiene le valor de la variable Uint8 Balloon::getMenace() { if (isEnabled()) { return menace; } else { return 0; } } // Obtiene le valor de la variable Uint8 Balloon::getPower() { return power; } void Balloon::bounceStart() { bouncing.enabled = true; bouncing.zoomW = 1; bouncing.zoomH = 1; sprite->setZoomW(bouncing.zoomW); sprite->setZoomH(bouncing.zoomH); bouncing.despX = 0; bouncing.despY = 0; } void Balloon::bounceStop() { bouncing.enabled = false; bouncing.counter = 0; bouncing.zoomW = 1.0f; bouncing.zoomH = 1.0f; sprite->setZoomW(bouncing.zoomW); sprite->setZoomH(bouncing.zoomH); bouncing.despX = 0.0f; bouncing.despY = 0.0f; } void Balloon::updateBounce() { if (bouncing.enabled) { bouncing.zoomW = bouncing.w[bouncing.counter / bouncing.speed]; bouncing.zoomH = bouncing.h[bouncing.counter / bouncing.speed]; sprite->setZoomW(bouncing.zoomW); sprite->setZoomH(bouncing.zoomH); bouncing.despX = (sprite->getSpriteClip().w - (sprite->getSpriteClip().w * bouncing.zoomW)); bouncing.despY = (sprite->getSpriteClip().h - (sprite->getSpriteClip().h * bouncing.zoomH)); bouncing.counter++; if ((bouncing.counter / bouncing.speed) > (MAX_BOUNCE - 1)) { bounceStop(); } } }