From 7cd515fcfa1a5aac5605fcc63381033563fbf5d7 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Mon, 14 Mar 2022 14:11:05 -0400 Subject: map is now "infinite" using chunks that dynamically load like in diamond&pearl game is also slow as shit now --- src/consts.h | 4 +- src/game.cpp | 123 +++++++++++-------------------------- src/game.h | 40 +----------- src/main.cpp | 2 +- src/map.h | 184 +++++++++++++++++++++++++++++++++++++++++++++++-------- src/renderer.cpp | 83 ++++++++++++++++--------- 6 files changed, 256 insertions(+), 180 deletions(-) diff --git a/src/consts.h b/src/consts.h index 141838b..78312c0 100644 --- a/src/consts.h +++ b/src/consts.h @@ -5,9 +5,11 @@ constexpr int GAME_WIDTH = 1280;//640*2; constexpr int GAME_HEIGHT = 720;//480*2; constexpr int TILE_WIDTH = 8*2; constexpr int TILE_HEIGHT = TILE_WIDTH; -constexpr int INIT_ZOOM = 5; +constexpr int INIT_ZOOM = 2; constexpr int ZOOM_X_FACTOR = 16; constexpr int ZOOM_Y_FACTOR = 9; +constexpr int CHUNK_WIDTH = 80; +constexpr int CHUNK_HEIGHT = 80; constexpr int RADIUS = 8; constexpr int NUM_TITLES = 1; diff --git a/src/game.cpp b/src/game.cpp index a7c94db..62e755b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -8,25 +8,11 @@ Game::Game(std::mt19937& rng, Muxer& muxer) : rng(rng), - muxer(muxer), - map( - -INIT_ZOOM * ZOOM_X_FACTOR / 2, - -INIT_ZOOM * ZOOM_Y_FACTOR / 2, - INIT_ZOOM * ZOOM_X_FACTOR, - INIT_ZOOM * ZOOM_Y_FACTOR) + muxer(muxer) { losePopLampTimer.accumulate(losePopLampTimer.getDt()); - for (MapData& md : map.data()) - { - if (std::bernoulli_distribution(0.5)(rng)) - { - md.tile = Tile::Wall; - } - } - - tick(); - tick(); + loadMap(); for (int y = -1; y <= 1; y++) { @@ -39,12 +25,12 @@ Game::Game(std::mt19937& rng, Muxer& muxer) : tick(); } -inline bool isTileSetOrNotLit(const Map& map, int x, int y) +inline bool isTileSetOrNotLit(const Map& map, int x, int y) { return (map.inBounds(x, y) && (map.at(x,y).tile == Tile::Wall || !map.at(x,y).lit)); } -inline bool isTileSet(const Map& map, int x, int y, Tile val = Tile::Wall) +inline bool isTileSet(const Map& map, int x, int y, Tile val = Tile::Wall) { return (map.inBounds(x, y) && map.at(x,y).tile == val); } @@ -69,7 +55,7 @@ void Game::tick( bool invert, bool onlyDark) { - Map temp(map); + std::vector temp(map.data()); for (int y = map.getTop(); y < map.getBottom(); y++) { @@ -102,21 +88,22 @@ void Game::tick( incrementIfSet(*this, count, x+1, y ); incrementIfSet(*this, count, x+1, y+1); + int tempIndex = map.getTrueX(x) + map.getTrueY(y) * map.getWidth(); if (count >= 5) { - temp.at(x,y).tile = Tile::Wall; + temp[tempIndex].tile = Tile::Wall; } else { - temp.at(x,y).tile = Tile::Floor; + temp[tempIndex].tile = Tile::Floor; } - if (temp.at(x,y).tile != map.at(x,y).tile) { - temp.at(x,y).dirtyRender = true; + if (temp[tempIndex].tile != map.at(x,y).tile) { + temp[tempIndex].dirtyRender = true; dirtyRender = true; } } } - map = std::move(temp); + map.data() = std::move(temp); } void Game::tick(bool onlyDark) @@ -132,10 +119,10 @@ void Game::tick(bool onlyDark) bool Game::movePlayer(int x, int y) { - if (x >= curBoundX && + if (/*x >= curBoundX && y >= curBoundY && x < curBoundX + curZoom * ZOOM_X_FACTOR && - y < curBoundY + curZoom * ZOOM_Y_FACTOR && + y < curBoundY + curZoom * ZOOM_Y_FACTOR &&*/ map.at(x,y).tile == Tile::Floor) { if (map.at(player_x, player_y).tile == Tile::Floor) @@ -154,6 +141,13 @@ bool Game::movePlayer(int x, int y) moveProgress.start(66); dirtyLighting = true; + int chunkX, chunkY, old_chunkX, old_chunkY; + toChunkPos(player_x, player_y, chunkX, chunkY); + toChunkPos(player_oldx, player_oldy, old_chunkX, old_chunkY); + if ((chunkX != old_chunkX) || (chunkY != old_chunkY)) { + loadMap(); + } + return true; } else { if (!alreadyBumped) { @@ -501,39 +495,25 @@ void Game::processKickup() }); } -void Game::growMap(size_t zoom) -{ - int ol = map.getLeft(); - int ot = map.getTop(); - int ow = map.getWidth(); - int oh = map.getHeight(); +void Game::loadMap() { + int newChunksHoriz = std::ceil(static_cast(curZoom) * ZOOM_X_FACTOR / CHUNK_WIDTH) + 4; + int newChunksVert = std::ceil(static_cast(curZoom) * ZOOM_Y_FACTOR / CHUNK_HEIGHT) + 4; + int curPlayerChunkX, curPlayerChunkY; + toChunkPos(player_x, player_y, curPlayerChunkX, curPlayerChunkY); - map.resize( - -zoom * ZOOM_X_FACTOR / 2, - -zoom * ZOOM_Y_FACTOR / 2, - zoom * ZOOM_X_FACTOR, - zoom * ZOOM_Y_FACTOR); + map.load( + curPlayerChunkX - newChunksHoriz / 2, + curPlayerChunkY - newChunksVert / 2, + newChunksHoriz, + newChunksVert, + rng); - maxZoom = zoom; - - for (int y = map.getTop(); y < map.getBottom(); y++) - { - for (int x = map.getLeft(); x < map.getRight(); x++) - { - if (!(x >= ol && x < (ol + ow) && y >= ot && y < (ot + oh))) - { - if (std::bernoulli_distribution(0.5)(rng)) - { - map.at(x,y).tile = Tile::Wall; - } - } - } - } + tick(); + tick(); + tick(); - for (int i = 0; i < 3; i++) - { - tick(ol, ot, ol + ow, ot + oh, true); - } + dirtyLighting = true; + dirtyRender = true; } void Game::setZoom(size_t zoom) @@ -543,40 +523,11 @@ void Game::setZoom(size_t zoom) return; } - if (zoom > maxZoom) - { - growMap(zoom); - } - - std::tie( - lastZoomLeft, - lastZoomTop, - lastZoomWidth, - lastZoomHeight) = - Renderer::calculateZoomRect(*this); - zoomProgress = 0; zoomLength = std::abs(static_cast(zoom - curZoom)) * TILE_WIDTH; curZoom = zoom; zooming = true; - - curBoundX = player_x - zoom * ZOOM_X_FACTOR / 2; - if (curBoundX < map.getLeft()) - { - curBoundX = map.getLeft(); - } else if (curBoundX + zoom * ZOOM_X_FACTOR >= map.getRight()) - { - curBoundX = map.getRight() - zoom * ZOOM_X_FACTOR; - } - - curBoundY = player_y - zoom * ZOOM_Y_FACTOR / 2; - if (curBoundY < map.getTop()) - { - curBoundY = map.getTop(); - } else if (curBoundY + zoom * ZOOM_Y_FACTOR >= map.getBottom()) - { - curBoundY = map.getBottom() - zoom * ZOOM_Y_FACTOR; - } + loadMap(); int zoomLevel = getZoomLevel(*this); if (zoomLevel == 0) { diff --git a/src/game.h b/src/game.h index 446680a..40ace3d 100644 --- a/src/game.h +++ b/src/game.h @@ -16,20 +16,6 @@ constexpr int TilesetIndex(int x, int y) { return x + y * 24; } -enum class Tile { - Floor, - Wall, - Dust, - Lamp -}; - -enum class Source { - None, - Dust, - Lamp, - Player -}; - enum class LoseState { None, PoppingLamps, @@ -52,8 +38,6 @@ struct Input { } }; -using coord = std::tuple; - struct Kickup { int x; int y; @@ -64,18 +48,6 @@ struct Kickup { std::set front; }; -struct MapData { - Tile tile = Tile::Floor; - bool lit = false; - bool wasLit = false; - size_t dustLife = 0; - Source lightType = Source::None; - int lightRadius = 0; - std::set litTiles; - int renderId = -1; - bool dirtyRender = true; -}; - class Game { public: @@ -89,7 +61,7 @@ public: bool quit = false; LoseState losing = LoseState::None; - Map map; + Map map; std::list kickups; int litSpots = 0; bool dirtyLighting = true; @@ -105,18 +77,10 @@ public: Animation playerAnim {"../res/player_anim.txt"}; int maxZoom = INIT_ZOOM; - int curZoom = INIT_ZOOM; - int curBoundX = map.getLeft(); - int curBoundY = map.getTop(); - bool zooming = false; int zoomProgress = 0; int zoomLength; - int lastZoomTop; - int lastZoomLeft; - int lastZoomWidth; - int lastZoomHeight; Input keystate; bool firstInput = false; @@ -159,7 +123,7 @@ private: void processKickup(); - void growMap(size_t zoom); + void loadMap(); void setZoom(size_t zoom); diff --git a/src/main.cpp b/src/main.cpp index 4ae11d6..0d14986 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,7 +23,7 @@ int main(int, char**) Game game(rng, muxer); - constexpr int titleFadeLen = 3000; + constexpr int titleFadeLen = 2000; bool doneTitles = false; int titleNum = 0; TitleState titleState = TitleState::FadeIn; diff --git a/src/map.h b/src/map.h index 329553c..d28b8d4 100644 --- a/src/map.h +++ b/src/map.h @@ -3,23 +3,62 @@ #include #include +#include +#include +#include +#include +#include "consts.h" -template -class Map { -public: +using coord = std::tuple; - Map( - int left, - int top, - int width, - int height) : - left_(left), - top_(top), - width_(width), - height_(height), - data_(width_*height_) - { +enum class Tile { + Floor, + Wall, + Dust, + Lamp +}; + +enum class Source { + None, + Dust, + Lamp, + Player +}; + +struct MapData { + Tile tile = Tile::Floor; + bool lit = false; + bool wasLit = false; + size_t dustLife = 0; + Source lightType = Source::None; + int lightRadius = 0; + std::set litTiles; + int renderId = -1; + bool dirtyRender = true; +}; + +struct Chunk { + std::array data; + int litTiles = 0; + int x; + int y; +}; + +inline void toChunkPos(int x, int y, int& cx, int& cy) { + cx = x / CHUNK_WIDTH; + cy = y / CHUNK_HEIGHT; + if (x < 0) { + cx *= -1; + cx--; + } + if (y < 0) { + cy *= -1; + cy--; } +} + +class Map { +public: inline int getLeft() const { @@ -69,27 +108,27 @@ public: (y < top_ + height_); } - inline const T& at(int x, int y) const + inline const MapData& at(int x, int y) const { - return data_.at((x - left_) + width_ * (y - top_)); + return loaded_.at((x - left_) + width_ * (y - top_)); } - inline T& at(int x, int y) + inline MapData& at(int x, int y) { - return const_cast(static_cast(*this).at(x, y)); + return const_cast(static_cast(*this).at(x, y)); } - inline const std::vector& data() const + inline const std::vector& data() const { - return data_; + return loaded_; } - inline std::vector& data() + inline std::vector& data() { - return data_; + return loaded_; } - void resize(int newLeft, int newTop, int newWidth, int newHeight) + /*void resize(int newLeft, int newTop, int newWidth, int newHeight) { std::vector newData(newWidth * newHeight); @@ -112,6 +151,96 @@ public: width_ = newWidth; height_ = newHeight; data_.swap(newData); + }*/ + + void load(int newLeftChunk, int newTopChunk, int newWidthChunks, int newHeightChunks, std::mt19937& rng) { + // Flush the currently loaded data as long as there is any (this isn't the first load). + if (!loaded_.empty()) { + std::vector touchedChunks; + + for (int chunkY = 0; chunkY < chunksVert_; chunkY++) { + for (int chunkX = 0; chunkX < chunksHoriz_; chunkX++) { + size_t chunkIndex = chunkByPos_.at(leftmostChunk_ + chunkX).at(topmostChunk_ + chunkY); + touchedChunks.push_back(chunkIndex); + + Chunk& chunk = chunks_.at(chunkIndex); + chunk.litTiles = 0; + + int startX = chunkX * CHUNK_WIDTH; + int startY = chunkY * CHUNK_HEIGHT; + for (int y=0; y(width_ * height_); + + // Load in the requested chunks. + for (int chunkY = 0; chunkY < chunksVert_; chunkY++) { + for (int chunkX = 0; chunkX < chunksHoriz_; chunkX++) { + // Instantiate a new chunk if necessary. + if (!chunkByPos_[leftmostChunk_ + chunkX].count(topmostChunk_ + chunkY)) { + size_t chunkIndex; + if (!freeList_.empty()) { + chunkIndex = freeList_.front(); + freeList_.pop_front(); + } else { + chunkIndex = chunks_.size(); + chunks_.emplace_back(); + } + chunkByPos_[leftmostChunk_ + chunkX][topmostChunk_ + chunkY] = chunkIndex; + + Chunk& chunk = chunks_[chunkIndex]; + chunk.x = leftmostChunk_ + chunkX; + chunk.y = topmostChunk_ + chunkY; + + for (MapData& md : chunk.data) + { + if (std::bernoulli_distribution(0.5)(rng)) + { + md.tile = Tile::Wall; + } else { + md.tile = Tile::Floor; + } + md.dirtyRender = true; + } + } + + size_t chunkIndex = chunkByPos_[leftmostChunk_ + chunkX][topmostChunk_ + chunkY]; + Chunk& chunk = chunks_[chunkIndex]; + + for (int y = 0; y < CHUNK_HEIGHT; y++) { + std::copy( + std::next(std::begin(chunk.data), y*CHUNK_WIDTH), + std::next(std::begin(chunk.data), (y+1)*CHUNK_WIDTH), + std::next(std::begin(loaded_), (chunkY*CHUNK_HEIGHT + y)*width_ + chunkX*CHUNK_WIDTH)); + } + } + } + } private: @@ -120,8 +249,15 @@ private: int top_; int width_; int height_; + int leftmostChunk_; + int topmostChunk_; + int chunksHoriz_; + int chunksVert_; + std::vector loaded_; - std::vector data_; + std::vector chunks_; + std::list freeList_; + std::map> chunkByPos_; // chunkByPos_[X][Y] }; #endif /* end of include guard: MAP_H_3AB00D12 */ diff --git a/src/renderer.cpp b/src/renderer.cpp index 9ef8bb9..1f51e0a 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -12,7 +12,7 @@ Renderer::Renderer() GAME_HEIGHT, SDL_WINDOW_SHOWN)); - SDL_SetWindowFullscreen(win_.get(), SDL_WINDOW_FULLSCREEN_DESKTOP); + //SDL_SetWindowFullscreen(win_.get(), SDL_WINDOW_FULLSCREEN_DESKTOP); if (!win_) { @@ -115,13 +115,16 @@ void Renderer::renderGame( const Game& game, bool drawDark) { + int windowTileWidth = game.curZoom * ZOOM_X_FACTOR + 2; + int windowTileHeight = game.curZoom * ZOOM_Y_FACTOR + 2; + texture_ptr canvas( SDL_CreateTexture( ren_.get(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, - TILE_WIDTH * game.map.getWidth(), - TILE_HEIGHT * game.map.getHeight())); + windowTileWidth * TILE_WIDTH, + windowTileHeight * TILE_HEIGHT)); if (!canvas) { @@ -133,15 +136,17 @@ void Renderer::renderGame( SDL_SetRenderDrawColor(ren_.get(), rand() % 255, rand() % 255, rand() % 255, 255); SDL_RenderClear(ren_.get()); - for (int y = game.map.getTop(); y < game.map.getBottom(); y++) + int leftmost = game.player_x - game.curZoom * ZOOM_X_FACTOR / 2 - 1; + int topmost = game.player_y - game.curZoom * ZOOM_Y_FACTOR / 2 - 1; + for (int y = topmost; y < topmost + windowTileHeight; y++) { - for (int x = game.map.getLeft(); x < game.map.getRight(); x++) + for (int x = leftmost; x < leftmost + windowTileWidth; x++) { bool draw = true; bool drawColour = false; SDL_Rect rect { - game.map.getTrueX(x) * TILE_WIDTH, - game.map.getTrueY(y) * TILE_HEIGHT, + (x - leftmost) * TILE_WIDTH, + (y - topmost) * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; @@ -190,14 +195,14 @@ void Renderer::renderGame( if (game.renderPlayer) { SDL_Rect rect { - game.map.getTrueX(game.player_x) * TILE_WIDTH, - game.map.getTrueY(game.player_y) * TILE_HEIGHT, + (game.player_x - leftmost) * TILE_WIDTH, + (game.player_y - topmost) * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; if (game.moving) { - rect.x = game.moveProgress.getProgress(game.map.getTrueX(game.player_oldx) * TILE_WIDTH, rect.x); - rect.y = game.moveProgress.getProgress(game.map.getTrueY(game.player_oldy) * TILE_HEIGHT, rect.y); + rect.x = game.moveProgress.getProgress((game.player_oldx - leftmost) * TILE_WIDTH, rect.x); + rect.y = game.moveProgress.getProgress((game.player_oldy - topmost) * TILE_HEIGHT, rect.y); } SDL_RenderCopy(ren_.get(), playerSheet_.get(), &game.playerAnim.getRenderRect(), &rect); @@ -208,8 +213,8 @@ void Renderer::renderGame( ren_.get(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, - TILE_WIDTH * game.map.getWidth(), - TILE_HEIGHT * game.map.getHeight())); + windowTileWidth * TILE_WIDTH, + windowTileHeight * TILE_HEIGHT)); if (!mask) { @@ -220,9 +225,9 @@ void Renderer::renderGame( SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, 0); SDL_RenderClear(ren_.get()); - for (int y = game.map.getTop(); y < game.map.getBottom(); y++) + for (int y = topmost; y < topmost + windowTileHeight; y++) { - for (int x = game.map.getLeft(); x < game.map.getRight(); x++) + for (int x = leftmost; x < leftmost + windowTileWidth; x++) { if (game.map.at(x,y).lightType != Source::None) { @@ -231,8 +236,8 @@ void Renderer::renderGame( ren_.get(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, - TILE_WIDTH * game.map.getWidth(), - TILE_HEIGHT * game.map.getHeight())); + windowTileWidth * TILE_WIDTH, + windowTileHeight * TILE_HEIGHT)); if (!sourceMask) { @@ -244,11 +249,11 @@ void Renderer::renderGame( SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, 0); SDL_RenderClear(ren_.get()); - int posToUseX = game.map.getTrueX(x); - int posToUseY = game.map.getTrueY(y); + int posToUseX = x - leftmost; + int posToUseY = y - topmost; if (game.map.at(x,y).lightType == Source::Player && game.moving) { - posToUseX = game.moveProgress.getProgress(game.map.getTrueX(game.player_oldx), posToUseX); - posToUseY = game.moveProgress.getProgress(game.map.getTrueY(game.player_oldy), posToUseY); + posToUseX = game.moveProgress.getProgress((game.player_oldx) - leftmost, posToUseX); + posToUseY = game.moveProgress.getProgress((game.player_oldy) - topmost, posToUseY); } int fadeX = posToUseX - game.map.at(x,y).lightRadius; @@ -283,8 +288,8 @@ void Renderer::renderGame( if (!game.map.at(x,y).litTiles.count({sx, sy})) { SDL_Rect rect { - game.map.getTrueX(sx) * TILE_WIDTH, - game.map.getTrueY(sy) * TILE_HEIGHT, + (sx - leftmost) * TILE_WIDTH, + (sy - topmost) * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; @@ -306,10 +311,28 @@ void Renderer::renderGame( SDL_SetRenderTarget(ren_.get(), nullptr); - SDL_Rect zoomRect; + // TODO: this is just moving interp. we also need zoom + SDL_Rect zoomRect { + TILE_WIDTH, TILE_HEIGHT, (windowTileWidth - 2) * TILE_WIDTH, (windowTileHeight - 2) * TILE_HEIGHT + }; + + if (game.moving) { + double interp = + static_cast(game.zoomProgress) / + static_cast(game.zoomLength); + + if (game.player_x > game.player_oldx) { + zoomRect.x = game.moveProgress.getProgress(0, TILE_WIDTH); + } else if (game.player_x < game.player_oldx) { + zoomRect.x = game.moveProgress.getProgress(2*TILE_WIDTH, TILE_WIDTH); + } - std::tie(zoomRect.x, zoomRect.y, zoomRect.w, zoomRect.h) = - calculateZoomRect(game); + if (game.player_y > game.player_oldy) { + zoomRect.y = game.moveProgress.getProgress(0, TILE_HEIGHT); + } else if (game.player_y < game.player_oldy) { + zoomRect.y = game.moveProgress.getProgress(TILE_HEIGHT*2, TILE_HEIGHT); + } + } SDL_RenderCopy(ren_.get(), canvas.get(), &zoomRect, nullptr); SDL_RenderPresent(ren_.get()); @@ -358,12 +381,12 @@ void Renderer::renderTitle(int num, double fade) { std::tuple Renderer::calculateZoomRect(const Game& game) { - int x = game.map.getTrueX(game.curBoundX) * TILE_WIDTH; - int y = game.map.getTrueY(game.curBoundY) * TILE_HEIGHT; int w = game.curZoom * TILE_WIDTH * ZOOM_X_FACTOR; int h = game.curZoom * TILE_HEIGHT * ZOOM_Y_FACTOR; + int x = (game.map.getTrueX(game.player_x) * TILE_WIDTH) - (w / 2); + int y = (game.map.getTrueY(game.player_y) * TILE_HEIGHT) - (h / 2); - if (game.zooming) + /*if (game.zooming) { double interp = static_cast(game.zoomProgress) / @@ -373,7 +396,7 @@ std::tuple Renderer::calculateZoomRect(const Game& game) y = (y - game.lastZoomTop) * interp + game.lastZoomTop; w = (w - game.lastZoomWidth) * interp + game.lastZoomWidth; h = (h - game.lastZoomHeight) * interp + game.lastZoomHeight; - } + }*/ return {x, y, w, h}; } -- cgit 1.4.1