afegides regles per reescriure la clase Player
This commit is contained in:
1529
PLAYER_MECHANICS.md
Normal file
1529
PLAYER_MECHANICS.md
Normal file
File diff suppressed because it is too large
Load Diff
49
PLAYER_RULES.md
Normal file
49
PLAYER_RULES.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Reglas para la clase Player
|
||||
|
||||
## Estados
|
||||
|
||||
El jugador tiene tres estados diferenciados:
|
||||
- STANDING
|
||||
- JUMPING
|
||||
- FALLING
|
||||
|
||||
## Puntos de colision
|
||||
|
||||
El jugador tiene un rectabgulo que lo delimita. Se obtiene con getRect()
|
||||
Tiene ademas dos puntos en un vector de puntos llamado feet_ con el punto inferior izquierdo y el inferior derecho
|
||||
Tiene otros dos puntos llamados under_feet_ que son los puntos inmediatamente inferiores a los puntos en feet_. Se usan para saber SOBRE qué tipo de superficie esta el jugador o si bajo solo tiene aire
|
||||
Tiene otros 8 puntos (el jugador ocupa dos tiles en vertical del mapa, los tiles son de 8 pixeles) que son las 4 esquinas de los dos rectangulos de 8px que formarian al jugador. Se usa para comprobar si el jugador está tocando algun tile de los que matan
|
||||
|
||||
## Comprobar colisiones con el mapa
|
||||
Esto es un poco marciano pero, el jugador genera un rectangulo de proyeccion. Digamos que si se va a mover 3 pixeles hacia la derecha, el rectangulo de proyeccion es el rectangulo que cubre la superficie entre donde está el jugador y donde estará el jugador. Se usa para ver si ese rectangulo (que suele ser de ancho o alto 1, ya que el jugador no llega a moverse mas de un pixel cada vez) colisiona con alguna superficie del mapa. En caso de colision se devuelve el punto de colision y se recoloca al jugador en ese punto. Eso para las superficies rectas.
|
||||
|
||||
## Reglas
|
||||
A continuacion las reglas que se han de cumplir para el jugador en todo momento
|
||||
- Si está STANDING -> vy_ = 0;
|
||||
- Si no tiene suelo debajo y no está JUMPING -> FALLING
|
||||
- Si está JUMPING y tropieza contra el techo -> FALLING
|
||||
- Si está FALLING -> vx_ = 0
|
||||
- Si está STANDING y tropieza lateralmente con una Slope, se pega a la slope
|
||||
- Si esta FALLING y tiene una Slope bajo los pies, se pega a la slope
|
||||
- La unica forma de atravesar una Slope es en estado JUMPING y con vx_ != 0
|
||||
- Si salta, se guarda la posicion inicial en Y, si durante el salto está mas bajo de Y (es decir, el valor de y pasa a ser superior al inicial) -> FALLING
|
||||
|
||||
## Tipos de superficies
|
||||
Hay tres tipos de superficies:
|
||||
- Suelo normal
|
||||
- Suelo tipo conveyor belt
|
||||
- Rampas
|
||||
|
||||
## Reglas explicadas de manera mas abierta
|
||||
Debido a que las reglas anteriores pueden sonar confusas y ser incompletas, se describen aqui con lenguaje mas natural:
|
||||
- El jugador camina sobre las superficies
|
||||
- Si tiene los dos pies sobre el aire -> cae
|
||||
- El jugador sube y baja por las rampas
|
||||
- La unica forma de atravesar las rampas es saltando sobre ellas en movimiento
|
||||
- Un salto recto o una caida (las caidas siempre son rectas) hacen aterrizar al jugador sobre las rampas
|
||||
- Las conveyor belt desplazan al jugador en la direccion de la conveyor belt
|
||||
- El jugador cuando esta siendo desplazado por una conveyor belt, no puede cambiar de direccion
|
||||
- Solo puede saltar y la propia inercia le hace saltar en movimiento
|
||||
- Hay una excepcion en las conveyor belts y es que cuando el jugador cae sobre ellas, puede mantener la direccion que tenia el jugador. En el momento que el jugador deja de estar pulsando una direccion, ya se acopla al movimiento de la conveyor belt y no puede cambiar de direccion
|
||||
- El jugador deja de estar ligado al movimiento de la conveyor belt cuando sus dos pies ya no la tienen debajo, bien porque hay suelo o bien porque hay aire -> cae
|
||||
- El jugador no puede cambiar de direccion en el aire
|
||||
@@ -35,61 +35,42 @@ void Player::render() {
|
||||
// Actualiza las variables del objeto
|
||||
void Player::update(float delta_time) {
|
||||
if (!is_paused_) {
|
||||
checkInput(); // Comprueba las entradas y establece las velocidades y el flip
|
||||
move(delta_time); // Recalcula la posición del jugador
|
||||
animate(delta_time); // Establece la animación del jugador
|
||||
updateState(delta_time); // Comprueba el estado del jugador
|
||||
checkBorders(); // Comprueba si está situado en alguno de los cuatro bordes de la habitación
|
||||
checkJumpEnd(); // Comprueba si ha finalizado el salto al alcanzar la altura de inicio
|
||||
checkKillingTiles(); // Comprueba que el jugador no toque ningun tile de los que matan}
|
||||
// 1. Procesamiento de entrada: captura las intenciones del jugador
|
||||
checkInput();
|
||||
|
||||
// 2. Física: aplica gravedad y actualiza velocidades
|
||||
applyGravity(delta_time);
|
||||
updateVelocity();
|
||||
|
||||
// 3. Movimiento: ejecuta movimiento, actualiza estado durante movimiento, resuelve colisiones
|
||||
move(delta_time);
|
||||
|
||||
// 4. Finalización: animación, comprobaciones y efectos
|
||||
animate(delta_time);
|
||||
checkBorders();
|
||||
checkJumpEnd();
|
||||
checkKillingTiles();
|
||||
setColor();
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas y establece las velocidades y el flip
|
||||
// Comprueba las entradas y establece las banderas de intención
|
||||
void Player::checkInput() {
|
||||
// Solo comprueba las entradas de dirección cuando está sobre una superficie
|
||||
if (state_ != State::STANDING) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!auto_movement_) {
|
||||
// Comprueba las entradas de desplazamiento lateral solo en el caso de no estar enganchado a una superficie automatica
|
||||
if (Input::get()->checkInput(InputAction::LEFT)) {
|
||||
vx_ = -HORIZONTAL_VELOCITY;
|
||||
sprite_->setFlip(SDL_FLIP_HORIZONTAL);
|
||||
left_or_right_is_pressed_ = true;
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::RIGHT)) {
|
||||
vx_ = HORIZONTAL_VELOCITY;
|
||||
sprite_->setFlip(SDL_FLIP_NONE);
|
||||
left_or_right_is_pressed_ = true;
|
||||
}
|
||||
|
||||
else {
|
||||
// No se pulsa ninguna dirección
|
||||
vx_ = 0.0F;
|
||||
left_or_right_is_pressed_ = false;
|
||||
}
|
||||
} else {
|
||||
// El movimiento lo proporciona la superficie
|
||||
vx_ = HORIZONTAL_VELOCITY * room_->getAutoSurfaceDirection();
|
||||
sprite_->setFlip(vx_ > 0.0F ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL);
|
||||
// Resetea las banderas de intención
|
||||
want_to_jump_ = false;
|
||||
want_to_move_left_ = false;
|
||||
want_to_move_right_ = false;
|
||||
|
||||
// Captura las intenciones de movimiento
|
||||
if (Input::get()->checkInput(InputAction::LEFT)) {
|
||||
want_to_move_left_ = true;
|
||||
} else if (Input::get()->checkInput(InputAction::RIGHT)) {
|
||||
want_to_move_right_ = true;
|
||||
}
|
||||
|
||||
// Captura la intención de salto
|
||||
if (Input::get()->checkInput(InputAction::JUMP)) {
|
||||
/*
|
||||
Solo puede saltar si ademas de estar (State::STANDING)
|
||||
Esta sobre el suelo, rampa o suelo que se mueve
|
||||
Esto es para evitar el salto desde el vacio al cambiar de pantalla verticalmente
|
||||
Ya que se coloca el estado State::STANDING al cambiar de pantalla
|
||||
*/
|
||||
|
||||
if (isOnFloor() || isOnAutoSurface()) {
|
||||
setState(State::JUMPING);
|
||||
}
|
||||
want_to_jump_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,38 +101,120 @@ void Player::checkBorders() {
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba el estado del jugador
|
||||
// Actualiza el estado del jugador basado en física e intenciones
|
||||
void Player::updateState(float delta_time) {
|
||||
// Actualiza las variables en función del estado
|
||||
// Guarda el estado anterior para detectar transiciones
|
||||
previous_state_ = state_;
|
||||
|
||||
// Máquina de estados: determina transiciones basándose en PLAYER_RULES.md
|
||||
switch (state_) {
|
||||
case State::STANDING: {
|
||||
// Calcula la distancia de caída en pixels (velocidad * tiempo)
|
||||
const int FALLING_DISTANCE = static_cast<int>(y_) - last_grounded_position_;
|
||||
if (previous_state_ == State::FALLING && FALLING_DISTANCE > MAX_FALLING_HEIGHT) {
|
||||
// Si cae de muy alto, el jugador muere
|
||||
is_alive_ = false;
|
||||
// Comprueba muerte por caída desde altura
|
||||
if (previous_state_ == State::FALLING) {
|
||||
const int FALLING_DISTANCE = static_cast<int>(y_) - last_grounded_position_;
|
||||
if (FALLING_DISTANCE > MAX_FALLING_HEIGHT) {
|
||||
is_alive_ = false;
|
||||
}
|
||||
}
|
||||
vy_ = 0.0F;
|
||||
jumping_time_ = 0.0F;
|
||||
|
||||
// Actualiza la posición de tierra
|
||||
last_grounded_position_ = static_cast<int>(y_);
|
||||
auto_movement_ = !isOnFloor() && isOnAutoSurface();
|
||||
if (!isOnFloor() && !isOnAutoSurface() && !isOnDownSlope()) {
|
||||
jumping_time_ = 0.0F;
|
||||
|
||||
// Regla: Si no tiene suelo debajo y no está JUMPING -> FALLING
|
||||
if (shouldFall()) {
|
||||
setState(State::FALLING);
|
||||
return;
|
||||
}
|
||||
|
||||
// Regla: Puede saltar si está sobre suelo o superficie automática
|
||||
if (want_to_jump_ && canJump()) {
|
||||
setState(State::JUMPING);
|
||||
return;
|
||||
}
|
||||
|
||||
// Nota: auto_movement_ se gestiona en updateVelocity() basado en el input
|
||||
break;
|
||||
}
|
||||
|
||||
case State::JUMPING: {
|
||||
// Actualiza el tiempo de salto
|
||||
jumping_time_ += delta_time;
|
||||
playJumpSound();
|
||||
|
||||
// Regla: Si durante el salto Y > jump_init_pos -> FALLING
|
||||
if (static_cast<int>(y_) >= jump_init_pos_ && vy_ > 0.0F) {
|
||||
setState(State::FALLING);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case State::FALLING: {
|
||||
vx_ = 0.0F;
|
||||
vy_ = MAX_VY;
|
||||
// Reproduce sonido de caída
|
||||
playFallSound();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si el jugador puede saltar
|
||||
auto Player::canJump() -> bool {
|
||||
// Solo puede saltar si está STANDING y sobre suelo o superficie automática
|
||||
return state_ == State::STANDING && (isOnFloor() || isOnAutoSurface());
|
||||
}
|
||||
|
||||
// Comprueba si el jugador debe caer
|
||||
auto Player::shouldFall() -> bool {
|
||||
// Cae si no tiene suelo, no está en superficie automática, y no está en rampa descendente
|
||||
return !isOnFloor() && !isOnAutoSurface() && !isOnDownSlope();
|
||||
}
|
||||
|
||||
// Actualiza velocidad basada en estado e intenciones
|
||||
void Player::updateVelocity() {
|
||||
switch (state_) {
|
||||
case State::STANDING: {
|
||||
// Regla: Si está STANDING -> vy_ = 0
|
||||
vy_ = 0.0F;
|
||||
|
||||
if (!auto_movement_) {
|
||||
// Movimiento normal: el jugador controla la dirección
|
||||
if (want_to_move_left_) {
|
||||
vx_ = -HORIZONTAL_VELOCITY;
|
||||
sprite_->setFlip(SDL_FLIP_HORIZONTAL);
|
||||
} else if (want_to_move_right_) {
|
||||
vx_ = HORIZONTAL_VELOCITY;
|
||||
sprite_->setFlip(SDL_FLIP_NONE);
|
||||
} else {
|
||||
// No se pulsa ninguna dirección
|
||||
vx_ = 0.0F;
|
||||
// Regla conveyor belt: cuando el jugador deja de pulsar, se acopla al movimiento
|
||||
if (isOnAutoSurface()) {
|
||||
auto_movement_ = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Movimiento automático: conveyor belt controla la dirección
|
||||
// Regla conveyor belt: el jugador no puede cambiar de dirección
|
||||
vx_ = HORIZONTAL_VELOCITY * room_->getAutoSurfaceDirection();
|
||||
sprite_->setFlip(vx_ > 0.0F ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case State::JUMPING: {
|
||||
last_grounded_position_ = static_cast<int>(y_);
|
||||
jumping_time_ += delta_time;
|
||||
playJumpSound();
|
||||
// Durante el salto, mantiene la velocidad horizontal
|
||||
// La velocidad vertical la controla applyGravity()
|
||||
break;
|
||||
}
|
||||
|
||||
case State::FALLING: {
|
||||
// Regla: Si está FALLING -> vx_ = 0 (no puede cambiar dirección en el aire)
|
||||
vx_ = 0.0F;
|
||||
// La velocidad vertical es MAX_VY (ya configurada por setState)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -199,88 +262,78 @@ void Player::applyGravity(float delta_time) {
|
||||
}
|
||||
}
|
||||
|
||||
// Maneja el movimiento horizontal hacia la izquierda
|
||||
void Player::moveHorizontalLeft(float delta_time) {
|
||||
// Crea el rectangulo de proyección en el eje X para ver si colisiona
|
||||
const float DISPLACEMENT = vx_ * delta_time;
|
||||
SDL_FRect proj = {
|
||||
.x = x_ + DISPLACEMENT,
|
||||
.y = y_,
|
||||
.w = std::ceil(std::fabs(DISPLACEMENT)), // Para evitar que tenga un ancho de 0 pixels
|
||||
.h = HEIGHT};
|
||||
|
||||
// Comprueba la colisión con las superficies
|
||||
const int POS = room_->checkRightSurfaces(&proj);
|
||||
|
||||
// Calcula la nueva posición
|
||||
if (POS == -1) {
|
||||
// Si no hay colisión
|
||||
x_ += DISPLACEMENT;
|
||||
} else {
|
||||
// Si hay colisión lo mueve hasta donde no colisiona
|
||||
x_ = POS + 1;
|
||||
std::cout << "LEFT\n";
|
||||
// Maneja el movimiento sobre rampas
|
||||
// direction: -1 para izquierda, 1 para derecha
|
||||
void Player::handleSlopeMovement(int direction) {
|
||||
// No procesa rampas durante el salto (permite atravesarlas cuando salta con movimiento horizontal)
|
||||
// Pero SÍ procesa en STANDING y FALLING (para pegarse a las rampas)
|
||||
if (state_ == State::JUMPING) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Si ha tocado alguna rampa mientras camina (sin saltar)
|
||||
if (state_ == State::STANDING) {
|
||||
// Si está bajando la rampa, recoloca al jugador
|
||||
if (isOnDownSlope() && state_ == State::STANDING) {
|
||||
y_ += 1;
|
||||
std::cout << "RAMP DOWN LEFT\n";
|
||||
}
|
||||
// Asciende
|
||||
else {
|
||||
const LineVertical LEFT_SIDE = {.x = static_cast<int>(x_), .y1 = static_cast<int>(y_) + static_cast<int>(HEIGHT) - 2, .y2 = static_cast<int>(y_) + static_cast<int>(HEIGHT) - 1}; // Comprueba solo los dos pixels de abajo
|
||||
const int LY = room_->checkLeftSlopes(&LEFT_SIDE);
|
||||
if (LY > -1) {
|
||||
y_ = LY - HEIGHT;
|
||||
std::cout << "RAMP UP LEFT\n";
|
||||
}
|
||||
}
|
||||
// Regla: Si está bajando la rampa, se pega a la slope
|
||||
if (isOnDownSlope()) {
|
||||
y_ += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Regla: Si está STANDING y tropieza lateralmente con una Slope, se pega a la slope
|
||||
// Comprueba si hay rampa en contacto lateral (solo los dos pixels inferiores)
|
||||
const int SIDE_X = direction < 0 ? static_cast<int>(x_) : static_cast<int>(x_) + WIDTH - 1;
|
||||
const LineVertical SIDE = {
|
||||
.x = SIDE_X,
|
||||
.y1 = static_cast<int>(y_) + HEIGHT - 2,
|
||||
.y2 = static_cast<int>(y_) + HEIGHT - 1
|
||||
};
|
||||
|
||||
// Comprueba la rampa correspondiente según la dirección
|
||||
const int SLOPE_Y = direction < 0 ? room_->checkLeftSlopes(&SIDE) : room_->checkRightSlopes(&SIDE);
|
||||
|
||||
if (SLOPE_Y > -1) {
|
||||
// Hay rampa: sube al jugador para pegarlo a la rampa
|
||||
y_ = SLOPE_Y - HEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
// Maneja el movimiento horizontal hacia la derecha
|
||||
void Player::moveHorizontalRight(float delta_time) {
|
||||
// Crea el rectangulo de proyección en el eje X para ver si colisiona
|
||||
// Maneja el movimiento horizontal
|
||||
// direction: -1 para izquierda, 1 para derecha
|
||||
void Player::moveHorizontal(float delta_time, int direction) {
|
||||
const float DISPLACEMENT = vx_ * delta_time;
|
||||
SDL_FRect proj = {
|
||||
.x = x_ + WIDTH,
|
||||
.y = y_,
|
||||
.w = std::ceil(DISPLACEMENT), // Para evitar que tenga un ancho de 0 pixels
|
||||
.h = HEIGHT};
|
||||
|
||||
// Comprueba la colisión
|
||||
const int POS = room_->checkLeftSurfaces(&proj);
|
||||
// Crea el rectangulo de proyección en el eje X para ver si colisiona
|
||||
SDL_FRect proj;
|
||||
if (direction < 0) {
|
||||
// Movimiento a la izquierda
|
||||
proj = {
|
||||
.x = x_ + DISPLACEMENT,
|
||||
.y = y_,
|
||||
.w = std::ceil(std::fabs(DISPLACEMENT)),
|
||||
.h = HEIGHT
|
||||
};
|
||||
} else {
|
||||
// Movimiento a la derecha
|
||||
proj = {
|
||||
.x = x_ + WIDTH,
|
||||
.y = y_,
|
||||
.w = std::ceil(DISPLACEMENT),
|
||||
.h = HEIGHT
|
||||
};
|
||||
}
|
||||
|
||||
// Comprueba la colisión con las superficies
|
||||
const int POS = direction < 0 ? room_->checkRightSurfaces(&proj) : room_->checkLeftSurfaces(&proj);
|
||||
|
||||
// Calcula la nueva posición
|
||||
if (POS == -1) {
|
||||
// Si no hay colisión
|
||||
// No hay colisión: mueve al jugador
|
||||
x_ += DISPLACEMENT;
|
||||
} else {
|
||||
// Si hay colisión lo mueve hasta donde no colisiona
|
||||
x_ = POS - WIDTH;
|
||||
std::cout << "RIGHT\n";
|
||||
// Hay colisión: reposiciona al jugador en el punto de colisión
|
||||
x_ = direction < 0 ? POS + 1 : POS - WIDTH;
|
||||
}
|
||||
|
||||
// Si ha tocado alguna rampa mientras camina (sin saltar)
|
||||
if (state_ == State::STANDING) {
|
||||
// Si está bajando la rampa, recoloca al jugador
|
||||
if (isOnDownSlope() && state_ == State::STANDING) {
|
||||
y_ += 1;
|
||||
std::cout << "RAMP DOWN RIGHT\n";
|
||||
}
|
||||
// Asciende
|
||||
else {
|
||||
const LineVertical RIGHT_SIDE = {.x = static_cast<int>(x_) + static_cast<int>(WIDTH) - 1, .y1 = static_cast<int>(y_) + static_cast<int>(HEIGHT) - 2, .y2 = static_cast<int>(y_) + static_cast<int>(HEIGHT) - 1}; // Comprueba solo los dos pixels de abajo
|
||||
const int RY = room_->checkRightSlopes(&RIGHT_SIDE);
|
||||
if (RY > -1) {
|
||||
y_ = RY - HEIGHT;
|
||||
std::cout << "RAMP UP RIGHT\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// Maneja el movimiento sobre rampas
|
||||
handleSlopeMovement(direction);
|
||||
}
|
||||
|
||||
// Maneja el movimiento vertical hacia arriba
|
||||
@@ -302,9 +355,9 @@ void Player::moveVerticalUp(float delta_time) {
|
||||
// Si no hay colisión
|
||||
y_ += DISPLACEMENT;
|
||||
} else {
|
||||
// Si hay colisión lo mueve hasta donde no colisiona y entra en caída
|
||||
// Si hay colisión lo mueve hasta donde no colisiona
|
||||
// Regla: Si está JUMPING y tropieza contra el techo -> FALLING
|
||||
y_ = POS + 1;
|
||||
std::cout << "TOP\n";
|
||||
setState(State::FALLING);
|
||||
}
|
||||
}
|
||||
@@ -325,47 +378,45 @@ void Player::moveVerticalDown(float delta_time) {
|
||||
if (POS > -1) {
|
||||
// Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie
|
||||
y_ = POS - HEIGHT;
|
||||
std::cout << "BOTTOM\n";
|
||||
setState(State::STANDING);
|
||||
auto_movement_ = false; // Desactiva conveyor belt al aterrizar
|
||||
} else {
|
||||
// Si no hay colisión con los muros, comprueba la colisión con las rampas
|
||||
if (state_ != State::JUMPING) { // Las rampas no se miran si se está saltando
|
||||
auto frect = getRect();
|
||||
auto rect = toSDLRect(frect);
|
||||
// Regla: La unica forma de atravesar una Slope es en estado JUMPING y con vx_ != 0
|
||||
if (state_ != State::JUMPING || vx_ == 0.0F) {
|
||||
// No está saltando o salta recto: se pega a las rampas
|
||||
auto rect = toSDLRect(proj);
|
||||
const LineVertical LEFT_SIDE = {.x = rect.x, .y1 = rect.y, .y2 = rect.y + rect.h - 1};
|
||||
const LineVertical RIGHT_SIDE = {.x = rect.x + rect.w - 1, .y1 = rect.y, .y2 = rect.y + rect.h - 1};
|
||||
std::cout << RIGHT_SIDE.x << " " << RIGHT_SIDE.y1 << " " << RIGHT_SIDE.y2 << "\n";
|
||||
const float POINT = std::max(room_->checkRightSlopes(&RIGHT_SIDE), room_->checkLeftSlopes(&LEFT_SIDE));
|
||||
if (POINT > -1) {
|
||||
// No está saltando y hay colisión con una rampa
|
||||
// Calcula la nueva posición
|
||||
// Hay colisión con una rampa: se pega a ella
|
||||
y_ = POINT - HEIGHT;
|
||||
std::cout << "BOTTOM SLOPE\n";
|
||||
setState(State::STANDING);
|
||||
} else {
|
||||
// No está saltando y no hay colisón con una rampa
|
||||
// Calcula la nueva posición
|
||||
// No hay colisión con rampa: continúa cayendo
|
||||
y_ += DISPLACEMENT;
|
||||
}
|
||||
} else {
|
||||
// Esta saltando y no hay colisión con los muros
|
||||
// Calcula la nueva posición
|
||||
// Está saltando con movimiento horizontal: atraviesa las rampas
|
||||
y_ += DISPLACEMENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recalcula la posición del jugador y su animación
|
||||
// Orquesta el movimiento del jugador
|
||||
void Player::move(float delta_time) {
|
||||
applyGravity(delta_time); // Aplica gravedad al jugador
|
||||
|
||||
// Movimiento horizontal
|
||||
if (vx_ < 0.0F) {
|
||||
moveHorizontalLeft(delta_time);
|
||||
moveHorizontal(delta_time, -1); // Izquierda
|
||||
} else if (vx_ > 0.0F) {
|
||||
moveHorizontalRight(delta_time);
|
||||
moveHorizontal(delta_time, 1); // Derecha
|
||||
}
|
||||
|
||||
// Actualización de estado DURANTE el movimiento (después de horizontal, antes de vertical)
|
||||
// Esto asegura que el estado se actualice con la posición correcta
|
||||
updateState(delta_time);
|
||||
|
||||
// Movimiento vertical
|
||||
if (vy_ < 0.0F) {
|
||||
moveVerticalUp(delta_time);
|
||||
@@ -373,7 +424,8 @@ void Player::move(float delta_time) {
|
||||
moveVerticalDown(delta_time);
|
||||
}
|
||||
|
||||
placeSprite(); // Coloca el sprite en la nueva posición
|
||||
// Actualiza la geometría del collider y sprite
|
||||
updateColliderGeometry();
|
||||
}
|
||||
|
||||
// Establece la animación del jugador
|
||||
@@ -545,42 +597,37 @@ void Player::updateFeet() {
|
||||
|
||||
// Cambia el estado del jugador
|
||||
void Player::setState(State value) {
|
||||
// Solo actualiza el estado y configura las variables iniciales
|
||||
// NO llama a updateState() para evitar recursión circular
|
||||
previous_state_ = state_;
|
||||
state_ = value;
|
||||
|
||||
switch (state_) {
|
||||
case State::STANDING:
|
||||
vy_ = 0.0F;
|
||||
last_grounded_position_ = static_cast<int>(y_);
|
||||
std::cout << "SET STANDING\n";
|
||||
// Se establecerá vy_ = 0 en updateVelocity()
|
||||
break;
|
||||
|
||||
case State::JUMPING:
|
||||
last_grounded_position_ = static_cast<int>(y_);
|
||||
// Configura el salto
|
||||
vy_ = JUMP_VELOCITY;
|
||||
jump_init_pos_ = y_;
|
||||
jumping_time_ = 0.0F;
|
||||
std::cout << "SET JUMPING\n";
|
||||
break;
|
||||
|
||||
case State::FALLING:
|
||||
vx_ = 0.0F;
|
||||
// Configura la caída
|
||||
vy_ = MAX_VY;
|
||||
playFallSound();
|
||||
// vx_ = 0 se establecerá en updateVelocity()
|
||||
if (previous_state_ == State::STANDING) {
|
||||
last_grounded_position_ = static_cast<int>(y_);
|
||||
}
|
||||
auto_movement_ = false;
|
||||
jumping_time_ = 0.0F;
|
||||
std::cout << "SET FALLING\n";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Llama a checkState con delta_time 0 porque esto es un cambio de estado inmediato
|
||||
updateState(0.0F);
|
||||
}
|
||||
|
||||
// Inicializa los sonidos de salto y caida
|
||||
@@ -619,9 +666,14 @@ void Player::initSprite(const std::string& animations_path) {
|
||||
sprite_->setCurrentAnimation("walk");
|
||||
}
|
||||
|
||||
// Coloca el sprite en la posición del jugador
|
||||
void Player::placeSprite() {
|
||||
sprite_->setPos(x_, y_); // Recoloca el sprite
|
||||
// Actualiza collider_box y collision points
|
||||
void Player::updateColliderGeometry() {
|
||||
placeSprite(); // Coloca el sprite en la posición del jugador
|
||||
collider_box_ = getRect(); // Actualiza el rectangulo de colisión
|
||||
updateColliderPoints(); // Actualiza los puntos de colisión
|
||||
}
|
||||
|
||||
// Coloca el sprite en la posición del jugador
|
||||
void Player::placeSprite() {
|
||||
sprite_->setPos(x_, y_);
|
||||
}
|
||||
@@ -98,53 +98,83 @@ class Player {
|
||||
std::shared_ptr<Room> room_; // Objeto encargado de gestionar cada habitación del juego
|
||||
std::unique_ptr<SurfaceAnimatedSprite> sprite_; // Sprite del jugador
|
||||
|
||||
// --- Variables ---
|
||||
// --- Variables de posición y física ---
|
||||
float x_ = 0.0F; // Posición del jugador en el eje X
|
||||
float y_ = 0.0F; // Posición del jugador en el eje Y
|
||||
float vx_ = 0.0F; // Velocidad/desplazamiento del jugador en el eje X
|
||||
float vy_ = 0.0F; // Velocidad/desplazamiento del jugador en el eje Y
|
||||
Uint8 color_ = 0; // Color del jugador
|
||||
|
||||
// --- Variables de estado ---
|
||||
State state_ = State::STANDING; // Estado en el que se encuentra el jugador. Util apara saber si está saltando o cayendo
|
||||
State previous_state_ = State::STANDING; // Estado previo en el que se encontraba el jugador
|
||||
|
||||
// --- Variables de entrada (input intent) ---
|
||||
bool want_to_jump_ = false; // Indica si el jugador quiere saltar
|
||||
bool want_to_move_left_ = false; // Indica si el jugador quiere moverse a la izquierda
|
||||
bool want_to_move_right_ = false; // Indica si el jugador quiere moverse a la derecha
|
||||
|
||||
// --- Variables de colisión ---
|
||||
SDL_FRect collider_box_; // Caja de colisión con los enemigos u objetos
|
||||
std::array<SDL_FPoint, 8> collider_points_{}; // Puntos de colisión con el mapa
|
||||
std::array<SDL_FPoint, 2> under_feet_{}; // Contiene los puntos que hay bajo cada pie del jugador
|
||||
std::array<SDL_FPoint, 2> feet_{}; // Contiene los puntos que hay en el pie del jugador
|
||||
State state_ = State::STANDING; // Estado en el que se encuentra el jugador. Util apara saber si está saltando o cayendo
|
||||
State previous_state_ = State::STANDING; // Estado previo en el que se encontraba el jugador
|
||||
|
||||
// --- Variables de juego ---
|
||||
bool is_on_border_ = false; // Indica si el jugador esta en uno de los cuatro bordes de la pantalla
|
||||
bool is_alive_ = true; // Indica si el jugador esta vivo o no
|
||||
bool is_paused_ = false; // Indica si el jugador esta en modo pausa
|
||||
bool auto_movement_ = false; // Indica si esta siendo arrastrado por una superficie automatica
|
||||
Room::Border border_ = Room::Border::TOP; // Indica en cual de los cuatro bordes se encuentra
|
||||
int jump_init_pos_ = 0; // Valor del eje Y en el que se inicia el salto
|
||||
int last_grounded_position_ = 0; // Ultima posición en Y en la que se estaba en contacto con el suelo
|
||||
|
||||
// --- Variables de renderizado y sonido ---
|
||||
Uint8 color_ = 0; // Color del jugador
|
||||
std::vector<JA_Sound_t*> jumping_sound_; // Vecor con todos los sonidos del salto
|
||||
std::vector<JA_Sound_t*> falling_sound_; // Vecor con todos los sonidos de la caída
|
||||
float jumping_time_ = 0.0F; // Tiempo acumulado de salto en segundos
|
||||
int last_grounded_position_ = 0; // Ultima posición en Y en la que se estaba en contacto con el suelo
|
||||
bool left_or_right_is_pressed_ = false; // Indica si se está pulsando una de las dos direcciones. Sirve para las conveyor belts
|
||||
|
||||
// --- Funciones ---
|
||||
void checkInput(); // Comprueba las entradas y modifica variables
|
||||
void checkBorders(); // Comprueba si se halla en alguno de los cuatro bordes
|
||||
void updateState(float delta_time); // Comprueba el estado del jugador
|
||||
// --- Funciones de inicialización ---
|
||||
void initSprite(const std::string& animations_path); // Inicializa el sprite del jugador
|
||||
void initSounds(); // Inicializa los sonidos de salto y caida
|
||||
void applySpawnValues(const SpawnData& spawn); // Aplica los valores de spawn al jugador
|
||||
|
||||
// --- Funciones de procesamiento de entrada ---
|
||||
void checkInput(); // Comprueba las entradas y establece las banderas de intención
|
||||
|
||||
// --- Funciones de gestión de estado ---
|
||||
void updateState(float delta_time); // Actualiza el estado del jugador basado en física e intenciones
|
||||
void setState(State value); // Cambia el estado del jugador
|
||||
auto canJump() -> bool; // Comprueba si el jugador puede saltar
|
||||
auto shouldFall() -> bool; // Comprueba si el jugador debe caer
|
||||
|
||||
// --- Funciones de física ---
|
||||
void applyGravity(float delta_time); // Aplica gravedad al jugador
|
||||
void move(float delta_time); // Recalcula la posición del jugador y su animación
|
||||
void moveHorizontalLeft(float delta_time); // Maneja el movimiento horizontal hacia la izquierda
|
||||
void moveHorizontalRight(float delta_time); // Maneja el movimiento horizontal hacia la derecha
|
||||
void updateVelocity(); // Actualiza velocidad basada en estado e intenciones
|
||||
|
||||
// --- Funciones de movimiento y colisión ---
|
||||
void move(float delta_time); // Orquesta el movimiento del jugador
|
||||
void moveHorizontal(float delta_time, int direction); // Maneja el movimiento horizontal (-1: izq, 1: der)
|
||||
void moveVerticalUp(float delta_time); // Maneja el movimiento vertical hacia arriba
|
||||
void moveVerticalDown(float delta_time); // Maneja el movimiento vertical hacia abajo
|
||||
void animate(float delta_time); // Establece la animación del jugador
|
||||
void checkJumpEnd(); // Comprueba si ha finalizado el salto al alcanzar la altura de inicio
|
||||
void playJumpSound(); // Calcula y reproduce el sonido de salto
|
||||
void playFallSound(); // Calcula y reproduce el sonido de caer
|
||||
void handleSlopeMovement(int direction); // Maneja el movimiento sobre rampas
|
||||
|
||||
// --- Funciones de detección de superficies ---
|
||||
auto isOnFloor() -> bool; // Comprueba si el jugador tiene suelo debajo de los pies
|
||||
auto isOnAutoSurface() -> bool; // Comprueba si el jugador esta sobre una superficie automática
|
||||
auto isOnDownSlope() -> bool; // Comprueba si el jugador está sobre una rampa hacia abajo
|
||||
auto checkKillingTiles() -> bool; // Comprueba que el jugador no toque ningun tile de los que matan
|
||||
|
||||
// --- Funciones de actualización de geometría ---
|
||||
void updateColliderGeometry(); // Actualiza collider_box y collision points
|
||||
void updateColliderPoints(); // Actualiza los puntos de colisión
|
||||
void updateFeet(); // Actualiza los puntos de los pies
|
||||
void setState(State value); // Cambia el estado del jugador
|
||||
void initSounds(); // Inicializa los sonidos de salto y caida
|
||||
void placeSprite(); // Coloca el sprite en la posición del jugador
|
||||
void applySpawnValues(const SpawnData& spawn); // Aplica los valores de spawn al jugador
|
||||
void initSprite(const std::string& animations_path); // Inicializa el sprite del jugador
|
||||
|
||||
// --- Funciones de finalización ---
|
||||
void animate(float delta_time); // Establece la animación del jugador
|
||||
void checkBorders(); // Comprueba si se halla en alguno de los cuatro bordes
|
||||
void checkJumpEnd(); // Comprueba si ha finalizado el salto al alcanzar la altura de inicio
|
||||
auto checkKillingTiles() -> bool; // Comprueba que el jugador no toque ningun tile de los que matan
|
||||
void playJumpSound(); // Calcula y reproduce el sonido de salto
|
||||
void playFallSound(); // Calcula y reproduce el sonido de caer
|
||||
};
|
||||
Reference in New Issue
Block a user