81 lines
3.5 KiB
C++
81 lines
3.5 KiB
C++
#pragma once
|
||
|
||
#include <cstdint>
|
||
#include <vector>
|
||
|
||
#include "external/fkyaml_node.hpp"
|
||
#include "game/entities/animation_component.hpp"
|
||
#include "game/entities/hazard.hpp"
|
||
|
||
// Mòmia: perill dinàmic que deambula pels passadís. A cada intersecció
|
||
// tria una direcció vàlida; l'algoritme per triar-la és un hook virtual
|
||
// (`chooseDirection`) que la base implementa com a aleatori uniforme
|
||
// sobre les direccions admissibles. Futurs derivats poden sesgar cap al
|
||
// jugador sense tocar la lògica de moviment.
|
||
//
|
||
// Andamiatge: el concepte d'"intersecció" i la validació de direcció
|
||
// requereixen conèixer el mapa. De moment l'exposem com un conjunt de
|
||
// direccions admissibles que l'EntityManager injecta; la implementació
|
||
// real arribarà quan cablegem l'entitat al game loop.
|
||
class Mummy : public DynamicHazard {
|
||
public:
|
||
enum class Direction : std::uint8_t { NONE,
|
||
UP,
|
||
DOWN,
|
||
LEFT,
|
||
RIGHT };
|
||
|
||
explicit Mummy(const fkyaml::node& yaml);
|
||
|
||
// Hook d'IA. Donat un conjunt de direccions admissibles, decideix la
|
||
// següent direcció a prendre. La implementació de la base tria una
|
||
// aleatoria; si `allowed` està buit, retorna `NONE`.
|
||
virtual auto chooseDirection(const std::vector<Direction>& allowed) -> Direction;
|
||
|
||
// Política de moviment "corridor_wanderer": camina recte fins que el
|
||
// pròxim tram la bloquejaria (mur del playfield o sarc). Quan troba un
|
||
// obstacle, recull les direccions perpendiculars vàlides (evitant
|
||
// U-turn llevat que no hi hagi alternativa) i crida `chooseDirection`
|
||
// per decidir-ne una. No consumeix moviment el frame de gir.
|
||
void step(float delta_time) override;
|
||
|
||
// Contacte amb el jugador: publica `player_hit` amb el dany.
|
||
void onPlayerContact(Player* player) override;
|
||
|
||
private:
|
||
// Caixa de col·lisió candidata si l'entitat es desplaçara (dx, dy).
|
||
[[nodiscard]] auto candidateBox(float dx, float dy) const -> SDL_FRect;
|
||
|
||
// Amarra la caja a la vora exacta del playfield quan el candidat hi
|
||
// sortiria — sense això, amb la caja 16×16 iguala el corredor, la
|
||
// posició subpíxel dins de l'última cel·la impediria girar a cap
|
||
// perpendicular (col·lisionaria amb el sarc adjacent). Es crida abans
|
||
// de la lògica de gir.
|
||
void snapToPlayfieldEdge(float dx, float dy);
|
||
|
||
// Recull les direccions alternatives viables des de la posició actual:
|
||
// `perpendiculars` (girs) i `uturn` (inversa). La direcció actual s'exclou
|
||
// perquè ja sabem que està bloquejada. Cada candidata es valida amb
|
||
// `Map::insidePlayfield` + `Map::collides` sobre la caja resultant.
|
||
struct DirectionPools {
|
||
std::vector<Direction> perp;
|
||
std::vector<Direction> uturn;
|
||
};
|
||
[[nodiscard]] auto collectDirectionPools(float step) const -> DirectionPools;
|
||
|
||
// Canvi de direcció + aplicació de l'animació i flip corresponents.
|
||
// Tots els camins que trien nova direcció (ctor amb `initial_direction`,
|
||
// gir després d'un bloqueig) passen per ací per mantenir anim_ i
|
||
// flip_ en sincronia amb (dir_x_, dir_y_).
|
||
void changeDirection(float dx, float dy);
|
||
|
||
// Aplica la direcció triada (wrapper del switch en una sola crida).
|
||
void applyChoice(Direction dir);
|
||
|
||
// Animacions carregades del YAML, una per cada facing. Per a horitzontal
|
||
// només en cal una (`walk`) i el flip ja diferencia esquerra/dreta.
|
||
AnimationComponent anim_walk_down_;
|
||
AnimationComponent anim_walk_up_;
|
||
AnimationComponent anim_walk_lateral_;
|
||
};
|