From b47191a0c1f6b242c9e48545caad4f31dc8fa665 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Mon, 21 Apr 2014 03:56:48 +1000 Subject: [PATCH] Fixed a horrible region coordinate bug Coordinates are supposed to be stored by their x & y, but the sizes of the tile sheets were getting mixed in as well. When trying to store a region at (0, 20), it was being stored at (0, 260). Another visual bug inside the tile sheet's rendering function masked this issue until now. Another thing to note is that I've removed an incredibly complex system for updating the client's map. The new system may seem complex at first, but it is straight forward compared to what it replaced. I've also fixed a few logarithmic lagging points in the code. --- client/player_character.hpp | 1 + client/scenes/in_world.cpp | 80 ++++++++-------------------------- client/scenes/in_world.hpp | 1 - common/graphics/tile_sheet.cpp | 4 +- common/map/region_pager.hpp | 5 +-- 5 files changed, 23 insertions(+), 68 deletions(-) diff --git a/client/player_character.hpp b/client/player_character.hpp index 1f6bc7a..9dde742 100644 --- a/client/player_character.hpp +++ b/client/player_character.hpp @@ -25,6 +25,7 @@ #include "vector2.hpp" #include "sprite_sheet.hpp" +//TODO: correct the PlayerCharacter class and it's movement system class PlayerCharacter { public: enum class Direction { diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index d6cb5a5..936be7d 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -404,76 +404,34 @@ void InWorld::RequestRegion(int x, int y) { //Utilities //------------------------- -int InWorld::CheckBufferDistance(Region* const region) { - /* TODO: Remove InWorld::CheckBufferDistance(), and replace it with a simpler system - * DOCUMENTATION - * This algorithm is extremely complex and involed, but initial tests show - * that it gives the right answers. The purpose is to determine how far off screen - * a certain region is, so that it can be unloaded when necessary. - * - * If the region is actually onscreen, then there's no reason to run the rest, so - * the algorithm corrects for the camera's location, before checking the bounds of - * the screen. - * - * The next part is tricky. If X or Y is negative, then it is divided by the - * graphical size of the regions, resulting in a usable integer, representing how - * far from the screen it is in "region units". If, however, X or Y is larger than - * 0, than first, the size of the screen is subtracted from that variable, before - * it is then divided by the graphical size of a region. Finally, to compensate for - * the off by one error, 1 is added at the end. - * - * Since only the magnitude of the distance in either direction is needed, this - * method returns the largest absolute value of X or Y. - * - * The final result of this algorithm is an integer representing how far, rounded - * up, a certain region is from the screen's edges in any direction, measured in - * "region units". This algorithm may be flawed, in which case, I recommend simply - * replacing it with a boolean check, to see if the region's distance from the player - * is larger than a certain value. This algorithm lacks the advantages I initially - * expected, so that may be beneficial at some point. - */ - - //locations relative to the camera - int x = region->GetX() - camera.x; - int y = region->GetY() - camera.y; - - //if the region is visible, return -1 - if (x >= -REGION_WIDTH * tileSheet.GetTileW() && x < camera.width && - y >= -REGION_HEIGHT * tileSheet.GetTileH() && y < camera.height) { - return -1; - } - - //prune the screen's area from the algorithm; get the pseudo-indexes - if (x < 0) x /= (REGION_WIDTH * tileSheet.GetTileW()); - if (y < 0) y /= (REGION_HEIGHT * tileSheet.GetTileH()); - if (x > 0) x = (x - camera.width) / (REGION_WIDTH * tileSheet.GetTileW()) + 1; - if (y > 0) y = (y - camera.height) / (REGION_HEIGHT * tileSheet.GetTileH()) + 1; - - //return the pseudo-index with the greatest magnitude - return std::max(abs(x), abs(y)); -} - -//TODO: Revise InWorld::UpdateMap() after InWorld::CheckBufferDistance() +//TODO: convert this into a more generic function?; using parameters for the bounds void InWorld::UpdateMap() { + //these represent the zone of regions that the client needs loaded, including the mandatory buffers (+1/-1) + int xStart = snapToBase(REGION_WIDTH, camera.x/tileSheet.GetTileW()) - REGION_WIDTH; + int xEnd = snapToBase(REGION_WIDTH, (camera.x+camera.width)/tileSheet.GetTileW()) + REGION_WIDTH; + + int yStart = snapToBase(REGION_HEIGHT, camera.y/tileSheet.GetTileH()) - REGION_HEIGHT; + int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT; + //prune distant regions for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) { - if (CheckBufferDistance(*it) > 2) { - regionPager.UnloadRegion((*it)->GetX(), (*it)->GetY()); + //check if the region is outside off this area + if ((*it)->GetX() < xStart || (*it)->GetX() > xEnd || (*it)->GetY() < yStart || (*it)->GetY() > yEnd) { - //reset - it = regionPager.GetContainer()->begin(); + //clunky, but the alternative was time consuming + int tmpX = (*it)->GetX(); + int tmpY = (*it)->GetY(); + ++it; + + regionPager.UnloadRegion(tmpX, tmpY); continue; } ++it; } - //TODO: make the region units official? - int regionUnitX = REGION_WIDTH * tileSheet.GetTileW(); - int regionUnitY = REGION_HEIGHT * tileSheet.GetTileH(); - - //request empty regions, including buffers (-1 & +1 region unit) - for (int i = snapToBase(regionUnitX, camera.x - regionUnitX); i <= snapToBase(regionUnitX, camera.x + camera.width + regionUnitX); i += regionUnitX) { - for (int j = snapToBase(regionUnitY, camera.y - regionUnitY); j <= snapToBase(regionUnitY, camera.y + camera.height + regionUnitY); j += regionUnitY) { + //request empty regions within this zone + for (int i = xStart; i <= xEnd; i += REGION_WIDTH) { + for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) { if (!regionPager.FindRegion(i, j)) { RequestRegion(i, j); } diff --git a/client/scenes/in_world.hpp b/client/scenes/in_world.hpp index 899ee8a..bb0cc5c 100644 --- a/client/scenes/in_world.hpp +++ b/client/scenes/in_world.hpp @@ -86,7 +86,6 @@ protected: void RequestRegion(int x, int y); //utilities - int CheckBufferDistance(Region* const); void UpdateMap(); //globals diff --git a/common/graphics/tile_sheet.cpp b/common/graphics/tile_sheet.cpp index e1b9ea2..bb9a4cb 100644 --- a/common/graphics/tile_sheet.cpp +++ b/common/graphics/tile_sheet.cpp @@ -53,8 +53,8 @@ void TileSheet::DrawRegionTo(SDL_Surface* const dest, Region* const region, int image.SetClipX((tile-1) % XCount * image.GetClipW()); image.SetClipY((tile-1) / XCount * image.GetClipH()); image.DrawTo(dest, - region->GetX() + i * image.GetClipW() - camX, - region->GetY() + j * image.GetClipH() - camY); + (region->GetX() + i) * image.GetClipW() - camX, + (region->GetY() + j) * image.GetClipH() - camY); } } } diff --git a/common/map/region_pager.hpp b/common/map/region_pager.hpp index 9b3b991..95864f0 100644 --- a/common/map/region_pager.hpp +++ b/common/map/region_pager.hpp @@ -109,10 +109,7 @@ public: for (std::list::iterator it = regionList.begin(); it != regionList.end(); /* EMPTY */) { if ((*it)->GetX() == x && (*it)->GetY() == y) { allocator.Unload(*it); - regionList.erase(it); - - //reset the loop, because of reasons - it = regionList.begin(); + it = regionList.erase(it); continue; } ++it;