Refet el spritesheet del jugador i el fitxer d'animacions

Afegits nous estats per al jugador: RECOIL
This commit is contained in:
2025-07-11 22:03:44 +02:00
parent 8f1511998c
commit 7ac46876ca
7 changed files with 194 additions and 90 deletions

View File

@@ -16,78 +16,106 @@ frames=4,5,6,7
[/animation]
[animation]
name=walk-sideshoot
name=walk-fire-side
speed=5
loop=0
frames=8,9,10,11
[/animation]
[animation]
name=walk-sideshoot-cooldown
name=walk-recoil-side
speed=5
loop=0
frames=12,13,14,15
[/animation]
[animation]
name=stand-sideshoot
name=walk-cool-side
speed=5
loop=0
frames=16,17,18,19
[/animation]
[animation]
name=stand-sideshoot-cooldown
name=stand-fire-side
speed=5
loop=0
frames=15
frames=20
[/animation]
[animation]
name=walk-centershoot
name=stand-recoil-side
speed=5
loop=0
frames=20,21,22,23
frames=21
[/animation]
[animation]
name=walk-centershoot-cooldown
name=stand-cool-side
speed=5
loop=0
frames=24,25,26,27
frames=22
[/animation]
[animation]
name=stand-centershoot
name=walk-fire-center
speed=5
loop=0
frames=28,29,30,31
frames=23,24,25,26
[/animation]
[animation]
name=stand-centershoot-cooldown
name=walk-recoil-center
speed=5
loop=0
frames=27
frames=27,28,29,30
[/animation]
[animation]
name=dying
name=walk-cool-center
speed=5
loop=0
frames=31,32,33,34
[/animation]
[animation]
name=stand-fire-center
speed=5
loop=0
frames=35
[/animation]
[animation]
name=stand-recoil-center
speed=5
loop=0
frames=36
[/animation]
[animation]
name=stand-cool-center
speed=5
loop=0
frames=37
[/animation]
[animation]
name=rolling
speed=10
loop=0
frames=32,33,34,35
[/animation]
[animation]
name=dead
speed=3
loop=0
frames=44,45,46,47,48,49,50
frames=38,39,40,41
[/animation]
[animation]
name=celebration
speed=10
loop=-1
frames=36,36,36,36,36,36,37,38,39,40,40,40,40,40,40,39,39,39,40,40,40,39,39,39,38,37,36,36,36
frames=42,42,42,42,42,42,43,44,45,46,46,46,46,46,46,45,45,45,46,46,46,45,45,45,44,43,42,42,42
[/animation]
[animation]
name=dead
speed=5
loop=0
frames=47,48,49,50,51,52,53
[/animation]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -65,7 +65,7 @@ public:
// Configuración de juego
void setPlayArea(SDL_FRect play_area) { play_area_ = play_area; }; // Define el área de juego
void setCreationTimeEnabled(bool value) { creation_time_enabled_ = value; }; // Activa o desactiva el tiempo de creación de globos
void setDeployBalloons(bool value) { can_deploy_balloons_ = value; }; // Activa o desactiva la generación de globos
void enableBalloonDeployment(bool value) { can_deploy_balloons_ = value; }; // Activa o desactiva la generación de globos
// Obtención de información
int getMenace(); // Obtiene el nivel de amenaza generado por los globos

View File

@@ -49,7 +49,7 @@ Director::Director(int argc, const char *argv[])
Section::name = Section::Name::GAME;
Section::options = Section::Options::GAME_PLAY_1P;
#elif DEBUG
Section::name = Section::Name::LOGO;
Section::name = Section::Name::GAME;
Section::options = Section::Options::GAME_PLAY_1P;
#else // NORMAL GAME
Section::name = Section::Name::LOGO;

View File

@@ -60,7 +60,7 @@ void Player::init()
vel_y_ = 0;
score_ = 0;
score_multiplier_ = 1.0f;
cool_down_ = 10;
cant_fire_counter_ = 10;
enter_name_->init(last_enter_name_);
// Establece la posición del sprite
@@ -358,41 +358,49 @@ void Player::setAnimation()
case PlayerState::CREDITS:
{
// Crea cadenas de texto para componer el nombre de la animación
const std::string WALKING_ANIMATION = walking_state_ == PlayerState::WALKING_STOP ? "stand" : "walk";
const std::string FIRING_ANIMATION = firing_state_ == PlayerState::FIRING_UP ? "centershoot" : "sideshoot";
const std::string COOLING_ANIMATION = firing_state_ == PlayerState::COOLING_UP ? "centershoot" : "sideshoot";
const std::string WALK_ANIMATION = walking_state_ == PlayerState::WALKING_STOP ? "stand" : "walk";
const std::string FIRE_ANIMATION = firing_state_ == PlayerState::FIRING_UP ? "-fire-center" : "-fire-side";
const std::string RECOIL_ANIMATION = firing_state_ == PlayerState::RECOILING_UP ? "-recoil-center" : "-recoil-side";
const std::string COOL_ANIMATION = firing_state_ == PlayerState::COOLING_UP ? "-cool-center" : "-cool-side";
const SDL_FlipMode FLIP_WALK = walking_state_ == PlayerState::WALKING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
const SDL_FlipMode FLIP_FIRE = firing_state_ == PlayerState::FIRING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
const SDL_FlipMode FLIP_COOLING = firing_state_ == PlayerState::COOLING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
const SDL_FlipMode FLIP_RECOIL = firing_state_ == PlayerState::RECOILING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
const SDL_FlipMode FLIP_COOL = firing_state_ == PlayerState::COOLING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
// Establece la animación a partir de las cadenas
if (firing_state_ == PlayerState::FIRING_NONE)
{
// No esta disparando
player_sprite_->setCurrentAnimation(WALKING_ANIMATION);
player_sprite_->setCurrentAnimation(WALK_ANIMATION);
player_sprite_->setFlip(FLIP_WALK);
}
else if (isRecoiling())
{
// Retroceso
player_sprite_->setCurrentAnimation(WALK_ANIMATION + RECOIL_ANIMATION);
player_sprite_->setFlip(FLIP_RECOIL);
}
else if (isCooling())
{
// Acaba de disparar
player_sprite_->setCurrentAnimation(WALKING_ANIMATION + "-" + COOLING_ANIMATION + "-cooldown");
player_sprite_->setFlip(FLIP_COOLING);
player_sprite_->setCurrentAnimation(WALK_ANIMATION + COOL_ANIMATION);
player_sprite_->setFlip(FLIP_COOL);
}
else
{
// Está disparando
player_sprite_->setCurrentAnimation(WALKING_ANIMATION + "-" + FIRING_ANIMATION);
player_sprite_->setCurrentAnimation(WALK_ANIMATION + FIRE_ANIMATION);
// Si dispara de lado, invierte el sprite segun hacia donde dispara
// Si dispara recto, invierte el sprite segun hacia donde camina
player_sprite_->setFlip(FIRING_ANIMATION == "centershoot" ? FLIP_WALK : FLIP_FIRE);
player_sprite_->setFlip(FIRE_ANIMATION == "-fire-center" ? FLIP_WALK : FLIP_FIRE);
}
break;
}
case PlayerState::DYING:
case PlayerState::CONTINUE_TIME_OUT:
{
player_sprite_->setCurrentAnimation("dying");
player_sprite_->setCurrentAnimation("rolling");
break;
}
case PlayerState::LYING_ON_THE_FLOOR_FOREVER:
@@ -419,38 +427,64 @@ void Player::setAnimation()
// Actualiza el valor de la variable
void Player::updateCooldown()
{
if (cool_down_ > 0)
if (playing_state_ == PlayerState::PLAYING)
{
--cool_down_;
cooling_state_counter_ = 50;
}
else
{
if (cooling_state_counter_ > 0)
if (cant_fire_counter_ > 0)
{
if (cooling_state_counter_ == 40)
cooling_state_counter_ = COOLING_DURATION_;
// La mitad del tiempo que no puede disparar tiene el brazo arriba (PlayerState::FIRING)
// y la otra mitad en retroceso (PlayerState::RECOILING)
if (cant_fire_counter_ == recoiling_state_duration_ / 2)
{
switch (firing_state_)
{
case PlayerState::FIRING_LEFT:
setFiringState(PlayerState::COOLING_LEFT);
setFiringState(PlayerState::RECOILING_LEFT);
break;
case PlayerState::FIRING_RIGHT:
setFiringState(PlayerState::COOLING_RIGHT);
setFiringState(PlayerState::RECOILING_RIGHT);
break;
case PlayerState::FIRING_UP:
setFiringState(PlayerState::COOLING_UP);
setFiringState(PlayerState::RECOILING_UP);
break;
default:
break;
}
}
--cooling_state_counter_;
--cant_fire_counter_;
}
else
{
setFiringState(PlayerState::FIRING_NONE);
cooling_state_counter_ = 0;
if (cooling_state_counter_ > COOLING_COMPLETE_)
{
if (cooling_state_counter_ == COOLING_DURATION_)
{
switch (firing_state_)
{
case PlayerState::RECOILING_LEFT:
setFiringState(PlayerState::COOLING_LEFT);
break;
case PlayerState::RECOILING_RIGHT:
setFiringState(PlayerState::COOLING_RIGHT);
break;
case PlayerState::RECOILING_UP:
setFiringState(PlayerState::COOLING_UP);
break;
default:
break;
}
}
--cooling_state_counter_;
}
if (cooling_state_counter_ == COOLING_COMPLETE_)
{
setFiringState(PlayerState::FIRING_NONE);
cooling_state_counter_ = -1;
}
}
}
}
@@ -464,10 +498,10 @@ void Player::update()
updateCooldown();
updatePowerUp();
updateInvulnerable();
updateScoreboard();
updateContinueCounter();
updateEnterNameCounter();
updateShowingName();
updateScoreboard();
}
// Incrementa la puntuación del jugador
@@ -650,19 +684,20 @@ void Player::setInvulnerable(bool value)
// Monitoriza el estado
void Player::updateInvulnerable()
{
if (invulnerable_)
{
if (invulnerable_counter_ > 0)
if (playing_state_ == PlayerState::PLAYING)
if (invulnerable_)
{
--invulnerable_counter_;
invulnerable_counter_ % 8 > 3 ? player_sprite_->getTexture()->setPalette(coffees_) : player_sprite_->getTexture()->setPalette(3);
if (invulnerable_counter_ > 0)
{
--invulnerable_counter_;
invulnerable_counter_ % 8 > 3 ? player_sprite_->getTexture()->setPalette(coffees_) : player_sprite_->getTexture()->setPalette(3);
}
else
{
setInvulnerable(false);
player_sprite_->getTexture()->setPalette(coffees_);
}
}
else
{
setInvulnerable(false);
player_sprite_->getTexture()->setPalette(coffees_);
}
}
}
// Establece el valor de la variable
@@ -675,11 +710,12 @@ void Player::setPowerUp()
// Actualiza el valor de la variable
void Player::updatePowerUp()
{
if (power_up_)
{
--power_up_counter_;
power_up_ = power_up_counter_ > 0;
}
if (playing_state_ == PlayerState::PLAYING)
if (power_up_)
{
--power_up_counter_;
power_up_ = power_up_counter_ > 0;
}
}
// Concede un toque extra al jugador

View File

@@ -28,6 +28,11 @@ enum class PlayerState
FIRING_RIGHT, // Disparando hacia la derecha
FIRING_NONE, // No está disparando
// Estados de retroceso tras disparar
RECOILING_UP, // Retroceso tras disparar hacia arriba
RECOILING_LEFT, // Retroceso tras disparar hacia la izquierda
RECOILING_RIGHT, // Retroceso tras disparar hacia la derecha
// Estados de enfriamiento tras disparar
COOLING_UP, // Enfriando tras disparar hacia arriba
COOLING_LEFT, // Enfriando tras disparar hacia la izquierda
@@ -109,9 +114,10 @@ public:
bool isWaiting() const { return playing_state_ == PlayerState::WAITING; }
// Getters
bool canFire() const { return cool_down_ <= 0; }
bool canFire() const { return cant_fire_counter_ <= 0; }
bool hasExtraHit() const { return extra_hit_; }
bool isCooling() const { return firing_state_ == PlayerState::COOLING_LEFT || firing_state_ == PlayerState::COOLING_UP || firing_state_ == PlayerState::COOLING_RIGHT; }
bool isRecoiling() const { return firing_state_ == PlayerState::RECOILING_LEFT || firing_state_ == PlayerState::RECOILING_UP || firing_state_ == PlayerState::RECOILING_RIGHT; }
bool IsEligibleForHighScore() const { return score_ > Options::settings.hi_score_table.back().score; }
bool isInvulnerable() const { return invulnerable_; }
bool isPowerUp() const { return power_up_; }
@@ -138,7 +144,7 @@ public:
// Setters inline
void setController(int index) { controller_index_ = index; }
void setFireCooldown(int time) { cool_down_ = time; }
void setCantFireCounter(int counter) { recoiling_state_duration_ = cant_fire_counter_ = counter; }
void setFiringState(PlayerState state) { firing_state_ = state; }
void setInvulnerableCounter(int value) { invulnerable_counter_ = value; }
void setName(const std::string &name) { name_ = name; }
@@ -156,6 +162,8 @@ private:
static constexpr int WIDTH_ = 30; // Anchura
static constexpr int HEIGHT_ = 30; // Altura
static constexpr float BASE_SPEED_ = 1.5f; // Velocidad base del jugador
static constexpr int COOLING_DURATION_ = 30;
static constexpr int COOLING_COMPLETE_ = 0;
// --- Objetos y punteros ---
std::unique_ptr<AnimatedSprite> player_sprite_; // Sprite para dibujar el jugador
@@ -171,7 +179,9 @@ private:
int default_pos_y_; // Posición inicial para el jugador
float vel_x_ = 0.0f; // Cantidad de píxeles a desplazarse en el eje X
int vel_y_ = 0.0f; // Cantidad de píxeles a desplazarse en el eje Y
int cool_down_ = 0; // Contador durante el cual no puede disparar
int cant_fire_counter_ = 0; // Contador durante el cual no puede disparar
int recoiling_state_counter_ = 0; // Contador para la animación del estado de retroceso
int recoiling_state_duration_ = 0; // Numero de frames que dura el estado de retroceso
int cooling_state_counter_ = 0; // Contador para la animación del estado cooling
int score_ = 0; // Puntos del jugador
float score_multiplier_ = 1.0f; // Multiplicador de puntos

View File

@@ -1431,37 +1431,65 @@ void Game::handleFireInput(const std::shared_ptr<Player> &player, BulletType bul
{
if (player->canFire())
{
player->setInput(bulletType == BulletType::UP ? InputAction::FIRE_CENTER : bulletType == BulletType::LEFT ? InputAction::FIRE_LEFT
: InputAction::FIRE_RIGHT);
switch (bulletType)
{
case BulletType::UP:
player->setInput(InputAction::FIRE_CENTER);
break;
case BulletType::LEFT:
player->setInput(InputAction::FIRE_LEFT);
break;
case BulletType::RIGHT:
player->setInput(InputAction::FIRE_RIGHT);
break;
default:
break;
}
createBullet(player->getPosX() + (player->getWidth() / 2) - 6, player->getPosY() + (player->getHeight() / 2), bulletType, player->isPowerUp(), player->getId());
playSound("bullet.wav");
// Establece un tiempo de espera para el próximo disparo.
const int cooldown = player->isPowerUp() ? 5 : Options::settings.autofire ? 10
: 7;
player->setFireCooldown(cooldown);
constexpr int POWERUP_COOLDOWN = 5;
constexpr int AUTOFIRE_COOLDOWN = 10;
constexpr int NORMAL_COOLDOWN = 7;
int cant_fire_counter;
if (player->isPowerUp())
{
cant_fire_counter = POWERUP_COOLDOWN;
}
else if (Options::settings.autofire)
{
cant_fire_counter = AUTOFIRE_COOLDOWN;
}
else
{
cant_fire_counter = NORMAL_COOLDOWN;
}
player->setCantFireCounter(cant_fire_counter);
}
}
// Gestiona las entradas de todos los jugadores en el modo normal (fuera del modo demo).
void Game::handlePlayersInput()
{
for (const auto &player : players_)
for (const auto &PLAYER : players_)
{
if (player->isPlaying())
if (PLAYER->isPlaying())
{
// Maneja el input de los jugadores en modo normal.
handleNormalPlayerInput(player);
handleNormalPlayerInput(PLAYER);
}
else if (player->isContinue() || player->isWaiting())
else if (PLAYER->isContinue() || PLAYER->isWaiting())
{
// Gestiona la continuación del jugador.
handlePlayerContinue(player);
handlePlayerContinue(PLAYER);
}
else if (player->isEnteringName() || player->isEnteringNameGameCompleted() || player->isShowingName())
else if (PLAYER->isEnteringName() || PLAYER->isEnteringNameGameCompleted() || PLAYER->isShowingName())
{
// Gestiona la introducción del nombre del jugador.
handleNameInput(player);
handleNameInput(PLAYER);
}
}
}
@@ -1469,17 +1497,17 @@ void Game::handlePlayersInput()
// Maneja las entradas de movimiento y disparo para un jugador en modo normal.
void Game::handleNormalPlayerInput(const std::shared_ptr<Player> &player)
{
const auto &controller = Options::controllers.at(player->getController());
const bool autofire = player->isPowerUp() || Options::settings.autofire;
const auto &CONTROLLER = Options::controllers.at(player->getController());
const bool AUTOFIRE = player->isPowerUp() || Options::settings.autofire;
if (input_->checkInput(InputAction::LEFT, INPUT_ALLOW_REPEAT, controller.type, controller.index))
if (input_->checkInput(InputAction::LEFT, INPUT_ALLOW_REPEAT, CONTROLLER.type, CONTROLLER.index))
{
player->setInput(InputAction::LEFT);
#ifdef RECORDING
demo_.keys.left = 1;
#endif
}
else if (input_->checkInput(InputAction::RIGHT, INPUT_ALLOW_REPEAT, controller.type, controller.index))
else if (input_->checkInput(InputAction::RIGHT, INPUT_ALLOW_REPEAT, CONTROLLER.type, CONTROLLER.index))
{
player->setInput(InputAction::RIGHT);
#ifdef RECORDING
@@ -1494,7 +1522,7 @@ void Game::handleNormalPlayerInput(const std::shared_ptr<Player> &player)
#endif
}
handleFireInputs(player, autofire, player->getController()); // Verifica y maneja todas las posibles entradas de disparo.
handleFireInputs(player, AUTOFIRE, player->getController()); // Verifica y maneja todas las posibles entradas de disparo.
}
// Procesa las entradas de disparo del jugador, permitiendo disparos automáticos si está habilitado.
@@ -1987,9 +2015,11 @@ void Game::checkDebugEvents(const SDL_Event &event)
balloon_manager_->createPowerBall();
break;
}
case SDLK_2: // Crea dos globos gordos
case SDLK_2: // Activa o desactiva la aparición de globos
{
balloon_manager_->createTwoBigBalloons();
static bool deploy_balloons = true;
deploy_balloons = !deploy_balloons;
balloon_manager_->enableBalloonDeployment(deploy_balloons);
break;
}
case SDLK_3: // Activa el modo para pasar el juego automaticamente
@@ -2001,7 +2031,7 @@ void Game::checkDebugEvents(const SDL_Event &event)
balloon_manager_->destroyAllBalloons();
playSound("power_ball_explosion.wav");
}
balloon_manager_->setDeployBalloons(!auto_pop_balloons_);
balloon_manager_->enableBalloonDeployment(!auto_pop_balloons_);
break;
}
case SDLK_4: // Suelta un item