afegit friendly fire
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# CMakeLists.txt
|
# CMakeLists.txt
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(orni VERSION 0.6.0)
|
project(orni VERSION 0.7.0)
|
||||||
|
|
||||||
# Info del proyecto
|
# Info del proyecto
|
||||||
set(PROJECT_LONG_NAME "Orni Attack")
|
set(PROJECT_LONG_NAME "Orni Attack")
|
||||||
|
|||||||
@@ -122,6 +122,12 @@ constexpr int STARTING_LIVES = 3; // Initial lives
|
|||||||
constexpr float DEATH_DURATION = 3.0f; // Seconds of death animation
|
constexpr float DEATH_DURATION = 3.0f; // Seconds of death animation
|
||||||
constexpr float GAME_OVER_DURATION = 5.0f; // Seconds to display game over
|
constexpr float GAME_OVER_DURATION = 5.0f; // Seconds to display game over
|
||||||
constexpr float COLLISION_SHIP_ENEMY_AMPLIFIER = 0.80f; // 80% hitbox (generous)
|
constexpr float COLLISION_SHIP_ENEMY_AMPLIFIER = 0.80f; // 80% hitbox (generous)
|
||||||
|
|
||||||
|
// Friendly fire system
|
||||||
|
constexpr bool FRIENDLY_FIRE_ENABLED = true; // Activar friendly fire
|
||||||
|
constexpr float COLLISION_BULLET_PLAYER_AMPLIFIER = 1.0f; // Hitbox exacto (100%)
|
||||||
|
constexpr float BULLET_GRACE_PERIOD = 0.2f; // Inmunidad post-disparo (s)
|
||||||
|
|
||||||
// Transición LEVEL_START (mensajes aleatorios PRE-level)
|
// Transición LEVEL_START (mensajes aleatorios PRE-level)
|
||||||
constexpr float LEVEL_START_DURATION = 3.0f; // Duración total
|
constexpr float LEVEL_START_DURATION = 3.0f; // Duración total
|
||||||
constexpr float LEVEL_START_TYPING_RATIO = 0.3f; // 30% escribiendo, 70% mostrando
|
constexpr float LEVEL_START_TYPING_RATIO = 0.3f; // 30% escribiendo, 70% mostrando
|
||||||
@@ -293,6 +299,7 @@ constexpr bool ENABLED = true; //
|
|||||||
constexpr const char* CONTINUE = "effects/continue.wav"; // Cuenta atras
|
constexpr const char* CONTINUE = "effects/continue.wav"; // Cuenta atras
|
||||||
constexpr const char* EXPLOSION = "effects/explosion.wav"; // Explosión
|
constexpr const char* EXPLOSION = "effects/explosion.wav"; // Explosión
|
||||||
constexpr const char* EXPLOSION2 = "effects/explosion2.wav"; // Explosión alternativa
|
constexpr const char* EXPLOSION2 = "effects/explosion2.wav"; // Explosión alternativa
|
||||||
|
constexpr const char* FRIENDLY_FIRE_HIT = "effects/friendly_fire.wav"; // Friendly fire hit
|
||||||
constexpr const char* INIT_HUD = "effects/init_hud.wav"; // Para la animación del HUD
|
constexpr const char* INIT_HUD = "effects/init_hud.wav"; // Para la animación del HUD
|
||||||
constexpr const char* LASER = "effects/laser_shoot.wav"; // Disparo
|
constexpr const char* LASER = "effects/laser_shoot.wav"; // Disparo
|
||||||
constexpr const char* LOGO = "effects/logo.wav"; // Logo
|
constexpr const char* LOGO = "effects/logo.wav"; // Logo
|
||||||
@@ -513,7 +520,7 @@ namespace FloatingScore {
|
|||||||
constexpr float LIFETIME = 2.0f; // Duració màxima (segons)
|
constexpr float LIFETIME = 2.0f; // Duració màxima (segons)
|
||||||
constexpr float VELOCITY_Y = -30.0f; // Velocitat vertical (px/s, negatiu = amunt)
|
constexpr float VELOCITY_Y = -30.0f; // Velocitat vertical (px/s, negatiu = amunt)
|
||||||
constexpr float VELOCITY_X = 0.0f; // Velocitat horizontal (px/s)
|
constexpr float VELOCITY_X = 0.0f; // Velocitat horizontal (px/s)
|
||||||
constexpr float SCALE = 0.75f; // Escala del text (0.75 = 75% del marcador)
|
constexpr float SCALE = 0.45f; // Escala del text (0.6 = 60% del marcador)
|
||||||
constexpr float SPACING = 0.0f; // Espaiat entre caràcters
|
constexpr float SPACING = 0.0f; // Espaiat entre caràcters
|
||||||
constexpr int MAX_CONCURRENT = 15; // Pool size (= MAX_ORNIS)
|
constexpr int MAX_CONCURRENT = 15; // Pool size (= MAX_ORNIS)
|
||||||
} // namespace FloatingScore
|
} // namespace FloatingScore
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ Bala::Bala(SDL_Renderer* renderer)
|
|||||||
angle_(0.0f),
|
angle_(0.0f),
|
||||||
velocitat_(0.0f),
|
velocitat_(0.0f),
|
||||||
esta_(false),
|
esta_(false),
|
||||||
|
grace_timer_(0.0f),
|
||||||
brightness_(Defaults::Brightness::BALA) {
|
brightness_(Defaults::Brightness::BALA) {
|
||||||
// [NUEVO] Carregar forma compartida des de fitxer
|
// [NUEVO] Carregar forma compartida des de fitxer
|
||||||
forma_ = Graphics::ShapeLoader::load("bullet.shp");
|
forma_ = Graphics::ShapeLoader::load("bullet.shp");
|
||||||
@@ -34,6 +35,7 @@ void Bala::inicialitzar() {
|
|||||||
centre_ = {0.0f, 0.0f};
|
centre_ = {0.0f, 0.0f};
|
||||||
angle_ = 0.0f;
|
angle_ = 0.0f;
|
||||||
velocitat_ = 0.0f;
|
velocitat_ = 0.0f;
|
||||||
|
grace_timer_ = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bala::disparar(const Punt& posicio, float angle, uint8_t owner_id) {
|
void Bala::disparar(const Punt& posicio, float angle, uint8_t owner_id) {
|
||||||
@@ -57,12 +59,23 @@ void Bala::disparar(const Punt& posicio, float angle, uint8_t owner_id) {
|
|||||||
// 7 px/frame × 20 FPS = 140 px/s
|
// 7 px/frame × 20 FPS = 140 px/s
|
||||||
velocitat_ = 140.0f;
|
velocitat_ = 140.0f;
|
||||||
|
|
||||||
|
// Activar grace period (prevents instant self-collision)
|
||||||
|
grace_timer_ = Defaults::Game::BULLET_GRACE_PERIOD;
|
||||||
|
|
||||||
// Reproducir sonido de disparo láser
|
// Reproducir sonido de disparo láser
|
||||||
Audio::get()->playSound(Defaults::Sound::LASER, Audio::Group::GAME);
|
Audio::get()->playSound(Defaults::Sound::LASER, Audio::Group::GAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bala::actualitzar(float delta_time) {
|
void Bala::actualitzar(float delta_time) {
|
||||||
if (esta_) {
|
if (esta_) {
|
||||||
|
// Decrementar grace timer
|
||||||
|
if (grace_timer_ > 0.0f) {
|
||||||
|
grace_timer_ -= delta_time;
|
||||||
|
if (grace_timer_ < 0.0f) {
|
||||||
|
grace_timer_ = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mou(delta_time);
|
mou(delta_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class Bala {
|
|||||||
bool esta_activa() const { return esta_; }
|
bool esta_activa() const { return esta_; }
|
||||||
const Punt& get_centre() const { return centre_; }
|
const Punt& get_centre() const { return centre_; }
|
||||||
uint8_t get_owner_id() const { return owner_id_; }
|
uint8_t get_owner_id() const { return owner_id_; }
|
||||||
|
float get_grace_timer() const { return grace_timer_; }
|
||||||
void desactivar() { esta_ = false; }
|
void desactivar() { esta_ = false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -38,8 +39,9 @@ class Bala {
|
|||||||
float angle_;
|
float angle_;
|
||||||
float velocitat_;
|
float velocitat_;
|
||||||
bool esta_;
|
bool esta_;
|
||||||
uint8_t owner_id_; // 0=P1, 1=P2
|
uint8_t owner_id_; // 0=P1, 1=P2
|
||||||
float brightness_; // Factor de brillantor (0.0-1.0)
|
float grace_timer_; // Grace period timer (0.0 = vulnerable)
|
||||||
|
float brightness_; // Factor de brillantor (0.0-1.0)
|
||||||
|
|
||||||
void mou(float delta_time);
|
void mou(float delta_time);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -476,6 +476,7 @@ void EscenaJoc::actualitzar(float delta_time) {
|
|||||||
|
|
||||||
detectar_col·lisions_bales_enemics();
|
detectar_col·lisions_bales_enemics();
|
||||||
detectar_col·lisio_naus_enemics();
|
detectar_col·lisio_naus_enemics();
|
||||||
|
detectar_col·lisions_bales_jugadors();
|
||||||
debris_manager_.actualitzar(delta_time);
|
debris_manager_.actualitzar(delta_time);
|
||||||
gestor_puntuacio_.actualitzar(delta_time);
|
gestor_puntuacio_.actualitzar(delta_time);
|
||||||
break;
|
break;
|
||||||
@@ -1068,6 +1069,81 @@ void EscenaJoc::detectar_col·lisio_naus_enemics() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EscenaJoc::detectar_col·lisions_bales_jugadors() {
|
||||||
|
// Skip if friendly fire disabled
|
||||||
|
if (!Defaults::Game::FRIENDLY_FIRE_ENABLED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collision constants (exact hitbox, 1.0x amplification)
|
||||||
|
constexpr float RADI_NAU = Defaults::Entities::SHIP_RADIUS;
|
||||||
|
constexpr float RADI_BALA = Defaults::Entities::BULLET_RADIUS;
|
||||||
|
constexpr float SUMA_RADIS = (RADI_NAU + RADI_BALA) *
|
||||||
|
Defaults::Game::COLLISION_BULLET_PLAYER_AMPLIFIER; // 15.0 px
|
||||||
|
constexpr float SUMA_RADIS_QUADRAT = SUMA_RADIS * SUMA_RADIS; // 225.0
|
||||||
|
|
||||||
|
// Check all active bullets
|
||||||
|
for (auto& bala : bales_) {
|
||||||
|
if (!bala.esta_activa()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip bullets in grace period (prevents instant self-collision)
|
||||||
|
if (bala.get_grace_timer() > 0.0f) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Punt& pos_bala = bala.get_centre();
|
||||||
|
uint8_t bullet_owner = bala.get_owner_id();
|
||||||
|
|
||||||
|
// Check collision with BOTH players
|
||||||
|
for (uint8_t player_id = 0; player_id < 2; player_id++) {
|
||||||
|
// Skip if player is dead, invulnerable, or inactive
|
||||||
|
if (itocado_per_jugador_[player_id] > 0.0f) continue;
|
||||||
|
if (!naus_[player_id].esta_viva()) continue;
|
||||||
|
if (naus_[player_id].es_invulnerable()) continue;
|
||||||
|
|
||||||
|
// Skip inactive players
|
||||||
|
bool jugador_actiu = (player_id == 0) ? config_partida_.jugador1_actiu
|
||||||
|
: config_partida_.jugador2_actiu;
|
||||||
|
if (!jugador_actiu) continue;
|
||||||
|
|
||||||
|
const Punt& pos_nau = naus_[player_id].get_centre();
|
||||||
|
|
||||||
|
// Calculate squared distance (avoid sqrt)
|
||||||
|
float dx = pos_bala.x - pos_nau.x;
|
||||||
|
float dy = pos_bala.y - pos_nau.y;
|
||||||
|
float distancia_quadrada = dx * dx + dy * dy;
|
||||||
|
|
||||||
|
// Check collision
|
||||||
|
if (distancia_quadrada <= SUMA_RADIS_QUADRAT) {
|
||||||
|
// *** FRIENDLY FIRE HIT ***
|
||||||
|
|
||||||
|
if (bullet_owner == player_id) {
|
||||||
|
// CASE 1: Self-hit (own bullet)
|
||||||
|
// Player loses 1 life, no gain
|
||||||
|
tocado(player_id);
|
||||||
|
} else {
|
||||||
|
// CASE 2: Teammate hit
|
||||||
|
// Victim loses 1 life
|
||||||
|
tocado(player_id);
|
||||||
|
|
||||||
|
// Attacker gains 1 life (no cap)
|
||||||
|
vides_per_jugador_[bullet_owner]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play distinct sound
|
||||||
|
Audio::get()->playSound(Defaults::Sound::FRIENDLY_FIRE_HIT, Audio::Group::GAME);
|
||||||
|
|
||||||
|
// Deactivate bullet
|
||||||
|
bala.desactivar();
|
||||||
|
|
||||||
|
break; // Bullet only hits once per frame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// [NEW] Stage system helper methods
|
// [NEW] Stage system helper methods
|
||||||
|
|
||||||
void EscenaJoc::dibuixar_missatge_stage(const std::string& missatge) {
|
void EscenaJoc::dibuixar_missatge_stage(const std::string& missatge) {
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ class EscenaJoc {
|
|||||||
void tocado(uint8_t player_id);
|
void tocado(uint8_t player_id);
|
||||||
void detectar_col·lisions_bales_enemics(); // Col·lisions bala-enemic
|
void detectar_col·lisions_bales_enemics(); // Col·lisions bala-enemic
|
||||||
void detectar_col·lisio_naus_enemics(); // Ship-enemy collision detection (plural)
|
void detectar_col·lisio_naus_enemics(); // Ship-enemy collision detection (plural)
|
||||||
|
void detectar_col·lisions_bales_jugadors(); // Bullet-player collision detection (friendly fire)
|
||||||
void dibuixar_marges() const; // Dibuixar vores de la zona de joc
|
void dibuixar_marges() const; // Dibuixar vores de la zona de joc
|
||||||
void dibuixar_marcador(); // Dibuixar marcador de puntuació
|
void dibuixar_marcador(); // Dibuixar marcador de puntuació
|
||||||
void disparar_bala(uint8_t player_id); // Shoot bullet from player
|
void disparar_bala(uint8_t player_id); // Shoot bullet from player
|
||||||
|
|||||||
Reference in New Issue
Block a user