feat: implementar jerarquia d'entitats amb classe base Entitat
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# CMakeLists.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(orni VERSION 0.7.0)
|
||||
project(orni VERSION 0.7.1)
|
||||
|
||||
# Info del proyecto
|
||||
set(PROJECT_LONG_NAME "Orni Attack")
|
||||
|
||||
@@ -120,10 +120,11 @@ constexpr float BLINK_INVISIBLE_TIME = 0.1F; // Tiempo invisible (segundos)
|
||||
|
||||
// Game rules (lives, respawn, game over)
|
||||
namespace Game {
|
||||
constexpr int STARTING_LIVES = 3; // Initial lives
|
||||
constexpr float DEATH_DURATION = 3.0F; // Seconds of death animation
|
||||
constexpr float GAME_OVER_DURATION = 5.0F; // Seconds to display game over
|
||||
constexpr float COLLISION_SHIP_ENEMY_AMPLIFIER = 0.80F; // 80% hitbox (generous)
|
||||
constexpr int STARTING_LIVES = 3; // Initial lives
|
||||
constexpr float DEATH_DURATION = 3.0F; // Seconds of death animation
|
||||
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_BULLET_ENEMY_AMPLIFIER = 1.15F; // 115% hitbox (generous)
|
||||
|
||||
// Friendly fire system
|
||||
constexpr bool FRIENDLY_FIRE_ENABLED = true; // Activar friendly fire
|
||||
|
||||
49
source/core/entities/entitat.hpp
Normal file
49
source/core/entities/entitat.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
// entitat.hpp - Classe base abstracta per a totes les entitats del joc
|
||||
// © 2025 Orni Attack - Arquitectura d'entitats
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "core/graphics/shape.hpp"
|
||||
#include "core/types.hpp"
|
||||
|
||||
namespace Entities {
|
||||
|
||||
class Entitat {
|
||||
public:
|
||||
virtual ~Entitat() = default;
|
||||
|
||||
// Interfície principal (virtual pur)
|
||||
virtual void inicialitzar() = 0;
|
||||
virtual void actualitzar(float delta_time) = 0;
|
||||
virtual void dibuixar() const = 0;
|
||||
[[nodiscard]] virtual bool esta_actiu() const = 0;
|
||||
|
||||
// Interfície de col·lisió (override opcional)
|
||||
[[nodiscard]] virtual float get_collision_radius() const { return 0.0F; }
|
||||
[[nodiscard]] virtual bool es_collidable() const { return false; }
|
||||
|
||||
// Getters comuns (inline, sense overhead)
|
||||
[[nodiscard]] const Punt& get_centre() const { return centre_; }
|
||||
[[nodiscard]] float get_angle() const { return angle_; }
|
||||
[[nodiscard]] float get_brightness() const { return brightness_; }
|
||||
[[nodiscard]] const std::shared_ptr<Graphics::Shape>& get_forma() const { return forma_; }
|
||||
|
||||
protected:
|
||||
// Estat comú (accés directe, sense overhead)
|
||||
SDL_Renderer* renderer_;
|
||||
std::shared_ptr<Graphics::Shape> forma_;
|
||||
Punt centre_;
|
||||
float angle_{0.0F};
|
||||
float brightness_{1.0F};
|
||||
|
||||
// Constructor protegit (classe abstracta)
|
||||
Entitat(SDL_Renderer* renderer = nullptr)
|
||||
: renderer_(renderer),
|
||||
centre_({.x = 0.0F, .y = 0.0F}) {}
|
||||
};
|
||||
|
||||
} // namespace Entities
|
||||
32
source/core/physics/collision.hpp
Normal file
32
source/core/physics/collision.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// collision.hpp - Utilitats de detecció de col·lisions
|
||||
// © 2025 Orni Attack - Sistema de física
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/entities/entitat.hpp"
|
||||
#include "core/types.hpp"
|
||||
|
||||
namespace Physics {
|
||||
|
||||
// Comprovació genèrica de col·lisió entre dues entitats
|
||||
inline bool check_collision(const Entities::Entitat& a, const Entities::Entitat& b, float amplifier = 1.0F) {
|
||||
// Comprovar si ambdós són col·lisionables
|
||||
if (!a.es_collidable() || !b.es_collidable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calcular radi combinat (amb amplificador per hitbox generós)
|
||||
float suma_radis = (a.get_collision_radius() + b.get_collision_radius()) * amplifier;
|
||||
float suma_radis_sq = suma_radis * suma_radis;
|
||||
|
||||
// Comprovació distància al quadrat (sense sqrt)
|
||||
const Punt& pos_a = a.get_centre();
|
||||
const Punt& pos_b = b.get_centre();
|
||||
float dx = pos_a.x - pos_b.x;
|
||||
float dy = pos_a.y - pos_b.y;
|
||||
float dist_sq = (dx * dx) + (dy * dy);
|
||||
|
||||
return dist_sq <= suma_radis_sq;
|
||||
}
|
||||
|
||||
} // namespace Physics
|
||||
@@ -6,22 +6,26 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
#include "core/audio/audio.hpp"
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/entities/entitat.hpp"
|
||||
#include "core/graphics/shape_loader.hpp"
|
||||
#include "core/rendering/shape_renderer.hpp"
|
||||
#include "core/types.hpp"
|
||||
#include "game/constants.hpp"
|
||||
|
||||
Bala::Bala(SDL_Renderer* renderer)
|
||||
: renderer_(renderer),
|
||||
centre_({.x = 0.0F, .y = 0.0F}),
|
||||
angle_(0.0F),
|
||||
: Entitat(renderer),
|
||||
velocitat_(0.0F),
|
||||
esta_(false),
|
||||
grace_timer_(0.0F),
|
||||
brightness_(Defaults::Brightness::BALA) {
|
||||
owner_id_(0),
|
||||
grace_timer_(0.0F) {
|
||||
// [NUEVO] Brightness específic per bales
|
||||
brightness_ = Defaults::Brightness::BALA;
|
||||
|
||||
// [NUEVO] Carregar forma compartida des de fitxer
|
||||
forma_ = Graphics::ShapeLoader::load("bullet.shp");
|
||||
|
||||
|
||||
@@ -6,43 +6,45 @@
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "core/graphics/shape.hpp"
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/entities/entitat.hpp"
|
||||
#include "core/types.hpp"
|
||||
|
||||
class Bala {
|
||||
class Bala : public Entities::Entitat {
|
||||
public:
|
||||
Bala()
|
||||
: renderer_(nullptr) {}
|
||||
: Entitat(nullptr) {}
|
||||
Bala(SDL_Renderer* renderer);
|
||||
|
||||
void inicialitzar();
|
||||
void inicialitzar() override;
|
||||
void disparar(const Punt& posicio, float angle, uint8_t owner_id);
|
||||
void actualitzar(float delta_time);
|
||||
void dibuixar() const;
|
||||
void actualitzar(float delta_time) override;
|
||||
void dibuixar() const override;
|
||||
|
||||
// Override: Interfície d'Entitat
|
||||
[[nodiscard]] bool esta_actiu() const override { return esta_; }
|
||||
|
||||
// Override: Interfície de col·lisió
|
||||
[[nodiscard]] float get_collision_radius() const override {
|
||||
return Defaults::Entities::BULLET_RADIUS;
|
||||
}
|
||||
[[nodiscard]] bool es_collidable() const override {
|
||||
return esta_ && grace_timer_ <= 0.0F;
|
||||
}
|
||||
|
||||
// Getters (API pública sense canvis)
|
||||
[[nodiscard]] bool esta_activa() const { return esta_; }
|
||||
[[nodiscard]] const Punt& get_centre() const { return centre_; }
|
||||
[[nodiscard]] uint8_t get_owner_id() const { return owner_id_; }
|
||||
[[nodiscard]] float get_grace_timer() const { return grace_timer_; }
|
||||
void desactivar() { esta_ = false; }
|
||||
|
||||
private:
|
||||
SDL_Renderer* renderer_;
|
||||
|
||||
// [NUEVO] Forma vectorial (compartida entre totes les bales)
|
||||
std::shared_ptr<Graphics::Shape> forma_;
|
||||
|
||||
// [NUEVO] Estat de la instància (separat de la geometria)
|
||||
Punt centre_;
|
||||
float angle_;
|
||||
// Membres específics de Bala (heretats: renderer_, forma_, centre_, angle_, brightness_)
|
||||
float velocitat_;
|
||||
bool esta_;
|
||||
uint8_t owner_id_; // 0=P1, 1=P2
|
||||
float grace_timer_; // Grace period timer (0.0 = vulnerable)
|
||||
float brightness_; // Factor de brillantor (0.0-1.0)
|
||||
|
||||
void mou(float delta_time);
|
||||
};
|
||||
|
||||
@@ -10,24 +10,26 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/entities/entitat.hpp"
|
||||
#include "core/graphics/shape_loader.hpp"
|
||||
#include "core/rendering/shape_renderer.hpp"
|
||||
#include "core/types.hpp"
|
||||
#include "game/constants.hpp"
|
||||
|
||||
Enemic::Enemic(SDL_Renderer* renderer)
|
||||
: renderer_(renderer),
|
||||
centre_({.x = 0.0F, .y = 0.0F}),
|
||||
angle_(0.0F),
|
||||
: Entitat(renderer),
|
||||
velocitat_(0.0F),
|
||||
drotacio_(0.0F),
|
||||
rotacio_(0.0F),
|
||||
esta_(false),
|
||||
brightness_(Defaults::Brightness::ENEMIC),
|
||||
tipus_(TipusEnemic::PENTAGON),
|
||||
tracking_timer_(0.0F),
|
||||
ship_position_(nullptr),
|
||||
tracking_strength_(0.5F), // Default tracking strength
|
||||
timer_invulnerabilitat_(0.0F) { // Start vulnerable
|
||||
// [NUEVO] Brightness específic per enemics
|
||||
brightness_ = Defaults::Brightness::ENEMIC;
|
||||
|
||||
// [NUEVO] Forma es carrega a inicialitzar() segons el tipus
|
||||
// Constructor no carrega forma per permetre tipus diferents
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "core/graphics/shape.hpp"
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/entities/entitat.hpp"
|
||||
#include "core/types.hpp"
|
||||
#include "game/constants.hpp"
|
||||
|
||||
@@ -36,22 +36,30 @@ struct AnimacioEnemic {
|
||||
float drotacio_duracio = 0.0F; // Duration of transition (seconds)
|
||||
};
|
||||
|
||||
class Enemic {
|
||||
class Enemic : public Entities::Entitat {
|
||||
public:
|
||||
Enemic()
|
||||
: renderer_(nullptr) {}
|
||||
: Entitat(nullptr) {}
|
||||
Enemic(SDL_Renderer* renderer);
|
||||
|
||||
void inicialitzar(TipusEnemic tipus = TipusEnemic::PENTAGON, const Punt* ship_pos = nullptr);
|
||||
void actualitzar(float delta_time);
|
||||
void dibuixar() const;
|
||||
void inicialitzar() override { inicialitzar(TipusEnemic::PENTAGON, nullptr); }
|
||||
void inicialitzar(TipusEnemic tipus, const Punt* ship_pos = nullptr);
|
||||
void actualitzar(float delta_time) override;
|
||||
void dibuixar() const override;
|
||||
|
||||
// Override: Interfície d'Entitat
|
||||
[[nodiscard]] bool esta_actiu() const override { return esta_; }
|
||||
|
||||
// Override: Interfície de col·lisió
|
||||
[[nodiscard]] float get_collision_radius() const override {
|
||||
return Defaults::Entities::ENEMY_RADIUS;
|
||||
}
|
||||
[[nodiscard]] bool es_collidable() const override {
|
||||
return esta_ && timer_invulnerabilitat_ <= 0.0F;
|
||||
}
|
||||
|
||||
// Getters (API pública sense canvis)
|
||||
[[nodiscard]] bool esta_actiu() const { return esta_; }
|
||||
[[nodiscard]] const Punt& get_centre() const { return centre_; }
|
||||
[[nodiscard]] const std::shared_ptr<Graphics::Shape>& get_forma() const { return forma_; }
|
||||
void destruir() { esta_ = false; }
|
||||
[[nodiscard]] float get_brightness() const { return brightness_; }
|
||||
[[nodiscard]] float get_drotacio() const { return drotacio_; }
|
||||
[[nodiscard]] Punt get_velocitat_vector() const {
|
||||
return {
|
||||
@@ -80,19 +88,11 @@ class Enemic {
|
||||
[[nodiscard]] float get_temps_invulnerabilitat() const { return timer_invulnerabilitat_; }
|
||||
|
||||
private:
|
||||
SDL_Renderer* renderer_;
|
||||
|
||||
// [NUEVO] Forma vectorial (compartida entre tots els enemics)
|
||||
std::shared_ptr<Graphics::Shape> forma_;
|
||||
|
||||
// [NUEVO] Estat de la instància (separat de la geometria)
|
||||
Punt centre_;
|
||||
float angle_; // Angle de moviment
|
||||
// Membres específics d'Enemic (heretats: renderer_, forma_, centre_, angle_, brightness_)
|
||||
float velocitat_;
|
||||
float drotacio_; // Delta rotació visual (rad/s)
|
||||
float rotacio_; // Rotació visual acumulada
|
||||
bool esta_;
|
||||
float brightness_; // Factor de brillantor (0.0-1.0)
|
||||
|
||||
// [NEW] Enemy type and configuration
|
||||
TipusEnemic tipus_;
|
||||
|
||||
@@ -8,22 +8,26 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/entities/entitat.hpp"
|
||||
#include "core/graphics/shape_loader.hpp"
|
||||
#include "core/input/input.hpp"
|
||||
#include "core/input/input_types.hpp"
|
||||
#include "core/rendering/shape_renderer.hpp"
|
||||
#include "core/types.hpp"
|
||||
#include "game/constants.hpp"
|
||||
|
||||
Nau::Nau(SDL_Renderer* renderer, const char* shape_file)
|
||||
: renderer_(renderer),
|
||||
centre_({.x = 0.0F, .y = 0.0F}),
|
||||
angle_(0.0F),
|
||||
: Entitat(renderer),
|
||||
velocitat_(0.0F),
|
||||
esta_tocada_(false),
|
||||
brightness_(Defaults::Brightness::NAU),
|
||||
invulnerable_timer_(0.0F) {
|
||||
// [NUEVO] Brightness específic per naus
|
||||
brightness_ = Defaults::Brightness::NAU;
|
||||
|
||||
// [NUEVO] Carregar forma compartida des de fitxer
|
||||
forma_ = Graphics::ShapeLoader::load(shape_file);
|
||||
|
||||
|
||||
@@ -7,31 +7,39 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "core/graphics/shape.hpp"
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/entities/entitat.hpp"
|
||||
#include "core/types.hpp"
|
||||
#include "game/constants.hpp"
|
||||
|
||||
class Nau {
|
||||
class Nau : public Entities::Entitat {
|
||||
public:
|
||||
Nau()
|
||||
: renderer_(nullptr) {}
|
||||
: Entitat(nullptr) {}
|
||||
Nau(SDL_Renderer* renderer, const char* shape_file = "ship.shp");
|
||||
|
||||
void inicialitzar(const Punt* spawn_point = nullptr, bool activar_invulnerabilitat = false);
|
||||
void inicialitzar() override { inicialitzar(nullptr, false); }
|
||||
void inicialitzar(const Punt* spawn_point, bool activar_invulnerabilitat = false);
|
||||
void processar_input(float delta_time, uint8_t player_id);
|
||||
void actualitzar(float delta_time);
|
||||
void dibuixar() const;
|
||||
void actualitzar(float delta_time) override;
|
||||
void dibuixar() const override;
|
||||
|
||||
// Override: Interfície d'Entitat
|
||||
[[nodiscard]] bool esta_actiu() const override { return !esta_tocada_; }
|
||||
|
||||
// Override: Interfície de col·lisió
|
||||
[[nodiscard]] float get_collision_radius() const override {
|
||||
return Defaults::Entities::SHIP_RADIUS;
|
||||
}
|
||||
[[nodiscard]] bool es_collidable() const override {
|
||||
return !esta_tocada_ && invulnerable_timer_ <= 0.0F;
|
||||
}
|
||||
|
||||
// Getters (API pública sense canvis)
|
||||
[[nodiscard]] const Punt& get_centre() const { return centre_; }
|
||||
[[nodiscard]] float get_angle() const { return angle_; }
|
||||
[[nodiscard]] bool esta_viva() const { return !esta_tocada_; }
|
||||
[[nodiscard]] bool esta_tocada() const { return esta_tocada_; }
|
||||
[[nodiscard]] bool es_invulnerable() const { return invulnerable_timer_ > 0.0F; }
|
||||
[[nodiscard]] const std::shared_ptr<Graphics::Shape>& get_forma() const { return forma_; }
|
||||
[[nodiscard]] float get_brightness() const { return brightness_; }
|
||||
[[nodiscard]] Punt get_velocitat_vector() const {
|
||||
return {
|
||||
.x = velocitat_ * std::cos(angle_ - (Constants::PI / 2.0F)),
|
||||
@@ -45,18 +53,9 @@ class Nau {
|
||||
void marcar_tocada() { esta_tocada_ = true; }
|
||||
|
||||
private:
|
||||
SDL_Renderer* renderer_;
|
||||
|
||||
// [NUEVO] Forma vectorial (compartida, només 1 instància de Nau però preparat
|
||||
// per reutilització)
|
||||
std::shared_ptr<Graphics::Shape> forma_;
|
||||
|
||||
// [NUEVO] Estat de la instància (separat de la geometria)
|
||||
Punt centre_;
|
||||
float angle_; // Angle d'orientació
|
||||
// Membres específics de Nau (heretats: renderer_, forma_, centre_, angle_, brightness_)
|
||||
float velocitat_; // Velocitat (px/s)
|
||||
bool esta_tocada_;
|
||||
float brightness_; // Factor de brillantor (0.0-1.0)
|
||||
float invulnerable_timer_; // 0.0f = vulnerable, >0.0f = invulnerable
|
||||
|
||||
void aplicar_fisica(float delta_time);
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
#include <vector>
|
||||
|
||||
#include "core/audio/audio.hpp"
|
||||
#include "core/entities/entitat.hpp"
|
||||
#include "core/input/input.hpp"
|
||||
#include "core/input/mouse.hpp"
|
||||
#include "core/math/easing.hpp"
|
||||
#include "core/physics/collision.hpp"
|
||||
#include "core/rendering/line_renderer.hpp"
|
||||
#include "core/system/context_escenes.hpp"
|
||||
#include "core/system/global_events.hpp"
|
||||
@@ -942,40 +944,21 @@ std::string EscenaJoc::construir_marcador() const {
|
||||
}
|
||||
|
||||
void EscenaJoc::detectar_col·lisions_bales_enemics() {
|
||||
// Constants amplificades per hitbox més generós (115%)
|
||||
constexpr float RADI_BALA = Defaults::Entities::BULLET_RADIUS;
|
||||
constexpr float RADI_ENEMIC = Defaults::Entities::ENEMY_RADIUS;
|
||||
constexpr float SUMA_RADIS = (RADI_BALA + RADI_ENEMIC) * 1.15F; // 28.75 px
|
||||
constexpr float SUMA_RADIS_QUADRAT = SUMA_RADIS * SUMA_RADIS; // 826.56
|
||||
// Amplificador per hitbox més generós (115%)
|
||||
constexpr float AMPLIFIER = Defaults::Game::COLLISION_BULLET_ENEMY_AMPLIFIER;
|
||||
|
||||
// Velocitat d'explosió reduïda per efecte suau
|
||||
constexpr float VELOCITAT_EXPLOSIO = 80.0F; // px/s (en lloc de 80.0f per defecte)
|
||||
|
||||
// Iterar per totes les bales actives
|
||||
// Iterar per totes les bales i enemics
|
||||
for (auto& bala : bales_) {
|
||||
if (!bala.esta_activa()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Punt& pos_bala = bala.get_centre();
|
||||
|
||||
// Comprovar col·lisió amb tots els enemics actius
|
||||
for (auto& enemic : orni_) {
|
||||
if (!enemic.esta_actiu()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Punt& pos_enemic = enemic.get_centre();
|
||||
|
||||
// Calcular distància quadrada (evita sqrt)
|
||||
float dx = pos_bala.x - pos_enemic.x;
|
||||
float dy = pos_bala.y - pos_enemic.y;
|
||||
float distancia_quadrada = (dx * dx) + (dy * dy);
|
||||
|
||||
// Comprovar col·lisió
|
||||
if (distancia_quadrada <= SUMA_RADIS_QUADRAT) {
|
||||
// Comprovar col·lisió utilitzant la interfície genèrica
|
||||
if (Physics::check_collision(bala, enemic, AMPLIFIER)) {
|
||||
// *** COL·LISIÓ DETECTADA ***
|
||||
|
||||
const Punt& pos_enemic = enemic.get_centre();
|
||||
|
||||
// 1. Calculate score for enemy type
|
||||
int punts = 0;
|
||||
switch (enemic.get_tipus()) {
|
||||
@@ -1025,12 +1008,8 @@ void EscenaJoc::detectar_col·lisions_bales_enemics() {
|
||||
}
|
||||
|
||||
void EscenaJoc::detectar_col·lisio_naus_enemics() {
|
||||
// Generous collision detection (80% hitbox)
|
||||
constexpr float RADI_NAU = Defaults::Entities::SHIP_RADIUS;
|
||||
constexpr float RADI_ENEMIC = Defaults::Entities::ENEMY_RADIUS;
|
||||
constexpr float SUMA_RADIS =
|
||||
(RADI_NAU + RADI_ENEMIC) * Defaults::Game::COLLISION_SHIP_ENEMY_AMPLIFIER;
|
||||
constexpr float SUMA_RADIS_QUADRAT = SUMA_RADIS * SUMA_RADIS;
|
||||
// Amplificador per hitbox generós (80%)
|
||||
constexpr float AMPLIFIER = Defaults::Game::COLLISION_SHIP_ENEMY_AMPLIFIER;
|
||||
|
||||
// Check collision for BOTH players
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
@@ -1045,28 +1024,15 @@ void EscenaJoc::detectar_col·lisio_naus_enemics() {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Punt& pos_nau = naus_[i].get_centre();
|
||||
|
||||
// Check collision with all active enemies
|
||||
for (const auto& enemic : orni_) {
|
||||
if (!enemic.esta_actiu()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip collision if enemy is invulnerable
|
||||
if (enemic.es_invulnerable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Punt& pos_enemic = enemic.get_centre();
|
||||
|
||||
// Calculate squared distance (avoid sqrt)
|
||||
auto dx = static_cast<float>(pos_nau.x - pos_enemic.x);
|
||||
auto dy = static_cast<float>(pos_nau.y - pos_enemic.y);
|
||||
float distancia_quadrada = (dx * dx) + (dy * dy);
|
||||
|
||||
// Check collision
|
||||
if (distancia_quadrada <= SUMA_RADIS_QUADRAT) {
|
||||
// Comprovar col·lisió utilitzant la interfície genèrica
|
||||
if (Physics::check_collision(naus_[i], enemic, AMPLIFIER)) {
|
||||
tocado(i); // Trigger death sequence for player i
|
||||
break; // Only one collision per player per frame
|
||||
}
|
||||
@@ -1080,12 +1046,8 @@ void EscenaJoc::detectar_col·lisions_bales_jugadors() {
|
||||
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
|
||||
// Amplificador per hitbox exacte (100%)
|
||||
constexpr float AMPLIFIER = Defaults::Game::COLLISION_BULLET_PLAYER_AMPLIFIER;
|
||||
|
||||
// Check all active bullets
|
||||
for (auto& bala : bales_) {
|
||||
@@ -1098,7 +1060,6 @@ void EscenaJoc::detectar_col·lisions_bales_jugadors() {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Punt& pos_bala = bala.get_centre();
|
||||
uint8_t bullet_owner = bala.get_owner_id();
|
||||
|
||||
// Check collision with BOTH players
|
||||
@@ -1121,15 +1082,8 @@ void EscenaJoc::detectar_col·lisions_bales_jugadors() {
|
||||
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) {
|
||||
// Comprovar col·lisió utilitzant la interfície genèrica
|
||||
if (Physics::check_collision(bala, naus_[player_id], AMPLIFIER)) {
|
||||
// *** FRIENDLY FIRE HIT ***
|
||||
|
||||
if (bullet_owner == player_id) {
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
#ifndef ESCENA_JOC_HPP
|
||||
#define ESCENA_JOC_HPP
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "core/graphics/vector_text.hpp"
|
||||
#include "core/rendering/sdl_manager.hpp"
|
||||
@@ -22,6 +21,7 @@
|
||||
#include "game/entities/bala.hpp"
|
||||
#include "game/entities/enemic.hpp"
|
||||
#include "game/entities/nau.hpp"
|
||||
#include "game/stage_system/stage_config.hpp"
|
||||
#include "game/stage_system/stage_manager.hpp"
|
||||
|
||||
// Game over state machine
|
||||
|
||||
Reference in New Issue
Block a user