#include "pch.h" #include "Level.h" #include "GroundTile.h" #include "WoodTile.h" #include "Item.h" #include #include class IsOverlappingHitbox { public: IsOverlappingHitbox(const Rectf& hitbox) : m_Hitbox(hitbox) { } bool operator()(const Tile* tile) { return (utils::IsOverlapping(Rectf{ tile->GetVertices()[0].x, tile->GetVertices()[0].y, Tile::m_Size, Tile::m_Size }, m_Hitbox)); } private: const Rectf& m_Hitbox; }; Level::Level(int world, int stage) : m_BackgroundTexture{ "Resources/Sprites/minebg.jpg" } , m_BorderBgTexture{ "Resources/Sprites/borderbg.png" } , m_BorderEdgesTexture{ "Resources/Sprites/border_edges.png" } , m_World{ world } , m_Stage{ stage } , m_Timer{ } , m_DoorTextures{ "Resources/Sprites/TU_exitdoors.png" } , m_EntryDoorPos{ } , m_ExitDoorPos{ } , m_EntryDoorSrc{ 256, 256, 256, 256 } , m_ExitDoorSrc{ 0, 256, 256, 256 } { m_LevelVertices.push_back(Point2f{ 0, 0 }); m_LevelVertices.push_back(Point2f{ Tile::m_Size * m_NrTilesX, 0 }); m_LevelVertices.push_back(Point2f{ Tile::m_Size * m_NrTilesX, Tile::m_Size * m_NrTilesY }); m_LevelVertices.push_back(Point2f{ 0, Tile::m_Size * m_NrTilesY }); LoadLevel(m_World, m_Stage); m_Boundaries = Rectf{ Tile::m_Size * -m_BorderSize, Tile::m_Size * -m_BorderSize, Tile::m_Size * (m_NrTilesX + m_BorderSize), Tile::m_Size * (m_NrTilesY + m_BorderSize) }; InitTiles(); } void Level::InitTiles() { for (Tile* tile : m_pTilesList) { tile->Init(m_pTiles, m_NrTilesX, m_NrTilesY); } } void Level::UpdateTilesBorders() { for (Tile* tile : m_pTilesList) { tile->UpdateBorder(m_pTiles, m_NrTilesX, m_NrTilesY); } } void Level::Update(float elapsedSec) { m_Timer += elapsedSec; } Level::Info Level::GetInfo() const { return Info{ m_World, m_Stage, m_Timer }; } unsigned int Level::GetTileIdx(int x, int y) const { return (x + m_NrTilesX * y); } void Level::CreateTile(int x, int y, Tile::Type tileType, int itemType) { switch (tileType) { case Tile::Type::Ground: m_pTiles[GetTileIdx(x, y)] = new GroundTile(x, y, itemType); break; case Tile::Type::Wood: m_pTiles[GetTileIdx(x, y)] = new WoodTile(x, y, itemType); break; } m_pTilesList.push_back(m_pTiles[GetTileIdx(x, y)]); } void Level::LoadLevel(int world, int stage) { std::ifstream levelFile{ "Resources/Levels/" + std::to_string(world) + "-" + std::to_string(stage) + "/level.lvl" }; int y{ m_NrTilesY - 1 }; while (levelFile) { std::string str{}; std::getline(levelFile, str); for (size_t x{}; x < str.length(); x++) { switch (str[x]) { case '0': break; case '1': CreateTile(static_cast(x), static_cast(y), Tile::Type::Ground); break; case '2': CreateTile(static_cast(x), static_cast(y), Tile::Type::Wood); break; case 'g': CreateTile(static_cast(x), static_cast(y), Tile::Type::Ground, int(Item::Type::GOLD_CHUNK_SMALL)); break; case 'G': CreateTile(static_cast(x), static_cast(y), Tile::Type::Ground, int(Item::Type::GOLD_CHUNK_BIG)); break; case 'd': m_EntryDoorPos.x = (x * Tile::m_Size) - (m_EntryDoorSrc.width / 2 - Tile::m_Size / 2); m_EntryDoorPos.y = (y * Tile::m_Size) - (m_EntryDoorSrc.height / 2 - Tile::m_Size / 2); break; case 'D': m_ExitDoorPos.x = (x * Tile::m_Size) - (m_ExitDoorSrc.width / 2 - Tile::m_Size / 2); m_ExitDoorPos.y = (y * Tile::m_Size) - (m_ExitDoorSrc.height / 2 - Tile::m_Size / 2); break; case 'l': CreateLadder(static_cast(x), static_cast(y)); break; case 'L': CreateLadder(static_cast(x), static_cast(y), WITH_PLATFORM); break; default: break; } } y--; } } void Level::CreateLadder(int x, int y, bool isPlatform) { m_pLadders.push_back(new Ladder{ x, y, isPlatform }); } Level::~Level() { for (size_t i{}; i < m_pTilesList.size(); i++) { delete m_pTilesList[i]; m_pTilesList[i] = nullptr; } for (size_t i{}; i < m_pLadders.size(); i++) { delete m_pLadders[i]; m_pLadders[i] = nullptr; } } Rectf Level::GetBoundaries() const { return m_Boundaries; } Point2f Level::GetStartPos(float playerWidth) const { return Point2f{ (Tile::m_Size - playerWidth) / 2 + m_EntryDoorPos.x + m_EntryDoorSrc.width / 2 - Tile::m_Size / 2, m_EntryDoorPos.y + m_EntryDoorSrc.height / 2 -Tile::m_Size / 2 }; } void Level::DrawBackground() const { // background Point2f bgPos{ 0, 0 }; for (int i{}; i < (m_NrTilesX / 4); i++) { for (int j{}; j < (m_NrTilesY / 4); j++) { m_BackgroundTexture.Draw(Point2f{ bgPos.x + m_BackgroundTexture.GetWidth() * i, bgPos.y + m_BackgroundTexture.GetHeight() * j }); } } // doors m_DoorTextures.Draw(Point2f{ m_EntryDoorPos.x, m_EntryDoorPos.y }, m_EntryDoorSrc); m_DoorTextures.Draw(Point2f{ m_ExitDoorPos.x, m_ExitDoorPos.y }, m_ExitDoorSrc); // ladders for (Ladder* pLadder : m_pLadders) { pLadder->Draw(); } // border Rectf srcRect{ 64, 0, 128, m_BorderBgTexture.GetHeight() / 2 }; for (int i{}; i < m_NrTilesX / 2; i++) { // top m_BorderBgTexture.Draw(Point2f{ i * srcRect.width, Tile::m_Size * m_NrTilesY }, srcRect); // bottom m_BorderBgTexture.Draw(Point2f{ i * srcRect.width, Tile::m_Size * - m_BorderSize }, srcRect); } srcRect = Rectf{ 0, 0, m_BorderBgTexture.GetWidth(), m_BorderBgTexture.GetHeight() }; for (int i{}; i < m_NrTilesY / 4; i++) { // left m_BorderBgTexture.Draw(Point2f{ Tile::m_Size * -m_BorderSize, i * m_BorderBgTexture.GetHeight() - (Tile::m_Size * m_BorderSize) }); // right m_BorderBgTexture.Draw(Point2f{ Tile::m_Size * m_NrTilesX, i * m_BorderBgTexture.GetHeight() - (Tile::m_Size * m_BorderSize) }, srcRect); } } void Level::DrawVertices() const { float vertexSize = 4; glLineWidth(1); glColor4f(.5f, .5f, .5f, 1); glBegin(GL_LINE_LOOP); for (Point2f vertex : m_LevelVertices) { glVertex2f(vertex.x, vertex.y); } glEnd(); glColor4f(0, 0, 1, 1); for (Point2f vertex : m_LevelVertices) { utils::FillRect(Point2f{ vertex.x - vertexSize / 2, vertex.y - vertexSize / 2 }, vertexSize, vertexSize); } for (Tile* tile : m_pTilesList) { tile->DrawVertices(); } } void Level::DrawForeground() const { // tiles for (const Tile* tile : m_pTilesList) { tile->Draw(); } for (const Tile* tile : m_pTilesList) { tile->DrawBorder(); tile->DrawItem(); } // border overlay Rectf srcTopBorder{ 128, 64, 64, 64 }; Rectf srcBtmBorder{ 192, 64, 64, 64 }; for (int i{}; i < m_NrTilesX; i++) { // top m_BorderEdgesTexture.Draw(Point2f{ i * Tile::m_Size, Tile::m_Size * m_NrTilesY - 14 }, srcTopBorder); // bottom m_BorderEdgesTexture.Draw(Point2f{ i * Tile::m_Size, -24 }, srcBtmBorder); } Rectf srcLeftBorder{ 64, 64, 64, 64 }; Rectf srcRightBorder{ 0, 64, 64, 64 }; float edgeMargin{ 16 }; for (int i{}; i < m_NrTilesY; i++) { // left m_BorderEdgesTexture.Draw(Point2f{ -edgeMargin, i * Tile::m_Size }, srcLeftBorder); // right m_BorderEdgesTexture.Draw(Point2f{ Tile::m_Size * (m_NrTilesX - 1) + edgeMargin, i * Tile::m_Size }, srcRightBorder); } } Tile* Level::IsGrabbingLedge(Rectf& hitbox, Vector2f& velocity, int playerDir) const { float grabDistance{ 4 }; float halfWidth{ hitbox.width * 0.5f }; Point2f topRight{ hitbox.left + hitbox.width, hitbox.bottom + hitbox.height }; Point2f topLeft{ hitbox.left, hitbox.bottom + hitbox.height }; utils::HitInfo hitInfo{}; std::vector pNearbyTiles; /* auto IsOverlappingLambda = [hitbox](Tile* tile) { return (utils::IsOverlapping(Rectf{ tile->GetVertices()[0].x, tile->GetVertices()[0].y, Tile::m_Size, Tile::m_Size }, hitbox)); }; for (std::vector::const_iterator it{ std::find_if(m_pTilesList.begin(), m_pTilesList.end(), IsOverlappingLambda) }; it != m_pTilesList.end(); it = std::find_if(++it, m_pTilesList.end(), IsOverlappingLambda)) */ for (std::vector::const_iterator it{ std::find_if(m_pTilesList.begin(), m_pTilesList.end(), IsOverlappingHitbox(hitbox)) }; it != m_pTilesList.end(); it = std::find_if(++it, m_pTilesList.end(), IsOverlappingHitbox(hitbox))) { pNearbyTiles.push_back(*it); } for (Tile* tile : pNearbyTiles) { if ((tile->GetY() < (m_NrTilesY - 1)) && (m_pTiles[GetTileIdx(tile->GetX(), tile->GetY() + 1)] == nullptr)) { switch (playerDir) { case 0: //left if (utils::Raycast(tile->GetLedgeVertices(), Point2f{ topLeft.x + halfWidth , topLeft.y }, Point2f{ topLeft.x - grabDistance, topLeft.y }, hitInfo)) return tile; break; case 1: //right if (utils::Raycast(tile->GetLedgeVertices(), Point2f{ topRight.x - halfWidth , topRight.y }, Point2f{ topRight.x + grabDistance, topRight.y }, hitInfo)) return tile; break; default: break; } } } return nullptr; } void Level::HandleCollision(Rectf& hitbox, Vector2f& velocity) const { float halfWidth{ hitbox.width * 0.5f }; float halfHeight{ hitbox.height * 0.5f }; float marginSides{ 12 }; float marginTop{ 12 }; Point2f btmLeft{ hitbox.left, hitbox.bottom }; Point2f btmRight{ hitbox.left + hitbox.width, hitbox.bottom }; Point2f topRight{ hitbox.left + hitbox.width, hitbox.bottom + hitbox.height }; Point2f topLeft{ hitbox.left, hitbox.bottom + hitbox.height }; utils::HitInfo hitInfo{}; // Collision with level boundaries if ((hitbox.left <= 0) || (hitbox.bottom <= 0) || ((hitbox.left + hitbox.width) >= m_NrTilesX * Tile::m_Size) || ((hitbox.bottom + hitbox.height) >= m_NrTilesY * Tile::m_Size)) { if (utils::Raycast(m_LevelVertices, Point2f{ topLeft.x + halfWidth, topLeft.y }, Point2f{ topLeft.x + halfWidth, topLeft.y - halfHeight }, hitInfo)) { // top hitbox.bottom = hitInfo.intersectPoint.y - hitbox.height; velocity.y = 0; } else if (utils::Raycast(m_LevelVertices, Point2f{ btmLeft.x + halfWidth, btmLeft.y }, Point2f{ btmLeft.x + halfWidth, btmLeft.y + halfHeight }, hitInfo)) { // bottom hitbox.bottom = hitInfo.intersectPoint.y; velocity.y = 0; } if (utils::Raycast(m_LevelVertices, Point2f{ topLeft.x , topLeft.y - halfHeight }, Point2f{ topLeft.x + halfWidth, topLeft.y - halfHeight }, hitInfo)) { //left hitbox.left = hitInfo.intersectPoint.x; velocity.x = 0; } else if (utils::Raycast(m_LevelVertices, Point2f{ topRight.x, topRight.y - halfHeight }, Point2f{ topRight.x - halfWidth, topRight.y - halfHeight }, hitInfo)) { // right hitbox.left = hitInfo.intersectPoint.x - hitbox.width; velocity.x = 0; } } // Collision with level tiles std::vector pNearbyTiles; for (std::vector::const_iterator it{ std::find_if(m_pTilesList.begin(), m_pTilesList.end(), IsOverlappingHitbox(hitbox)) }; it != m_pTilesList.end(); it = std::find_if(++it, m_pTilesList.end(), IsOverlappingHitbox(hitbox))) { pNearbyTiles.push_back(*it); } for (Tile* tile : pNearbyTiles) { if (utils::IsOverlapping(Rectf{ tile->GetVertices()[0].x, tile->GetVertices()[0].y, Tile::m_Size, Tile::m_Size }, hitbox)) { if (utils::Raycast(tile->GetVertices(), Point2f{ btmLeft.x + marginTop, btmLeft.y }, Point2f{ btmLeft.x + marginTop, btmLeft.y + halfHeight }, hitInfo) || utils::Raycast(tile->GetVertices(), Point2f{ btmRight.x - marginTop, btmRight.y }, Point2f{ btmRight.x - marginTop, btmRight.y + halfHeight }, hitInfo)) { // bottom hitbox.bottom = hitInfo.intersectPoint.y; velocity.y = 0; } else if (utils::Raycast(tile->GetVertices(), Point2f{ topLeft.x + marginTop, topLeft.y }, Point2f{ topLeft.x + marginTop, topLeft.y - halfHeight }, hitInfo) || utils::Raycast(tile->GetVertices(), Point2f{ topRight.x - marginTop, topRight.y }, Point2f{ topRight.x - marginTop, topRight.y - halfHeight }, hitInfo)) { // top hitbox.bottom = hitInfo.intersectPoint.y - hitbox.height; velocity.y = 0; } if (utils::Raycast(tile->GetVertices(), Point2f{ btmLeft.x, btmLeft.y + marginSides }, Point2f{ btmLeft.x + halfWidth, btmLeft.y + marginSides }, hitInfo) || utils::Raycast(tile->GetVertices(), Point2f{ topLeft.x, topLeft.y - marginSides }, Point2f{ topLeft.x + halfWidth, topLeft.y - marginSides }, hitInfo)) { // btm left hitbox.left = hitInfo.intersectPoint.x; velocity.x = 0; } else if (utils::Raycast(tile->GetVertices(), Point2f{ btmRight.x, btmRight.y + marginSides }, Point2f{ btmRight.x - halfWidth, btmRight.y + marginSides }, hitInfo) || utils::Raycast(tile->GetVertices(), Point2f{ topRight.x, topRight.y - marginSides }, Point2f{ topRight.x - halfWidth, topRight.y - marginSides }, hitInfo)) { // btm right hitbox.left = hitInfo.intersectPoint.x - hitbox.width; velocity.x = 0; } } } } void Level::BounceCollision(Rectf& hitbox, Vector2f& velocity) const { float halfWidth{ hitbox.width * 0.5f }; float halfHeight{ hitbox.height * 0.5f }; float marginSides{ 8 }; float marginTop{ 8 }; Point2f btmLeft{ hitbox.left, hitbox.bottom }; Point2f btmRight{ hitbox.left + hitbox.width, hitbox.bottom }; Point2f topRight{ hitbox.left + hitbox.width, hitbox.bottom + hitbox.height }; Point2f topLeft{ hitbox.left, hitbox.bottom + hitbox.height }; utils::HitInfo hitInfo{}; // Collision with level boundaries if ((hitbox.left <= 0) || (hitbox.bottom <= 0) || ((hitbox.left + hitbox.width) >= m_NrTilesX * Tile::m_Size) || ((hitbox.bottom + hitbox.height) >= m_NrTilesY * Tile::m_Size)) { if (utils::Raycast(m_LevelVertices, Point2f{ topLeft.x + halfWidth, topLeft.y }, Point2f{ topLeft.x + halfWidth, topLeft.y - halfHeight }, hitInfo)) { // top hitbox.bottom = hitInfo.intersectPoint.y - hitbox.height; velocity.y = -velocity.y; } else if (utils::Raycast(m_LevelVertices, Point2f{ btmLeft.x + halfWidth, btmLeft.y }, Point2f{ btmLeft.x + halfWidth, btmLeft.y + halfHeight }, hitInfo)) { // bottom hitbox.bottom = hitInfo.intersectPoint.y; velocity.y = -velocity.y; } if (utils::Raycast(m_LevelVertices, Point2f{ topLeft.x , topLeft.y - halfHeight }, Point2f{ topLeft.x + halfWidth, topLeft.y - halfHeight }, hitInfo)) { //left hitbox.left = hitInfo.intersectPoint.x; velocity.x = -velocity.x; } else if (utils::Raycast(m_LevelVertices, Point2f{ topRight.x, topRight.y - halfHeight }, Point2f{ topRight.x - halfWidth, topRight.y - halfHeight }, hitInfo)) { // right hitbox.left = hitInfo.intersectPoint.x - hitbox.width; velocity.x = -velocity.x; } } // Collision with level tiles std::vector pNearbyTiles; for (std::vector::const_iterator it{ std::find_if(m_pTilesList.begin(), m_pTilesList.end(), IsOverlappingHitbox(hitbox)) }; it != m_pTilesList.end(); it = std::find_if(++it, m_pTilesList.end(), IsOverlappingHitbox(hitbox))) { pNearbyTiles.push_back(*it); } for (Tile* tile : pNearbyTiles) { if (utils::IsOverlapping(Rectf{ tile->GetVertices()[0].x, tile->GetVertices()[0].y, Tile::m_Size, Tile::m_Size }, hitbox)) { if (utils::Raycast(tile->GetVertices(), Point2f{ btmLeft.x + marginTop, btmLeft.y }, Point2f{ btmLeft.x + marginTop, btmLeft.y + halfHeight }, hitInfo) || utils::Raycast(tile->GetVertices(), Point2f{ btmRight.x - marginTop, btmRight.y }, Point2f{ btmRight.x - marginTop, btmRight.y + halfHeight }, hitInfo)) { // bottom hitbox.bottom = hitInfo.intersectPoint.y; velocity.y = -velocity.y; } else if (utils::Raycast(tile->GetVertices(), Point2f{ topLeft.x + marginTop, topLeft.y }, Point2f{ topLeft.x + marginTop, topLeft.y - halfHeight }, hitInfo) || utils::Raycast(tile->GetVertices(), Point2f{ topRight.x - marginTop, topRight.y }, Point2f{ topRight.x - marginTop, topRight.y - halfHeight }, hitInfo)) { // top hitbox.bottom = hitInfo.intersectPoint.y - hitbox.height; velocity.y = -velocity.y; } if (utils::Raycast(tile->GetVertices(), Point2f{ btmLeft.x, btmLeft.y + marginSides }, Point2f{ btmLeft.x + halfWidth, btmLeft.y + marginSides }, hitInfo) || utils::Raycast(tile->GetVertices(), Point2f{ topLeft.x, topLeft.y - marginSides }, Point2f{ topLeft.x + halfWidth, topLeft.y - marginSides }, hitInfo)) { // btm left hitbox.left = hitInfo.intersectPoint.x; velocity.x = -velocity.x; } else if (utils::Raycast(tile->GetVertices(), Point2f{ btmRight.x, btmRight.y + marginSides }, Point2f{ btmRight.x - halfWidth, btmRight.y + marginSides }, hitInfo) || utils::Raycast(tile->GetVertices(), Point2f{ topRight.x, topRight.y - marginSides }, Point2f{ topRight.x - halfWidth, topRight.y - marginSides }, hitInfo)) { // btm right hitbox.left = hitInfo.intersectPoint.x - hitbox.width; velocity.x = -velocity.x; } } } } bool Level::IsOverlappingLadder(const Rectf& hitbox, float& maxY, bool& isTopPiece) const { for (Ladder* pLadder : m_pLadders) { if (utils::IsOverlapping(hitbox, pLadder->GetThinnerHitbox())) { std::vector::const_iterator found = std::find_if(m_pLadders.begin(), m_pLadders.end(), [pLadder](Ladder* ladder) { return ((ladder->GetX() == pLadder->GetX()) && (ladder->GetY() == (pLadder->GetY() + 1))); }); if (found == m_pLadders.end()) { isTopPiece = true; maxY = pLadder->GetHitbox().bottom + pLadder->GetHitbox().height; } return true; } } return false; } bool Level::IsOverlappingLadder(const Rectf& hitbox, float& ladderX) const { for (Ladder* pLadder : m_pLadders) { if (utils::IsOverlapping(hitbox, pLadder->GetThinnerHitbox())) { ladderX = pLadder->GetHitbox().left; return true; } } return false; } bool Level::IsNearlyFalling(const Rectf& hitbox, int playerDir) const { float halfWidth{ hitbox.width / 2 }; float halfHeight{ hitbox.height / 2 }; float marginTop{ 8 }; Point2f btmLeft{ hitbox.left, hitbox.bottom }; Point2f btmRight{ hitbox.left + hitbox.width, hitbox.bottom }; utils::HitInfo hitInfo{}; if (utils::Raycast(m_LevelVertices, Point2f{ btmLeft.x + halfWidth, btmLeft.y }, Point2f{ btmLeft.x + halfWidth, btmLeft.y + halfHeight }, hitInfo)) { return false; } std::vector pNearbyTiles; for (std::vector::const_iterator it{ std::find_if(m_pTilesList.begin(), m_pTilesList.end(), IsOverlappingHitbox(hitbox)) }; it != m_pTilesList.end(); it = std::find_if(++it, m_pTilesList.end(), IsOverlappingHitbox(hitbox))) { pNearbyTiles.push_back(*it); } for (Tile* tile : pNearbyTiles) { if (utils::Raycast(tile->GetVertices(), Point2f{ btmLeft.x + halfWidth, btmLeft.y + halfHeight }, Point2f{ btmLeft.x + halfWidth, btmLeft.y - 1 }, hitInfo)) { return false; } else { switch (playerDir) { case 0: //left if (utils::Raycast(tile->GetVertices(), Point2f{ btmLeft.x + marginTop, btmLeft.y + halfHeight }, Point2f{ btmLeft.x + marginTop, btmLeft.y - 1 }, hitInfo)) return false; break; case 1: //right if (utils::Raycast(tile->GetVertices(), Point2f{ btmRight.x - marginTop, btmRight.y + halfHeight }, Point2f{ btmRight.x - marginTop, btmRight.y - 1 }, hitInfo)) return false; break; default: break; } } } return true; } bool Level::IsOnSingleTile(const Rectf& hitbox) const { float halfWidth{ hitbox.width / 2 }; float halfHeight{ hitbox.height / 2 }; float marginTop{ 8 }; Point2f btmLeft{ hitbox.left, hitbox.bottom }; Point2f btmRight{ hitbox.left + hitbox.width, hitbox.bottom }; utils::HitInfo hitInfo{}; std::vector pNearbyTiles; for (std::vector::const_iterator it{ std::find_if(m_pTilesList.begin(), m_pTilesList.end(), IsOverlappingHitbox(hitbox)) }; it != m_pTilesList.end(); it = std::find_if(++it, m_pTilesList.end(), IsOverlappingHitbox(hitbox))) { pNearbyTiles.push_back(*it); } for (Tile* tile : pNearbyTiles) { if (utils::Raycast(tile->GetVertices(), Point2f{ btmLeft.x + marginTop, btmLeft.y + halfHeight }, Point2f{ btmLeft.x + marginTop, btmLeft.y - 1 }, hitInfo) || utils::Raycast(tile->GetVertices(), Point2f{ btmRight.x - marginTop, btmRight.y + halfHeight }, Point2f{ btmRight.x - marginTop, btmRight.y - 1 }, hitInfo)) { bool cantMoveRight{}; bool cantMoveLeft{}; if (tile->GetY() < m_NrTilesY - 1) { if (tile->GetX() < m_NrTilesX - 1) { if ((m_pTiles[GetTileIdx(tile->GetX() + 1, tile->GetY())] == nullptr) || (m_pTiles[GetTileIdx(tile->GetX() + 1, tile->GetY() + 1)] != nullptr)) { cantMoveRight = true; } } if (tile->GetX() > 0) { if ((m_pTiles[GetTileIdx(tile->GetX() - 1, tile->GetY())] == nullptr) || (m_pTiles[GetTileIdx(tile->GetX() - 1, tile->GetY() + 1)] != nullptr)) { cantMoveLeft = true; } } } //std::cout << "\rleftTile: " << noLeftTile << ", rightTile: " << noRightTile; //std::cout << "\rnoLeftTile: " << noLeftTile << ", noRightTile: " << noRightTile << ", tile: [" << tile->GetX() << ", " << tile->GetY() << "]"; return (cantMoveLeft && cantMoveRight); } } return false; } bool Level::IsOnGround(const Rectf& hitbox) const { float halfWidth{ hitbox.width / 2 }; float halfHeight{ hitbox.height / 2 }; float marginTop{ 8 }; Point2f btmLeft{ hitbox.left, hitbox.bottom }; Point2f btmRight{ hitbox.left + hitbox.width, hitbox.bottom }; utils::HitInfo hitInfo{}; if (utils::Raycast(m_LevelVertices, Point2f{ btmLeft.x + halfWidth, btmLeft.y }, Point2f{ btmLeft.x + halfWidth, btmLeft.y + halfHeight }, hitInfo)) { return true; } std::vector pNearbyTiles; for (std::vector::const_iterator it{ std::find_if(m_pTilesList.begin(), m_pTilesList.end(), IsOverlappingHitbox(hitbox)) }; it != m_pTilesList.end(); it = std::find_if(++it, m_pTilesList.end(), IsOverlappingHitbox(hitbox))) { pNearbyTiles.push_back(*it); } for (Tile* tile : pNearbyTiles) { if (utils::Raycast(tile->GetVertices(), Point2f{ btmLeft.x + marginTop, btmLeft.y + halfHeight }, Point2f{ btmLeft.x + marginTop, btmLeft.y - 1 }, hitInfo) || utils::Raycast(tile->GetVertices(), Point2f{ btmRight.x - marginTop, btmRight.y + halfHeight }, Point2f{ btmRight.x - marginTop, btmRight.y - 1 }, hitInfo)) { return true; } } return false; }