barrallantse en la colisió en les habitacions dels costats

fix: surface no clipejava be la copia de surfaces a surfaces que eixien per la dreta amb el flip activat
This commit is contained in:
2026-04-08 19:04:45 +02:00
parent 2a63227ee2
commit 79f79166bd
5 changed files with 191 additions and 13 deletions

View File

@@ -239,7 +239,7 @@ void Player::moveHorizontal(float delta_time) {
auto [tc, ox, oy] = getCollisionContext();
float new_x = x_ + (vx_ * delta_time);
// Colisión con paredes
// Colisión con paredes (room actual)
if (vx_ < 0.0F) {
float wall = tc.checkWallLeft(new_x + ox, y_ + oy, WIDTH, HEIGHT);
if (wall != Collision::NONE) {
@@ -252,6 +252,10 @@ void Player::moveHorizontal(float delta_time) {
}
}
// Cross-room: comprobar muros en rooms adyacentes
auto cross = getCrossRoomChecks();
checkCrossRoomWallH(new_x, cross);
x_ = new_x;
// Si estamos en una slope, ajustar Y para seguirla
@@ -352,6 +356,8 @@ void Player::moveVertical(float delta_time) {
auto [tc, ox, oy] = getCollisionContext();
float displacement = vy_ * delta_time;
float old_y = y_;
if (vy_ < 0.0F) {
// Subiendo: comprobar techo
float new_y = y_ + displacement;
@@ -385,6 +391,10 @@ void Player::moveVertical(float delta_time) {
#endif
}
}
// Cross-room: comprobar suelo/techo en rooms adyacentes
auto cross = getCrossRoomChecks();
checkCrossRoomFloor(old_y, cross);
}
// ============================================================================
@@ -423,6 +433,12 @@ void Player::checkFalling() {
transitionToState(State::ON_SLOPE);
return;
}
// Cross-room: comprobar suelo en rooms adyacentes antes de declarar caída
if (hasCrossRoomGround(getCrossRoomChecks())) {
return;
}
vy_ = 0.0F;
transitionToState(State::ON_AIR);
}
@@ -553,6 +569,109 @@ void Player::syncSpriteAndCollider() {
collider_box_ = getRect();
}
// Cross-room collision: asigna una room adyacente por índice
void Player::setBorderRoom(int index, std::shared_ptr<Room> room) {
if (index >= 0 && index < BORDER_ROOM_COUNT) {
border_rooms_[index] = std::move(room);
}
}
// Cross-room collision: limpia todas las rooms adyacentes
void Player::clearBorderRooms() {
for (auto& r : border_rooms_) {
r.reset();
}
}
// Cross-room: construye la lista de rooms adyacentes que solapan con la bbox del jugador
auto Player::getCrossRoomChecks() const -> CrossRoomChecks {
// Offsets por room: TOP, RIGHT, BOTTOM, LEFT, TR, BR, BL, TL
static constexpr float PW = static_cast<float>(PlayArea::WIDTH);
static constexpr float PH = static_cast<float>(PlayArea::HEIGHT);
static constexpr struct { float ox; float oy; } OFFSETS[BORDER_ROOM_COUNT] = {
{0, PH}, {-PW, 0}, {0, -PH}, {PW, 0}, {-PW, PH}, {-PW, -PH}, {PW, -PH}, {PW, PH}
};
bool over_top = y_ < 0.0F;
bool over_right = (x_ + WIDTH) > PlayArea::RIGHT;
bool over_bottom = (y_ + HEIGHT) > PlayArea::BOTTOM;
bool over_left = x_ < 0.0F;
bool needed[BORDER_ROOM_COUNT] = {
over_top, over_right, over_bottom, over_left,
over_top && over_right, over_bottom && over_right,
over_bottom && over_left, over_top && over_left
};
CrossRoomChecks result;
for (int i = 0; i < BORDER_ROOM_COUNT; ++i) {
if (needed[i] && border_rooms_[i]) {
result.entries[result.count++] = {&border_rooms_[i]->getTileCollider(), OFFSETS[i].ox, OFFSETS[i].oy};
}
}
return result;
}
// Cross-room: comprueba muros horizontales en rooms adyacentes
void Player::checkCrossRoomWallH(float& new_x, const CrossRoomChecks& checks) const {
for (int i = 0; i < checks.count; ++i) {
const auto& [tc, ox, oy] = checks.entries[i];
if (vx_ < 0.0F) {
float wall = tc->checkWallLeft(new_x + ox, y_ + oy, WIDTH, HEIGHT);
if (wall != Collision::NONE) {
float corrected = wall - ox;
if (corrected > new_x) { new_x = corrected; }
}
} else if (vx_ > 0.0F) {
float wall = tc->checkWallRight(new_x + ox, y_ + oy, WIDTH, HEIGHT);
if (wall != Collision::NONE) {
float corrected = wall - WIDTH - ox;
if (corrected < new_x) { new_x = corrected; }
}
}
}
}
// Cross-room: comprueba suelo/techo en rooms adyacentes (usa old_y para rango correcto de checkFloor)
void Player::checkCrossRoomFloor(float old_y, const CrossRoomChecks& checks) {
for (int i = 0; i < checks.count; ++i) {
const auto& [tc, ox, oy] = checks.entries[i];
if (vy_ < 0.0F) {
float ceiling = tc->checkCeiling(x_ + ox, y_ + oy, WIDTH);
if (ceiling != Collision::NONE) {
float corrected = ceiling - oy;
if (corrected > y_) {
y_ = corrected;
vy_ = 0.0F;
}
}
} else if (vy_ > 0.0F) {
float old_foot = old_y + oy + HEIGHT;
float new_foot = y_ + oy + HEIGHT;
auto hit = tc->checkFloor(x_ + ox, old_foot, WIDTH, new_foot);
if (hit.y != Collision::NONE) {
float corrected = hit.y - HEIGHT - oy;
if (corrected < y_) {
y_ = corrected;
vy_ = 0.0F;
transitionToState(State::ON_GROUND);
}
}
}
}
}
// Cross-room: comprueba si hay suelo bajo el jugador en alguna room adyacente
auto Player::hasCrossRoomGround(const CrossRoomChecks& checks) const -> bool {
for (int i = 0; i < checks.count; ++i) {
const auto& [tc, ox, oy] = checks.entries[i];
float foot = y_ + oy + HEIGHT;
if (tc->hasGroundBelow(x_ + ox, foot, WIDTH)) {
return true;
}
}
return false;
}
// Aplica el desplazamiento de una plataforma móvil al jugador
void Player::applyPlatformDisplacement(float dx, float surface_y) {
y_ = surface_y - HEIGHT; // Snap vertical al top de la plataforma