feat: implementar jerarquia d'entitats amb classe base Entitat
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.7.0)
|
project(orni VERSION 0.7.1)
|
||||||
|
|
||||||
# Info del proyecto
|
# Info del proyecto
|
||||||
set(PROJECT_LONG_NAME "Orni Attack")
|
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)
|
// Game rules (lives, respawn, game over)
|
||||||
namespace Game {
|
namespace Game {
|
||||||
constexpr int STARTING_LIVES = 3; // Initial lives
|
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)
|
||||||
|
constexpr float COLLISION_BULLET_ENEMY_AMPLIFIER = 1.15F; // 115% hitbox (generous)
|
||||||
|
|
||||||
// Friendly fire system
|
// Friendly fire system
|
||||||
constexpr bool FRIENDLY_FIRE_ENABLED = true; // Activar friendly fire
|
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 <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "core/audio/audio.hpp"
|
#include "core/audio/audio.hpp"
|
||||||
#include "core/defaults.hpp"
|
#include "core/defaults.hpp"
|
||||||
|
#include "core/entities/entitat.hpp"
|
||||||
#include "core/graphics/shape_loader.hpp"
|
#include "core/graphics/shape_loader.hpp"
|
||||||
#include "core/rendering/shape_renderer.hpp"
|
#include "core/rendering/shape_renderer.hpp"
|
||||||
|
#include "core/types.hpp"
|
||||||
#include "game/constants.hpp"
|
#include "game/constants.hpp"
|
||||||
|
|
||||||
Bala::Bala(SDL_Renderer* renderer)
|
Bala::Bala(SDL_Renderer* renderer)
|
||||||
: renderer_(renderer),
|
: Entitat(renderer),
|
||||||
centre_({.x = 0.0F, .y = 0.0F}),
|
|
||||||
angle_(0.0F),
|
|
||||||
velocitat_(0.0F),
|
velocitat_(0.0F),
|
||||||
esta_(false),
|
esta_(false),
|
||||||
grace_timer_(0.0F),
|
owner_id_(0),
|
||||||
brightness_(Defaults::Brightness::BALA) {
|
grace_timer_(0.0F) {
|
||||||
|
// [NUEVO] Brightness específic per bales
|
||||||
|
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");
|
||||||
|
|
||||||
|
|||||||
@@ -6,43 +6,45 @@
|
|||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "core/graphics/shape.hpp"
|
#include "core/defaults.hpp"
|
||||||
|
#include "core/entities/entitat.hpp"
|
||||||
#include "core/types.hpp"
|
#include "core/types.hpp"
|
||||||
|
|
||||||
class Bala {
|
class Bala : public Entities::Entitat {
|
||||||
public:
|
public:
|
||||||
Bala()
|
Bala()
|
||||||
: renderer_(nullptr) {}
|
: Entitat(nullptr) {}
|
||||||
Bala(SDL_Renderer* renderer);
|
Bala(SDL_Renderer* renderer);
|
||||||
|
|
||||||
void inicialitzar();
|
void inicialitzar() override;
|
||||||
void disparar(const Punt& posicio, float angle, uint8_t owner_id);
|
void disparar(const Punt& posicio, float angle, uint8_t owner_id);
|
||||||
void actualitzar(float delta_time);
|
void actualitzar(float delta_time) override;
|
||||||
void dibuixar() const;
|
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)
|
// Getters (API pública sense canvis)
|
||||||
[[nodiscard]] bool esta_activa() const { return esta_; }
|
[[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]] uint8_t get_owner_id() const { return owner_id_; }
|
||||||
[[nodiscard]] float get_grace_timer() const { return grace_timer_; }
|
[[nodiscard]] float get_grace_timer() const { return grace_timer_; }
|
||||||
void desactivar() { esta_ = false; }
|
void desactivar() { esta_ = false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SDL_Renderer* renderer_;
|
// Membres específics de Bala (heretats: renderer_, forma_, centre_, angle_, brightness_)
|
||||||
|
|
||||||
// [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_;
|
|
||||||
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 grace_timer_; // Grace period timer (0.0 = vulnerable)
|
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);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,24 +10,26 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "core/defaults.hpp"
|
#include "core/defaults.hpp"
|
||||||
|
#include "core/entities/entitat.hpp"
|
||||||
#include "core/graphics/shape_loader.hpp"
|
#include "core/graphics/shape_loader.hpp"
|
||||||
#include "core/rendering/shape_renderer.hpp"
|
#include "core/rendering/shape_renderer.hpp"
|
||||||
|
#include "core/types.hpp"
|
||||||
#include "game/constants.hpp"
|
#include "game/constants.hpp"
|
||||||
|
|
||||||
Enemic::Enemic(SDL_Renderer* renderer)
|
Enemic::Enemic(SDL_Renderer* renderer)
|
||||||
: renderer_(renderer),
|
: Entitat(renderer),
|
||||||
centre_({.x = 0.0F, .y = 0.0F}),
|
|
||||||
angle_(0.0F),
|
|
||||||
velocitat_(0.0F),
|
velocitat_(0.0F),
|
||||||
drotacio_(0.0F),
|
drotacio_(0.0F),
|
||||||
rotacio_(0.0F),
|
rotacio_(0.0F),
|
||||||
esta_(false),
|
esta_(false),
|
||||||
brightness_(Defaults::Brightness::ENEMIC),
|
|
||||||
tipus_(TipusEnemic::PENTAGON),
|
tipus_(TipusEnemic::PENTAGON),
|
||||||
tracking_timer_(0.0F),
|
tracking_timer_(0.0F),
|
||||||
ship_position_(nullptr),
|
ship_position_(nullptr),
|
||||||
tracking_strength_(0.5F), // Default tracking strength
|
tracking_strength_(0.5F), // Default tracking strength
|
||||||
timer_invulnerabilitat_(0.0F) { // Start vulnerable
|
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
|
// [NUEVO] Forma es carrega a inicialitzar() segons el tipus
|
||||||
// Constructor no carrega forma per permetre tipus diferents
|
// Constructor no carrega forma per permetre tipus diferents
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "core/graphics/shape.hpp"
|
#include "core/defaults.hpp"
|
||||||
|
#include "core/entities/entitat.hpp"
|
||||||
#include "core/types.hpp"
|
#include "core/types.hpp"
|
||||||
#include "game/constants.hpp"
|
#include "game/constants.hpp"
|
||||||
|
|
||||||
@@ -36,22 +36,30 @@ struct AnimacioEnemic {
|
|||||||
float drotacio_duracio = 0.0F; // Duration of transition (seconds)
|
float drotacio_duracio = 0.0F; // Duration of transition (seconds)
|
||||||
};
|
};
|
||||||
|
|
||||||
class Enemic {
|
class Enemic : public Entities::Entitat {
|
||||||
public:
|
public:
|
||||||
Enemic()
|
Enemic()
|
||||||
: renderer_(nullptr) {}
|
: Entitat(nullptr) {}
|
||||||
Enemic(SDL_Renderer* renderer);
|
Enemic(SDL_Renderer* renderer);
|
||||||
|
|
||||||
void inicialitzar(TipusEnemic tipus = TipusEnemic::PENTAGON, const Punt* ship_pos = nullptr);
|
void inicialitzar() override { inicialitzar(TipusEnemic::PENTAGON, nullptr); }
|
||||||
void actualitzar(float delta_time);
|
void inicialitzar(TipusEnemic tipus, const Punt* ship_pos = nullptr);
|
||||||
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::ENEMY_RADIUS;
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool es_collidable() const override {
|
||||||
|
return esta_ && timer_invulnerabilitat_ <= 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
// Getters (API pública sense canvis)
|
// 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; }
|
void destruir() { esta_ = false; }
|
||||||
[[nodiscard]] float get_brightness() const { return brightness_; }
|
|
||||||
[[nodiscard]] float get_drotacio() const { return drotacio_; }
|
[[nodiscard]] float get_drotacio() const { return drotacio_; }
|
||||||
[[nodiscard]] Punt get_velocitat_vector() const {
|
[[nodiscard]] Punt get_velocitat_vector() const {
|
||||||
return {
|
return {
|
||||||
@@ -80,19 +88,11 @@ class Enemic {
|
|||||||
[[nodiscard]] float get_temps_invulnerabilitat() const { return timer_invulnerabilitat_; }
|
[[nodiscard]] float get_temps_invulnerabilitat() const { return timer_invulnerabilitat_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SDL_Renderer* renderer_;
|
// Membres específics d'Enemic (heretats: renderer_, forma_, centre_, angle_, brightness_)
|
||||||
|
|
||||||
// [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
|
|
||||||
float velocitat_;
|
float velocitat_;
|
||||||
float drotacio_; // Delta rotació visual (rad/s)
|
float drotacio_; // Delta rotació visual (rad/s)
|
||||||
float rotacio_; // Rotació visual acumulada
|
float rotacio_; // Rotació visual acumulada
|
||||||
bool esta_;
|
bool esta_;
|
||||||
float brightness_; // Factor de brillantor (0.0-1.0)
|
|
||||||
|
|
||||||
// [NEW] Enemy type and configuration
|
// [NEW] Enemy type and configuration
|
||||||
TipusEnemic tipus_;
|
TipusEnemic tipus_;
|
||||||
|
|||||||
@@ -8,22 +8,26 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "core/defaults.hpp"
|
#include "core/defaults.hpp"
|
||||||
|
#include "core/entities/entitat.hpp"
|
||||||
#include "core/graphics/shape_loader.hpp"
|
#include "core/graphics/shape_loader.hpp"
|
||||||
#include "core/input/input.hpp"
|
#include "core/input/input.hpp"
|
||||||
|
#include "core/input/input_types.hpp"
|
||||||
#include "core/rendering/shape_renderer.hpp"
|
#include "core/rendering/shape_renderer.hpp"
|
||||||
|
#include "core/types.hpp"
|
||||||
#include "game/constants.hpp"
|
#include "game/constants.hpp"
|
||||||
|
|
||||||
Nau::Nau(SDL_Renderer* renderer, const char* shape_file)
|
Nau::Nau(SDL_Renderer* renderer, const char* shape_file)
|
||||||
: renderer_(renderer),
|
: Entitat(renderer),
|
||||||
centre_({.x = 0.0F, .y = 0.0F}),
|
|
||||||
angle_(0.0F),
|
|
||||||
velocitat_(0.0F),
|
velocitat_(0.0F),
|
||||||
esta_tocada_(false),
|
esta_tocada_(false),
|
||||||
brightness_(Defaults::Brightness::NAU),
|
|
||||||
invulnerable_timer_(0.0F) {
|
invulnerable_timer_(0.0F) {
|
||||||
|
// [NUEVO] Brightness específic per naus
|
||||||
|
brightness_ = Defaults::Brightness::NAU;
|
||||||
|
|
||||||
// [NUEVO] Carregar forma compartida des de fitxer
|
// [NUEVO] Carregar forma compartida des de fitxer
|
||||||
forma_ = Graphics::ShapeLoader::load(shape_file);
|
forma_ = Graphics::ShapeLoader::load(shape_file);
|
||||||
|
|
||||||
|
|||||||
@@ -7,31 +7,39 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "core/graphics/shape.hpp"
|
#include "core/defaults.hpp"
|
||||||
|
#include "core/entities/entitat.hpp"
|
||||||
#include "core/types.hpp"
|
#include "core/types.hpp"
|
||||||
#include "game/constants.hpp"
|
#include "game/constants.hpp"
|
||||||
|
|
||||||
class Nau {
|
class Nau : public Entities::Entitat {
|
||||||
public:
|
public:
|
||||||
Nau()
|
Nau()
|
||||||
: renderer_(nullptr) {}
|
: Entitat(nullptr) {}
|
||||||
Nau(SDL_Renderer* renderer, const char* shape_file = "ship.shp");
|
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 processar_input(float delta_time, uint8_t player_id);
|
||||||
void actualitzar(float delta_time);
|
void actualitzar(float delta_time) override;
|
||||||
void dibuixar() const;
|
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)
|
// 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_viva() const { return !esta_tocada_; }
|
||||||
[[nodiscard]] bool esta_tocada() const { return esta_tocada_; }
|
[[nodiscard]] bool esta_tocada() const { return esta_tocada_; }
|
||||||
[[nodiscard]] bool es_invulnerable() const { return invulnerable_timer_ > 0.0F; }
|
[[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 {
|
[[nodiscard]] Punt get_velocitat_vector() const {
|
||||||
return {
|
return {
|
||||||
.x = velocitat_ * std::cos(angle_ - (Constants::PI / 2.0F)),
|
.x = velocitat_ * std::cos(angle_ - (Constants::PI / 2.0F)),
|
||||||
@@ -45,18 +53,9 @@ class Nau {
|
|||||||
void marcar_tocada() { esta_tocada_ = true; }
|
void marcar_tocada() { esta_tocada_ = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SDL_Renderer* renderer_;
|
// Membres específics de Nau (heretats: renderer_, forma_, centre_, angle_, brightness_)
|
||||||
|
|
||||||
// [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ó
|
|
||||||
float velocitat_; // Velocitat (px/s)
|
float velocitat_; // Velocitat (px/s)
|
||||||
bool esta_tocada_;
|
bool esta_tocada_;
|
||||||
float brightness_; // Factor de brillantor (0.0-1.0)
|
|
||||||
float invulnerable_timer_; // 0.0f = vulnerable, >0.0f = invulnerable
|
float invulnerable_timer_; // 0.0f = vulnerable, >0.0f = invulnerable
|
||||||
|
|
||||||
void aplicar_fisica(float delta_time);
|
void aplicar_fisica(float delta_time);
|
||||||
|
|||||||
@@ -12,9 +12,11 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "core/audio/audio.hpp"
|
#include "core/audio/audio.hpp"
|
||||||
|
#include "core/entities/entitat.hpp"
|
||||||
#include "core/input/input.hpp"
|
#include "core/input/input.hpp"
|
||||||
#include "core/input/mouse.hpp"
|
#include "core/input/mouse.hpp"
|
||||||
#include "core/math/easing.hpp"
|
#include "core/math/easing.hpp"
|
||||||
|
#include "core/physics/collision.hpp"
|
||||||
#include "core/rendering/line_renderer.hpp"
|
#include "core/rendering/line_renderer.hpp"
|
||||||
#include "core/system/context_escenes.hpp"
|
#include "core/system/context_escenes.hpp"
|
||||||
#include "core/system/global_events.hpp"
|
#include "core/system/global_events.hpp"
|
||||||
@@ -942,40 +944,21 @@ std::string EscenaJoc::construir_marcador() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EscenaJoc::detectar_col·lisions_bales_enemics() {
|
void EscenaJoc::detectar_col·lisions_bales_enemics() {
|
||||||
// Constants amplificades per hitbox més generós (115%)
|
// Amplificador per hitbox més generós (115%)
|
||||||
constexpr float RADI_BALA = Defaults::Entities::BULLET_RADIUS;
|
constexpr float AMPLIFIER = Defaults::Game::COLLISION_BULLET_ENEMY_AMPLIFIER;
|
||||||
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
|
|
||||||
|
|
||||||
// Velocitat d'explosió reduïda per efecte suau
|
// Velocitat d'explosió reduïda per efecte suau
|
||||||
constexpr float VELOCITAT_EXPLOSIO = 80.0F; // px/s (en lloc de 80.0f per defecte)
|
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_) {
|
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_) {
|
for (auto& enemic : orni_) {
|
||||||
if (!enemic.esta_actiu()) {
|
// Comprovar col·lisió utilitzant la interfície genèrica
|
||||||
continue;
|
if (Physics::check_collision(bala, enemic, AMPLIFIER)) {
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
// *** COL·LISIÓ DETECTADA ***
|
// *** COL·LISIÓ DETECTADA ***
|
||||||
|
|
||||||
|
const Punt& pos_enemic = enemic.get_centre();
|
||||||
|
|
||||||
// 1. Calculate score for enemy type
|
// 1. Calculate score for enemy type
|
||||||
int punts = 0;
|
int punts = 0;
|
||||||
switch (enemic.get_tipus()) {
|
switch (enemic.get_tipus()) {
|
||||||
@@ -1025,12 +1008,8 @@ void EscenaJoc::detectar_col·lisions_bales_enemics() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EscenaJoc::detectar_col·lisio_naus_enemics() {
|
void EscenaJoc::detectar_col·lisio_naus_enemics() {
|
||||||
// Generous collision detection (80% hitbox)
|
// Amplificador per hitbox generós (80%)
|
||||||
constexpr float RADI_NAU = Defaults::Entities::SHIP_RADIUS;
|
constexpr float AMPLIFIER = Defaults::Game::COLLISION_SHIP_ENEMY_AMPLIFIER;
|
||||||
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;
|
|
||||||
|
|
||||||
// Check collision for BOTH players
|
// Check collision for BOTH players
|
||||||
for (uint8_t i = 0; i < 2; i++) {
|
for (uint8_t i = 0; i < 2; i++) {
|
||||||
@@ -1045,28 +1024,15 @@ void EscenaJoc::detectar_col·lisio_naus_enemics() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Punt& pos_nau = naus_[i].get_centre();
|
|
||||||
|
|
||||||
// Check collision with all active enemies
|
// Check collision with all active enemies
|
||||||
for (const auto& enemic : orni_) {
|
for (const auto& enemic : orni_) {
|
||||||
if (!enemic.esta_actiu()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip collision if enemy is invulnerable
|
// Skip collision if enemy is invulnerable
|
||||||
if (enemic.es_invulnerable()) {
|
if (enemic.es_invulnerable()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Punt& pos_enemic = enemic.get_centre();
|
// Comprovar col·lisió utilitzant la interfície genèrica
|
||||||
|
if (Physics::check_collision(naus_[i], enemic, AMPLIFIER)) {
|
||||||
// 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) {
|
|
||||||
tocado(i); // Trigger death sequence for player i
|
tocado(i); // Trigger death sequence for player i
|
||||||
break; // Only one collision per player per frame
|
break; // Only one collision per player per frame
|
||||||
}
|
}
|
||||||
@@ -1080,12 +1046,8 @@ void EscenaJoc::detectar_col·lisions_bales_jugadors() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collision constants (exact hitbox, 1.0x amplification)
|
// Amplificador per hitbox exacte (100%)
|
||||||
constexpr float RADI_NAU = Defaults::Entities::SHIP_RADIUS;
|
constexpr float AMPLIFIER = Defaults::Game::COLLISION_BULLET_PLAYER_AMPLIFIER;
|
||||||
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
|
// Check all active bullets
|
||||||
for (auto& bala : bales_) {
|
for (auto& bala : bales_) {
|
||||||
@@ -1098,7 +1060,6 @@ void EscenaJoc::detectar_col·lisions_bales_jugadors() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Punt& pos_bala = bala.get_centre();
|
|
||||||
uint8_t bullet_owner = bala.get_owner_id();
|
uint8_t bullet_owner = bala.get_owner_id();
|
||||||
|
|
||||||
// Check collision with BOTH players
|
// Check collision with BOTH players
|
||||||
@@ -1121,15 +1082,8 @@ void EscenaJoc::detectar_col·lisions_bales_jugadors() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Punt& pos_nau = naus_[player_id].get_centre();
|
// Comprovar col·lisió utilitzant la interfície genèrica
|
||||||
|
if (Physics::check_collision(bala, naus_[player_id], AMPLIFIER)) {
|
||||||
// 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 ***
|
// *** FRIENDLY FIRE HIT ***
|
||||||
|
|
||||||
if (bullet_owner == player_id) {
|
if (bullet_owner == player_id) {
|
||||||
|
|||||||
@@ -5,11 +5,10 @@
|
|||||||
#ifndef ESCENA_JOC_HPP
|
#ifndef ESCENA_JOC_HPP
|
||||||
#define ESCENA_JOC_HPP
|
#define ESCENA_JOC_HPP
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "core/graphics/vector_text.hpp"
|
#include "core/graphics/vector_text.hpp"
|
||||||
#include "core/rendering/sdl_manager.hpp"
|
#include "core/rendering/sdl_manager.hpp"
|
||||||
@@ -22,6 +21,7 @@
|
|||||||
#include "game/entities/bala.hpp"
|
#include "game/entities/bala.hpp"
|
||||||
#include "game/entities/enemic.hpp"
|
#include "game/entities/enemic.hpp"
|
||||||
#include "game/entities/nau.hpp"
|
#include "game/entities/nau.hpp"
|
||||||
|
#include "game/stage_system/stage_config.hpp"
|
||||||
#include "game/stage_system/stage_manager.hpp"
|
#include "game/stage_system/stage_manager.hpp"
|
||||||
|
|
||||||
// Game over state machine
|
// Game over state machine
|
||||||
|
|||||||
Reference in New Issue
Block a user