From c055e37e57ff365f5ae62d265d4b2140fbdc348a Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Tue, 29 May 2018 21:57:33 -0400 Subject: abstracted map data into a class to allow for zooming out --- src/main.cpp | 366 ++++++++++++++++++++++++++++++----------------------------- src/map.h | 127 +++++++++++++++++++++ 2 files changed, 316 insertions(+), 177 deletions(-) create mode 100644 src/map.h (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index c39cdb6..9534678 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,7 @@ #include #include #include "util.h" +#include "map.h" class sdl_error : public std::logic_error { public: @@ -75,49 +76,51 @@ struct Kickup { size_t chain; }; -class Map { +struct MapData { + Tile tile = Tile::Floor; + bool lit = false; + bool wasLit = false; + double visibility = 0.0; +}; + +class Game { public: - Map() : - tiles(VIEW_WIDTH*VIEW_HEIGHT, Tile::Floor), - lighting(VIEW_WIDTH*VIEW_HEIGHT, false), - lightStrength(VIEW_WIDTH*VIEW_HEIGHT, 0.0) + Game() : + map(-VIEW_WIDTH/2, -VIEW_HEIGHT/2, VIEW_WIDTH, VIEW_HEIGHT) { } - std::vector tiles; - std::vector lighting; - std::vector oldLighting; - std::vector lightStrength; + Map map; std::list kickups; int lightedSpots = 0; bool dirtyLighting = true; size_t numLamps = 0; size_t numDust = 0; -}; -int player_x = VIEW_WIDTH / 2; -int player_y = VIEW_HEIGHT / 2; -bool renderPlayer = true; + int player_x = 0; + int player_y = 0; + bool renderPlayer = true; +}; void render( SDL_Renderer* ren, - const Map& map, + const Game& game, bool drawDark = true) { SDL_SetRenderDrawColor(ren, rand() % 255, rand() % 255, rand() % 255, 255); SDL_RenderClear(ren); - for (int y = 0; y < VIEW_HEIGHT; y++) + for (int y = game.map.getTop(); y < game.map.getBottom(); y++) { - for (int x = 0; x < VIEW_WIDTH; x++) + for (int x = game.map.getLeft(); x < game.map.getRight(); x++) { bool draw = true; - if ((player_x == x && player_y == y) && renderPlayer) + if ((game.player_x == x && game.player_y == y) && game.renderPlayer) { SDL_SetRenderDrawColor(ren, 255, 255, 0, 255); - } else if (!map.lighting.at(x+VIEW_WIDTH*y)) + } else if (!game.map.at(x,y).lit) { if (drawDark) { @@ -126,7 +129,7 @@ void render( draw = false; } } else { - switch (map.tiles.at(x+y*VIEW_WIDTH)) + switch (game.map.at(x,y).tile) { case Tile::Floor: { @@ -156,10 +159,15 @@ void render( if (draw) { - SDL_Rect rect{x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; + SDL_Rect rect { + game.map.getTrueX(x) * TILE_WIDTH, + game.map.getTrueY(y) * TILE_HEIGHT, + TILE_WIDTH, + TILE_HEIGHT}; + SDL_RenderFillRect(ren, &rect); - int alpha = (1.0 - map.lightStrength.at(x+y*VIEW_WIDTH)) * 255; + int alpha = (1.0 - game.map.at(x,y).visibility) * 255; SDL_SetRenderDrawColor(ren, 40, 40, 40, alpha); SDL_RenderFillRect(ren, &rect); } @@ -169,115 +177,132 @@ void render( SDL_RenderPresent(ren); } -void incrementIfSet(Map& map, int& count, int x, int y, int w, int h, Tile val = Tile::Wall) +void incrementIfSet(Game& game, int& count, int x, int y, Tile val = Tile::Wall) { - if ((x >= 0) && (x < w) && (y >= 0) && (y < h) && (map.tiles[x+w*y] == val)) + if (game.map.inBounds(x, y) && game.map.at(x,y).tile == val) { count++; } } -void tick(Map& map, int x1 = 0, int y1 = 0, int x2 = VIEW_WIDTH, int y2 = VIEW_HEIGHT, bool onlyDark = false) +void tick( + Game& game, + int x1, + int y1, + int x2, + int y2, + bool invert = false, + bool onlyDark = false) { - std::vector temp(map.tiles); + Map temp(game.map); - for (int y = std::max(y1, 0); y < std::min(y2, VIEW_HEIGHT); y++) + for (int y = game.map.getTop(); y < game.map.getBottom(); y++) { - for (int x = std::max(x1, 0); x < std::min(x2, VIEW_WIDTH); x++) + for (int x = game.map.getLeft(); x < game.map.getRight(); x++) { - if (onlyDark && map.lighting[x+y*VIEW_WIDTH]) + if (invert == (x >= x1 && x < x2 && y >= y1 && y < y2)) + { + continue; + } + + if (onlyDark && game.map.at(x,y).lit) { continue; } - if (map.tiles[x+y*VIEW_WIDTH] == Tile::Lamp) + if (game.map.at(x,y).tile == Tile::Lamp) { continue; } int count = 0; - incrementIfSet(map, count, x-1, y-1, VIEW_WIDTH, VIEW_HEIGHT); - incrementIfSet(map, count, x-1, y , VIEW_WIDTH, VIEW_HEIGHT); - incrementIfSet(map, count, x-1, y+1, VIEW_WIDTH, VIEW_HEIGHT); - incrementIfSet(map, count, x , y-1, VIEW_WIDTH, VIEW_HEIGHT); - incrementIfSet(map, count, x , y , VIEW_WIDTH, VIEW_HEIGHT); - incrementIfSet(map, count, x , y+1, VIEW_WIDTH, VIEW_HEIGHT); - incrementIfSet(map, count, x+1, y-1, VIEW_WIDTH, VIEW_HEIGHT); - incrementIfSet(map, count, x+1, y , VIEW_WIDTH, VIEW_HEIGHT); - incrementIfSet(map, count, x+1, y+1, VIEW_WIDTH, VIEW_HEIGHT); + incrementIfSet(game, count, x-1, y-1); + incrementIfSet(game, count, x-1, y ); + incrementIfSet(game, count, x-1, y+1); + incrementIfSet(game, count, x , y-1); + incrementIfSet(game, count, x , y ); + incrementIfSet(game, count, x , y+1); + incrementIfSet(game, count, x+1, y-1); + incrementIfSet(game, count, x+1, y ); + incrementIfSet(game, count, x+1, y+1); if (count >= 5) { - temp[x+VIEW_WIDTH*y] = Tile::Wall; + temp.at(x,y).tile = Tile::Wall; } else { - temp[x+VIEW_WIDTH*y] = Tile::Floor; + temp.at(x,y).tile = Tile::Floor; } } } - map.tiles = temp; + game.map = std::move(temp); +} + +void tick(Game& game, bool onlyDark = false) +{ + tick( + game, + game.map.getLeft(), + game.map.getTop(), + game.map.getRight(), + game.map.getBottom(), + false, + onlyDark); } -void movePlayer(int x, int y, Map& map) +void movePlayer(Game& game, int x, int y) { - if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT) && - map.tiles[x+VIEW_WIDTH*y] == Tile::Floor) + if (game.map.inBounds(x, y) && game.map.at(x,y).tile == Tile::Floor) { - if (map.tiles[player_x+player_y*VIEW_WIDTH] == Tile::Floor) + if (game.map.at(game.player_x, game.player_y).tile == Tile::Floor) { - map.tiles[player_x+player_y*VIEW_WIDTH] = Tile::Dust; - map.numDust++; + game.map.at(game.player_x, game.player_y).tile = Tile::Dust; + game.numDust++; } - player_x = x; - player_y = y; + game.player_x = x; + game.player_y = y; - map.dirtyLighting = true; + game.dirtyLighting = true; } } -void setIfValid(Map& map, int x, int y, Tile val) +void recalculateLighting(Game& game, fov_settings_type* fov) { - if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT)) + game.lightedSpots = 0; + + for (MapData& md : game.map.data()) { - map.tiles[x+VIEW_WIDTH*y] = val; + md.wasLit = md.lit; + md.lit = false; + md.visibility = 0.0; } -} - -void recalculateLighting(Map& map, fov_settings_type* fov) -{ - map.oldLighting = map.lighting; - map.lighting = std::vector(VIEW_WIDTH*VIEW_HEIGHT, false); - map.lightStrength = std::vector(VIEW_WIDTH*VIEW_HEIGHT, 0.0); - map.lightedSpots = 0; fov_settings_set_opacity_test_function( fov, - [] (void* map, int x, int y) { - return - x >= 0 && - x < VIEW_WIDTH && - y >= 0 && - y < VIEW_HEIGHT && - static_cast(map)->tiles.at(x+VIEW_WIDTH*y) == Tile::Wall; + [] (void* data, int x, int y) { + Game& game = *static_cast(data); + + return game.map.inBounds(x,y) && game.map.at(x,y).tile == Tile::Wall; }); fov_settings_set_apply_lighting_function( fov, - [] (void* map, int x, int y, int dx, int dy, void*) { - if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT)) + [] (void* data, int x, int y, int dx, int dy, void*) { + Game& game = *static_cast(data); + + if (game.map.inBounds(x, y)) { - Map& m = *static_cast(map); - if (!m.lighting[x+VIEW_WIDTH*y]) + if (!game.map.at(x,y).lit) { - m.lightedSpots++; + game.lightedSpots++; } - m.lighting[x+VIEW_WIDTH*y] = true; + game.map.at(x,y).lit = true; - m.lightStrength[x+VIEW_WIDTH*y] = std::max( - m.lightStrength[x+VIEW_WIDTH*y], + game.map.at(x,y).visibility = std::max( + game.map.at(x,y).visibility, std::pow( std::max( 0.0, @@ -286,29 +311,29 @@ void recalculateLighting(Map& map, fov_settings_type* fov) } }); - for (int y = 0; y < VIEW_HEIGHT; y++) + for (int y = game.map.getTop(); y < game.map.getBottom(); y++) { - for (int x = 0; x < VIEW_WIDTH; x++) + for (int x = game.map.getLeft(); x < game.map.getRight(); x++) { - if ((player_x == x && player_y == y && renderPlayer) || - map.tiles[x+VIEW_WIDTH*y] == Tile::Dust || - map.tiles[x+VIEW_WIDTH*y] == Tile::Lamp) + if ((game.player_x == x && game.player_y == y && game.renderPlayer) || + game.map.at(x,y).tile == Tile::Dust || + game.map.at(x,y).tile == Tile::Lamp) { - fov_circle(fov, static_cast(&map), nullptr, x, y, RADIUS); + fov_circle(fov, static_cast(&game), nullptr, x, y, RADIUS); - map.lighting[x+VIEW_WIDTH*y] = true; - map.lightStrength[x+VIEW_WIDTH*y] = 1.0; + game.map.at(x,y).lit = true; + game.map.at(x,y).visibility = 1.0; } } } - map.dirtyLighting = false; + game.dirtyLighting = false; } -void processKeys(Map& map, const Input& keystate) +void processKeys(Game& game, const Input& keystate) { - int px = player_x; - int py = player_y; + int px = game.player_x; + int py = game.player_y; if (keystate.up) { @@ -330,13 +355,13 @@ void processKeys(Map& map, const Input& keystate) px++; } - if (!(player_x == px && player_y == py)) + if (!(game.player_x == px && game.player_y == py)) { - movePlayer(px, py, map); + movePlayer(game, px, py); } } -void kickUpDust(Map& map, int x, int y, size_t chain) +void kickUpDust(Game& game, int x, int y, size_t chain) { Kickup dk; dk.x = x; @@ -345,71 +370,67 @@ void kickUpDust(Map& map, int x, int y, size_t chain) dk.cur = 0; dk.radius = RADIUS + (chain + 1) * (chain + 1); - map.kickups.push_back(dk); + game.kickups.push_back(dk); } -void popLamp(Map& map, int x, int y, size_t chain) +void popLamp(Game& game, int x, int y, size_t chain) { - if (map.tiles[x+VIEW_WIDTH*y] == Tile::Lamp) + if (game.map.at(x,y).tile == Tile::Lamp) { - map.numLamps--; + game.numLamps--; } - map.tiles[x+VIEW_WIDTH*y] = Tile::Dust; - map.numDust++; - map.dirtyLighting = true; + game.map.at(x,y).tile = Tile::Dust; + game.numDust++; + game.dirtyLighting = true; - kickUpDust(map, x, y, chain); + kickUpDust(game, x, y, chain); } -void processKickup(Map& map) +void processKickup(Game& game) { - for (Kickup& kickup : map.kickups) + for (Kickup& kickup : game.kickups) { kickup.cur++; - if (map.tiles[kickup.x+VIEW_WIDTH*kickup.y] == Tile::Floor) + if (game.map.at(kickup.x, kickup.y).tile == Tile::Floor) { - map.tiles[kickup.x+VIEW_WIDTH*kickup.y] = Tile::Dust; - map.numDust++; + game.map.at(kickup.x, kickup.y).tile = Tile::Dust; + game.numDust++; } std::unique_ptr dusty(new fov_settings_type); fov_settings_set_opacity_test_function( dusty.get(), - [] (void* map, int x, int y) { - return - x >= 0 && - x < VIEW_WIDTH && - y >= 0 && - y < VIEW_HEIGHT && - static_cast(map)->tiles.at(x+VIEW_WIDTH*y) == Tile::Wall; + [] (void* data, int x, int y) { + Game& game = *static_cast(data); + + return game.map.inBounds(x,y) && game.map.at(x,y).tile == Tile::Wall; }); fov_settings_set_apply_lighting_function( dusty.get(), [] (void* data, int x, int y, int, int, void* source) { - Map& map = *static_cast(data); + Game& game = *static_cast(data); Kickup& kickup = *static_cast(source); - if ((x >= 0) && (x < VIEW_WIDTH) && - (y >= 0) && (y < VIEW_HEIGHT)) + if (game.map.inBounds(x,y)) { - if (map.tiles[x+VIEW_WIDTH*y] == Tile::Floor) + if (game.map.at(x,y).tile == Tile::Floor) { - map.tiles[x+VIEW_WIDTH*y] = Tile::Dust; - map.numDust++; - map.dirtyLighting = true; - } else if (map.tiles[x+VIEW_WIDTH*y] == Tile::Lamp) + game.map.at(x,y).tile = Tile::Dust; + game.numDust++; + game.dirtyLighting = true; + } else if (game.map.at(x,y).tile == Tile::Lamp) { - popLamp(map, x, y, kickup.chain + 1); + popLamp(game, x, y, kickup.chain + 1); } } }); fov_circle( dusty.get(), - static_cast(&map), + static_cast(&game), static_cast(&kickup), kickup.x, kickup.y, @@ -417,7 +438,7 @@ void processKickup(Map& map) } erase_if( - map.kickups, + game.kickups, [] (const Kickup& kickup) { return kickup.cur == kickup.radius; }); @@ -456,25 +477,22 @@ int main(int, char**) SDL_SetRenderDrawBlendMode(ren.get(), SDL_BLENDMODE_BLEND); - Map map; + Game game; std::unique_ptr fov(new fov_settings_type()); fov_settings_init(fov.get()); - for (int y = 0; y < VIEW_HEIGHT; y++) + for (MapData& md : game.map.data()) { - for (int x = 0; x < VIEW_WIDTH; x++) + if (std::bernoulli_distribution(0.5)(rng)) { - if (std::bernoulli_distribution(0.5)(rng)) - { - map.tiles[x+y*VIEW_WIDTH] = Tile::Wall; - } + md.tile = Tile::Wall; } } - tick(map); - tick(map); - tick(map); + tick(game); + tick(game); + tick(game); bool quit = false; LoseState losing = LoseState::None; @@ -531,26 +549,24 @@ int main(int, char**) { if (losing == LoseState::None) { - if (map.tiles[player_x+VIEW_WIDTH*player_y] == Tile::Floor) + if (game.map.at(game.player_x, game.player_y).tile == + Tile::Floor) { - map.tiles[player_x+VIEW_WIDTH*player_y] = Tile::Lamp; - map.numLamps++; - map.dirtyLighting = true; - kickUpDust(map, player_x, player_y, 0); + game.map.at(game.player_x, game.player_y).tile = Tile::Lamp; + game.numLamps++; + game.dirtyLighting = true; + kickUpDust(game, game.player_x, game.player_y, 0); for (int i = 0; i < 5; i++) { - processKeys(map, keystate); + processKeys(game, keystate); tick( - map, - player_x - (RADIUS - 1), - player_y - (RADIUS - 1), - player_x + RADIUS, - player_y + RADIUS); - - //render(ren.get(), map, false); - //SDL_Delay(30); + game, + game.player_x - (RADIUS - 1), + game.player_y - (RADIUS - 1), + game.player_x + RADIUS, + game.player_y + RADIUS); } } } @@ -572,21 +588,18 @@ int main(int, char**) while (dustAcc >= dustDt) { - for (int y = 0; y < VIEW_HEIGHT; y++) + for (MapData& md : game.map.data()) { - for (int x = 0; x < VIEW_WIDTH; x++) + if (md.tile == Tile::Dust) { - if (map.tiles[x+y*VIEW_WIDTH] == Tile::Dust) - { - map.tiles[x+y*VIEW_WIDTH] = Tile::Floor; - map.dirtyLighting = true; - } + md.tile = Tile::Floor; + game.dirtyLighting = true; } } - map.numDust = 0; + game.numDust = 0; - processKickup(map); + processKickup(game); dustAcc -= dustDt; } @@ -597,7 +610,7 @@ int main(int, char**) { while (inputAcc >= inputDt) { - processKeys(map, keystate); + processKeys(game, keystate); inputAcc -= inputDt; } @@ -607,9 +620,9 @@ int main(int, char**) case LoseState::PoppingLamps: { - if (map.numLamps == 0) + if (game.numLamps == 0) { - if (map.numDust == 0) + if (game.numDust == 0) { losing = LoseState::PoppingPlayer; } @@ -620,11 +633,11 @@ int main(int, char**) { std::vector> lamps; - for (int y = 0; y < VIEW_HEIGHT; y++) + for (int y = game.map.getTop(); y < game.map.getBottom(); y++) { - for (int x = 0; x < VIEW_WIDTH; x++) + for (int x = game.map.getLeft(); x < game.map.getRight(); x++) { - if (map.tiles[x+VIEW_WIDTH*y] == Tile::Lamp) + if (game.map.at(x,y).tile == Tile::Lamp) { lamps.emplace_back(x, y); } @@ -634,7 +647,7 @@ int main(int, char**) std::uniform_int_distribution lampDist(0, lamps.size() - 1); std::tuple popPos = lamps[lampDist(rng)]; - popLamp(map, std::get<0>(popPos), std::get<1>(popPos), 0); + popLamp(game, std::get<0>(popPos), std::get<1>(popPos), 0); losePopLampAcc -= losePopLampDt; } @@ -649,8 +662,8 @@ int main(int, char**) if (losePopPlayerAcc >= losePopPlayerDt) { - popLamp(map, player_x, player_y, 10); - renderPlayer = false; + popLamp(game, game.player_x, game.player_y, 10); + game.renderPlayer = false; losing = LoseState::Outro; } @@ -660,7 +673,7 @@ int main(int, char**) case LoseState::Outro: { - if (map.numDust == 0) + if (game.numDust == 0) { quit = true; } @@ -669,33 +682,32 @@ int main(int, char**) } } - if (map.dirtyLighting) + if (game.dirtyLighting) { - recalculateLighting(map, fov.get()); + recalculateLighting(game, fov.get()); - for (int y = 0; y < VIEW_HEIGHT; y++) + for (int y = game.map.getTop(); y < game.map.getBottom(); y++) { - for (int x = 0; x < VIEW_WIDTH; x++) + for (int x = game.map.getLeft(); x < game.map.getRight(); x++) { - if (!map.lighting[x+y*VIEW_WIDTH] && map.oldLighting[x+y*VIEW_WIDTH]) + if (!game.map.at(x,y).lit && game.map.at(x,y).wasLit) { if (std::bernoulli_distribution(0.5)(rng)) { - map.tiles[x+y*VIEW_WIDTH] = Tile::Wall; + game.map.at(x,y).tile = Tile::Wall; } else { - map.tiles[x+y*VIEW_WIDTH] = Tile::Floor; + game.map.at(x,y).tile = Tile::Floor; } } } } - tick(map, 0, 0, VIEW_WIDTH, VIEW_HEIGHT, true); - tick(map, 0, 0, VIEW_WIDTH, VIEW_HEIGHT, true); - tick(map, 0, 0, VIEW_WIDTH, VIEW_HEIGHT, true); + tick(game, true); + tick(game, true); + tick(game, true); } - render(ren.get(), map, true); - //SDL_Delay(50); + render(ren.get(), game, true); } } catch (const sdl_error& ex) { diff --git a/src/map.h b/src/map.h new file mode 100644 index 0000000..329553c --- /dev/null +++ b/src/map.h @@ -0,0 +1,127 @@ +#ifndef MAP_H_3AB00D12 +#define MAP_H_3AB00D12 + +#include +#include + +template +class Map { +public: + + Map( + int left, + int top, + int width, + int height) : + left_(left), + top_(top), + width_(width), + height_(height), + data_(width_*height_) + { + } + + inline int getLeft() const + { + return left_; + } + + inline int getRight() const + { + return left_ + width_; + } + + inline int getTop() const + { + return top_; + } + + inline int getBottom() const + { + return top_ + height_; + } + + inline int getWidth() const + { + return width_; + } + + inline int getHeight() const + { + return height_; + } + + inline int getTrueX(int x) const + { + return (x - left_); + } + + inline int getTrueY(int y) const + { + return (y - top_); + } + + inline bool inBounds(int x, int y) const + { + return (x >= left_) && + (x < left_ + width_) && + (y >= top_) && + (y < top_ + height_); + } + + inline const T& at(int x, int y) const + { + return data_.at((x - left_) + width_ * (y - top_)); + } + + inline T& at(int x, int y) + { + return const_cast(static_cast(*this).at(x, y)); + } + + inline const std::vector& data() const + { + return data_; + } + + inline std::vector& data() + { + return data_; + } + + void resize(int newLeft, int newTop, int newWidth, int newHeight) + { + std::vector newData(newWidth * newHeight); + + int winTop = std::max(top_, newTop); + int winBottom = std::min(top_ + height_, newTop + newHeight); + int winLeft = std::max(left_, newLeft); + int winRight = std::min(left_ + width_, newLeft + newWidth); + + for (int y = winTop; y < winBottom; y++) + { + std::move( + std::next(std::begin(data_), (winLeft - left_) + width_ * (y - top_)), + std::next(std::begin(data_), (winRight - left_) + width_ * (y - top_)), + std::next(std::begin(newData), + (winLeft - newLeft) + newWidth * (y - newTop))); + } + + left_ = newLeft; + top_ = newTop; + width_ = newWidth; + height_ = newHeight; + data_.swap(newData); + } + +private: + + int left_; + int top_; + int width_; + int height_; + + std::vector data_; +}; + +#endif /* end of include guard: MAP_H_3AB00D12 */ -- cgit 1.4.1