Files
coffee_crisis_arcade_edition/source/player.cpp

722 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "player.h"
#include <SDL2/SDL_render.h> // for SDL_FLIP_HORIZONTAL, SDL_FLIP_NONE, SDL...
#include <SDL2/SDL_timer.h> // for SDL_GetTicks
#include <stdlib.h> // for rand
#include <algorithm> // for max, min
#include "animated_sprite.h" // for AnimatedSprite
#include "enter_name.h"
#include "input.h" // for inputs_e
#include "param.h" // for param
#include "texture.h" // for Texture
// Constructor
Player::Player(int id, float x, int y, SDL_Rect *playArea, std::vector<Texture *> texture, std::vector<std::vector<std::string> *> animations)
{
// Reserva memoria para los objetos
playerSprite = new AnimatedSprite(texture[0], "", animations[0]);
powerSprite = new AnimatedSprite(texture[1], "", animations[1]);
powerSprite->getTexture()->setAlpha(224);
enterName = new EnterName();
// Rectangulo con la zona de juego
this->playArea = playArea;
// Establece la posición inicial del jugador
defaultPosX = posX = x;
defaultPosY = posY = y;
// Establece los offsets para el sprite de PowerUp
powerUpDespX = (powerSprite->getWidth() - playerSprite->getWidth()) / 2;
powerSprite->setPosY(y - (powerSprite->getHeight() - playerSprite->getHeight()));
// Inicializa variables
this->id = id;
statusPlaying = PLAYER_STATUS_WAITING;
scoreBoardPanel = 0;
name = "";
init();
}
// Destructor
Player::~Player()
{
delete playerSprite;
delete powerSprite;
if (enterName)
{
delete enterName;
}
}
// Iniciador
void Player::init()
{
// Inicializa variables de estado
posX = defaultPosX;
posY = defaultPosY;
statusWalking = PLAYER_STATUS_WALKING_STOP;
statusFiring = PLAYER_STATUS_FIRING_NO;
invulnerable = true;
invulnerableCounter = PLAYER_INVULNERABLE_COUNTER;
powerUp = false;
powerUpCounter = PLAYER_POWERUP_COUNTER;
extraHit = false;
coffees = 0;
input = true;
continueTicks = 0;
continueCounter = 20;
width = 30;
height = 30;
collider.r = 9;
shiftColliders();
velX = 0;
velY = 0;
baseSpeed = 1.5;
score = 0;
scoreMultiplier = 1.0f;
cooldown = 10;
// Establece la posición del sprite
playerSprite->setPosX(posX);
playerSprite->setPosY(posY);
// Selecciona un frame para pintar
playerSprite->setCurrentAnimation("stand");
}
// Actua en consecuencia de la entrada recibida
void Player::setInput(int input)
{
switch (statusPlaying)
{
case PLAYER_STATUS_PLAYING:
setInputPlaying(input);
break;
case PLAYER_STATUS_ENTERING_NAME:
setInputEnteringName(input);
break;
}
}
// Procesa inputs para cuando está jugando
void Player::setInputPlaying(int input)
{
switch (input)
{
case input_left:
velX = -baseSpeed;
setWalkingStatus(PLAYER_STATUS_WALKING_LEFT);
break;
case input_right:
velX = baseSpeed;
setWalkingStatus(PLAYER_STATUS_WALKING_RIGHT);
break;
case input_fire_center:
setFiringStatus(PLAYER_STATUS_FIRING_UP);
break;
case input_fire_left:
setFiringStatus(PLAYER_STATUS_FIRING_LEFT);
break;
case input_fire_right:
setFiringStatus(PLAYER_STATUS_FIRING_RIGHT);
break;
default:
velX = 0;
setWalkingStatus(PLAYER_STATUS_WALKING_STOP);
break;
}
}
// Procesa inputs para cuando está introduciendo el nombre
void Player::setInputEnteringName(int input)
{
switch (input)
{
case input_left:
enterName->decPos();
break;
case input_right:
enterName->incPos();
break;
case input_up:
enterName->incIndex();
break;
case input_down:
enterName->decIndex();
break;
case input_start:
recordName = enterName->getName();
break;
default:
break;
}
setRecordName(enterName->getName());
}
// Mueve el jugador a la posición y animación que le corresponde
void Player::move()
{
if (isPlaying())
{
// Mueve el jugador a derecha o izquierda
posX += velX;
// Si el jugador abandona el area de juego por los laterales
if ((posX < param.game.playArea.rect.x - 5) || (posX + width > playArea->w + 5))
{
// Restaura su posición
posX -= velX;
}
// Actualiza la posición del sprite
playerSprite->setPosX(getPosX());
playerSprite->setPosY(posY);
powerSprite->setPosX(getPosX() - powerUpDespX);
}
else if (isDying())
{
playerSprite->update();
// Si el cadaver abandona el area de juego por los laterales
if ((playerSprite->getPosX() < param.game.playArea.rect.x) || (playerSprite->getPosX() + width > playArea->w))
{
// Restaura su posición
const float vx = playerSprite->getVelX();
playerSprite->setPosX(playerSprite->getPosX() - vx);
// Rebota
playerSprite->setVelX(-vx);
}
// Si el cadaver abandona el area de juego por abajo
if (playerSprite->getPosY() > param.game.playArea.rect.h)
{
setStatusPlaying(PLAYER_STATUS_DIED);
}
}
}
// Pinta el jugador en pantalla
void Player::render()
{
if (powerUp && isPlaying())
{
if (powerUpCounter > (PLAYER_POWERUP_COUNTER / 4) || powerUpCounter % 20 > 4)
{
powerSprite->render();
}
}
playerSprite->render();
}
// Establece el estado del jugador cuando camina
void Player::setWalkingStatus(int status)
{
// Si cambiamos de estado, reiniciamos la animación
if (statusWalking != status)
{
statusWalking = status;
}
}
// Establece el estado del jugador cuando dispara
void Player::setFiringStatus(int status)
{
// Si cambiamos de estado, reiniciamos la animación
if (statusFiring != status)
{
statusFiring = status;
}
}
// Establece la animación correspondiente al estado
void Player::setAnimation()
{
// Crea cadenas de texto para componer el nombre de la animación
const std::string aWalking = statusWalking == PLAYER_STATUS_WALKING_STOP ? "stand" : "walk";
const std::string aFiring = statusFiring == PLAYER_STATUS_FIRING_UP ? "centershoot" : "sideshoot";
const SDL_RendererFlip flipWalk = statusWalking == PLAYER_STATUS_WALKING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
const SDL_RendererFlip flipFire = statusFiring == PLAYER_STATUS_FIRING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
// Establece la animación a partir de las cadenas
if (isPlaying())
{
if (statusFiring == PLAYER_STATUS_FIRING_NO)
{ // No esta disparando
playerSprite->setCurrentAnimation(aWalking);
playerSprite->setFlip(flipWalk);
}
else
{ // Está disparando
playerSprite->setCurrentAnimation(aWalking + "-" + aFiring);
// Si dispara de lado, invierte el sprite segun hacia donde dispara
// Si dispara recto, invierte el sprite segun hacia donde camina
aFiring == "centershoot" ? playerSprite->setFlip(flipWalk) : playerSprite->setFlip(flipFire);
}
}
else
{
playerSprite->setCurrentAnimation("death");
}
// Actualiza las animaciones de los sprites
playerSprite->animate();
// powerSprite->setFlip(flipWalk);
powerSprite->animate();
}
// Obtiene el valor de la variable
int Player::getPosX()
{
return int(posX);
}
// Obtiene el valor de la variable
int Player::getPosY()
{
return posY;
}
// Obtiene el valor de la variable
int Player::getWidth()
{
return width;
}
// Obtiene el valor de la variable
int Player::getHeight()
{
return height;
}
// Indica si el jugador puede disparar
bool Player::canFire()
{
// Si el contador a llegado a cero, podemos disparar. En caso contrario decrementamos el contador
return cooldown > 0 ? false : true;
}
// Establece el valor de la variable
void Player::setFireCooldown(int time)
{
cooldown = time;
}
// Actualiza el valor de la variable
void Player::updateCooldown()
{
if (cooldown > 0)
{
cooldown--;
if (powerUp)
{
cooldown--;
}
}
else
{
setFiringStatus(PLAYER_STATUS_FIRING_NO);
}
}
// Actualiza al jugador a su posicion, animación y controla los contadores
void Player::update()
{
move();
setAnimation();
shiftColliders();
updateCooldown();
updatePowerUpCounter();
updateInvulnerable();
updateContinueCounter();
}
// Obtiene la puntuación del jugador
int Player::getScore()
{
return score;
}
// Asigna un valor a la puntuación del jugador
void Player::setScore(int score)
{
this->score = score;
}
// Incrementa la puntuación del jugador
void Player::addScore(int score)
{
if (isPlaying())
{
this->score += score;
}
}
// Indica si el jugador está jugando
bool Player::isPlaying()
{
return statusPlaying == PLAYER_STATUS_PLAYING;
}
// Indica si el jugador está continuando
bool Player::isContinue()
{
return statusPlaying == PLAYER_STATUS_CONTINUE;
}
// Indica si el jugador está esperando
bool Player::isWaiting()
{
return statusPlaying == PLAYER_STATUS_WAITING;
}
// Indica si el jugador está introduciendo su nombre
bool Player::isEnteringName()
{
return statusPlaying == PLAYER_STATUS_ENTERING_NAME;
}
// Indica si el jugador está muriendose
bool Player::isDying()
{
return statusPlaying == PLAYER_STATUS_DYING;
}
// Indica si el jugador ha terminado de morir
bool Player::hasDied()
{
return statusPlaying == PLAYER_STATUS_DIED;
}
// Establece el estado del jugador en el juego
void Player::setStatusPlaying(int value)
{
statusPlaying = value;
switch (statusPlaying)
{
case PLAYER_STATUS_PLAYING:
statusPlaying = PLAYER_STATUS_PLAYING;
init();
break;
case PLAYER_STATUS_CONTINUE:
// Inicializa el contador de continuar
continueTicks = SDL_GetTicks();
continueCounter = 9;
break;
case PLAYER_STATUS_WAITING:
break;
case PLAYER_STATUS_ENTERING_NAME:
setRecordName("");
break;
case PLAYER_STATUS_DYING:
// Activa la animación de morir
playerSprite->setAccelY(0.2f);
playerSprite->setVelY(-6.6f);
rand() % 2 == 0 ? playerSprite->setVelX(3.3f) : playerSprite->setVelX(-3.3f);
break;
case PLAYER_STATUS_DIED:
break;
default:
break;
}
}
// Obtiene el estado del jugador en el juego
int Player::getStatusPlaying()
{
return statusPlaying;
}
// Obtiene el valor de la variable
float Player::getScoreMultiplier()
{
return scoreMultiplier;
}
// Establece el valor de la variable
void Player::setScoreMultiplier(float value)
{
scoreMultiplier = value;
}
// Aumenta el valor de la variable hasta un máximo
void Player::incScoreMultiplier()
{
scoreMultiplier += 0.1f;
scoreMultiplier = std::min(scoreMultiplier, 5.0f);
}
// Decrementa el valor de la variable hasta un mínimo
void Player::decScoreMultiplier()
{
scoreMultiplier -= 0.1f;
scoreMultiplier = std::max(scoreMultiplier, 1.0f);
}
// Obtiene el valor de la variable
bool Player::isInvulnerable()
{
return invulnerable;
}
// Establece el valor del estado
void Player::setInvulnerable(bool value)
{
invulnerable = value;
invulnerableCounter = invulnerable ? PLAYER_INVULNERABLE_COUNTER : 0;
}
// Obtiene el valor de la variable
int Player::getInvulnerableCounter()
{
return invulnerableCounter;
}
// Establece el valor de la variable
void Player::setInvulnerableCounter(int value)
{
invulnerableCounter = value;
}
// Monitoriza el estado
void Player::updateInvulnerable()
{
if (invulnerable)
{
if (invulnerableCounter > 0)
{
invulnerableCounter--;
invulnerableCounter % 8 > 3 ? playerSprite->getTexture()->setPalette(coffees) : playerSprite->getTexture()->setPalette(3);
}
else
{
setInvulnerable(false);
playerSprite->getTexture()->setPalette(coffees);
}
}
}
// Obtiene el valor de la variable
bool Player::isPowerUp()
{
return powerUp;
}
// Establece el valor de la variable
void Player::setPowerUp()
{
powerUp = true;
powerUpCounter = PLAYER_POWERUP_COUNTER;
}
// Obtiene el valor de la variable
int Player::getPowerUpCounter()
{
return powerUpCounter;
}
// Establece el valor de la variable
void Player::setPowerUpCounter(int value)
{
powerUpCounter = value;
}
// Actualiza el valor de la variable
void Player::updatePowerUpCounter()
{
if ((powerUpCounter > 0) && (powerUp))
{
powerUpCounter--;
}
else
{
powerUp = false;
// powerUpCounter = PLAYER_POWERUP_COUNTER;
}
}
// Obtiene el valor de la variable
bool Player::hasExtraHit()
{
return extraHit;
}
// Concede un toque extra al jugador
void Player::giveExtraHit()
{
extraHit = true;
if (coffees < 2)
{
coffees++;
playerSprite->getTexture()->setPalette(coffees);
}
}
// Quita el toque extra al jugador
void Player::removeExtraHit()
{
if (coffees > 0)
{
coffees--;
setInvulnerable(true);
playerSprite->getTexture()->setPalette(coffees);
}
extraHit = coffees == 0 ? false : true;
}
// Habilita la entrada de ordenes
void Player::enableInput()
{
input = true;
}
// Deshabilita la entrada de ordenes
void Player::disableInput()
{
input = false;
}
// Devuelve el número de cafes actuales
int Player::getCoffees()
{
return coffees;
}
// Obtiene el circulo de colisión
circle_t &Player::getCollider()
{
return collider;
}
// Actualiza el circulo de colisión a la posición del jugador
void Player::shiftColliders()
{
collider.x = int(posX + (width / 2));
collider.y = int(posY + (height / 2));
}
// Pone las texturas del jugador
void Player::setPlayerTextures(std::vector<Texture *> texture)
{
playerSprite->setTexture(texture[0]);
powerSprite->setTexture(texture[1]);
}
// Obtiene el valor de la variable
int Player::getContinueCounter()
{
return continueCounter;
}
// Actualiza el contador de continue
void Player::updateContinueCounter()
{
if (statusPlaying == PLAYER_STATUS_CONTINUE)
{
const Uint32 ticksSpeed = 1000;
if (SDL_GetTicks() - continueTicks > ticksSpeed)
{
decContinueCounter();
}
}
}
// Le asigna un panel en el marcador al jugador
void Player::setScoreBoardPanel(int panel)
{
scoreBoardPanel = panel;
}
// Obtiene el valor de la variable
int Player::getScoreBoardPanel()
{
return scoreBoardPanel;
}
// Decrementa el contador de continuar
void Player::decContinueCounter()
{
continueTicks = SDL_GetTicks();
continueCounter--;
if (continueCounter < 0)
{
setStatusPlaying(PLAYER_STATUS_WAITING);
}
}
// Establece el nombre del jugador
void Player::setName(std::string name)
{
this->name = name;
}
// Establece el nombre del jugador para la tabla de mejores puntuaciones
void Player::setRecordName(std::string recordName)
{
this->recordName = recordName.substr(0, 8);
}
// Obtiene el nombre del jugador
std::string Player::getName()
{
return name;
}
// Obtiene el nombre del jugador para la tabla de mejores puntuaciones
std::string Player::getRecordName()
{
return recordName;
}
// Obtiene la posici´´on que se está editando del nombre del jugador para la tabla de mejores puntuaciones
int Player::getRecordNamePos()
{
if (enterName)
{
return enterName->getPos();
}
return 0;
}
// Establece el mando que usará para ser controlado
void Player::setController(int index)
{
controllerIndex = index;
}
// Obtiene el mando que usa para ser controlado
int Player::getController()
{
return controllerIndex;
}
// Obtiene el "id" del jugador
int Player::getId()
{
return id;
}