#pragma once #include #include "core/rendering/sprite/animated_sprite.hpp" 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; }; // Sprite 12×24 amb perspectiva falsa: visualment, els 12 píxels // superiors són el cap i els 12 inferiors la base. static constexpr int SPRITE_WIDTH = 12; static constexpr int SPRITE_HEIGHT = 24; // Caixa de col·lisió: quadrat 16×16 concèntric amb els 12×12 inferiors // del sprite (la base "antiga"). Encaixa just als passadissos de 16 px // → el jugador va ajustat pels corredors. L'ampliació és simètrica: // 2 px per cada costat i 2 px per dalt i per baix. Mapa de colisions i // de dibuix són independents: el sprite pot sobresortir (el cap) sense // afectar les col·lisions. static constexpr int LEGACY_BASE_SIZE = 12; static constexpr int COLLISION_SIZE = 16; static constexpr int COLLISION_PADDING = (COLLISION_SIZE - LEGACY_BASE_SIZE) / 2; static constexpr int COLLISION_X_OFFSET = -COLLISION_PADDING; static constexpr int COLLISION_Y_OFFSET = (SPRITE_HEIGHT - LEGACY_BASE_SIZE) - COLLISION_PADDING; Player(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(COLLISION_Y_OFFSET + COLLISION_SIZE); } private: // Rectangle de col·lisió del jugador (16×16), usat pel mapa de colisions // i com a referència per al Z-order. [[nodiscard]] auto baseBox() const -> SDL_FRect; // 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). Això permet canviar de direcció // sense haver d'alinear-se píxel-perfect en l'encreuament. void snapToHorizontalLane(float delta_time); void snapToVerticalLane(float delta_time); Controls controls_; };