Files
aee-arcade/source/game/entities/player.hpp
T

98 lines
3.8 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.
#pragma once
#include <SDL3/SDL.h>
#include <string>
#include <utility>
#include "core/rendering/sprite/animated_sprite.hpp"
class EventBus;
class Player : public AnimatedSprite {
public:
// Mapeig de tecles per al moviment del jugador. Cada jugador local en pot
// tenir unes diferents; així podem afegir-ne més sense tocar el codi del
// Player, només instanciant amb Controls distints.
struct Controls {
SDL_Scancode up;
SDL_Scancode down;
SDL_Scancode left;
SDL_Scancode right;
};
// Geometria carregada des de `data/player/player.yaml`. `sprite_*` són
// la mida del frame (sprite 12×24 amb perspectiva falsa: visualment, els
// 12 píxels superiors són el cap i els 12 inferiors la base).
// La caixa de col·lisió és un quadrat `collision_size` concèntric amb el
// quadrat inferior del sprite (`base_size`). Els offsets els calculem
// al load a partir d'aquests tres valors; el mapa de col·lisions i el
// de dibuix són independents (el sprite pot sobresortir sense afectar).
inline static int sprite_w = 0;
inline static int sprite_h = 0;
inline static int base_size = 0;
inline static int collision_size = 0;
inline static int collision_padding = 0;
inline static int collision_x_offset = 0;
inline static int collision_y_offset = 0;
// Ha de cridar-se abans d'instanciar Player; GameScene ho fa al ctor.
static void loadFrom(const std::string& yaml_path);
Player(const std::string& anim_key, float x, float y, const Controls& controls);
void update(float delta_time) override;
// Y de la base del jugador (cara inferior de la caixa de colisió). Usada
// per al Z-order contra els sarcs: peus per sobre d'un sarc → darrere;
// per sota → davant.
[[nodiscard]] auto getFeetY() const -> float {
return getPosY() + static_cast<float>(collision_y_offset + collision_size);
}
// Injecta el bus del nivell. El Player publica `on_tile_entered` cada
// vegada que el centre de la seua caixa de col·lisió entra en una
// cel·la nova del tilemap. Si el bus no s'injecta, no emet res.
void setEventBus(EventBus* bus) { bus_ = bus; }
// Tile actual del jugador (centre de `baseBox()` convertit a
// coordenades de tile del tilemap, usant Map::tile_size i
// Map::tilemap_origin_*). Retorna (col, row).
[[nodiscard]] auto getCurrentTile() const -> std::pair<int, int>;
private:
// Rectangle de col·lisió del jugador, usat pel mapa de colisions i com
// a referència per al Z-order.
[[nodiscard]] auto baseBox() const -> SDL_FRect;
// Clamp de la caixa de col·lisió al playfield (no al sprite sencer:
// el cap pot sobresortir pel mur superior sense afectar el joc).
void clampToPlayfield();
// Snap cap al passadís perpendicular a la direcció premuda. Si la caixa
// de col·lisió està a ≤ collision_size/2 d'una lane, s'hi aproxima
// gradualment (a velocitat de moviment). Permet canviar de direcció
// sense haver d'alinear-se píxel-perfect en l'encreuament. Els dos
// wrappers deleguen a `snapToLane` només canviant l'eix actiu.
void snapToHorizontalLane(float delta_time);
void snapToVerticalLane(float delta_time);
void snapToLane(
float delta_time,
float base,
float pitch,
int max_idx,
float (Player::*get_pos)() const,
void (Player::*set_pos)(float));
Controls controls_;
// Bus del nivell (opcional). Propietat externa (EntityManager); el
// Player només en guarda un punter per publicar events.
EventBus* bus_{nullptr};
// Últim tile publicat. Inicialitzats a un sentinel fora de rang perquè
// el primer frame en què el bus estigui connectat ja emeti un event.
int last_tile_col_{-9999};
int last_tile_row_{-9999};
};