Files
coffee_crisis/source/balloon.cpp

864 lines
16 KiB
C++

#include "const.h"
#include "balloon.h"
// Constructor
Balloon::Balloon(float x, float y, Uint8 kind, float velx, float speed, Uint16 creationtimer, LTexture *texture, std::vector<std::string> *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(370, 148, 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(370, 148, 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.at(bouncing.counter / bouncing.speed);
bouncing.zoomH = bouncing.h.at(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();
}
}
}