From f5297dfb66ced81b5e4991e8609d29bb88a8d028 Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Wed, 15 Jan 2025 17:42:28 +0100 Subject: [PATCH] Support multiple and custom levels --- src/block.hpp | 10 +++++++++- src/blockRegistry.hpp | 14 ++++++++++---- src/blockSettings.hpp | 22 ++++++++++++++++++++++ src/color.hpp | 16 ++++++++++++++++ src/main.cpp | 18 +++++++++++++----- src/movementHandler.hpp | 23 +++++++++++++++++++---- src/player.hpp | 8 ++++++++ worlds/{world.txt => 1.txt} | 0 worlds/2.txt | 15 +++++++++++++++ worlds/3.txt | 15 +++++++++++++++ 10 files changed, 127 insertions(+), 14 deletions(-) create mode 100644 src/color.hpp rename worlds/{world.txt => 1.txt} (100%) create mode 100644 worlds/2.txt create mode 100644 worlds/3.txt diff --git a/src/block.hpp b/src/block.hpp index 53d3283..991b6f8 100644 --- a/src/block.hpp +++ b/src/block.hpp @@ -1,16 +1,21 @@ #pragma once #include "identifier.hpp" +#include "color.hpp" #include "blockSettings.hpp" class Block { private: Identifier id = Identifier("adventure", "missing"); char encoding; + Color color; BlockSettings settings; + public: - Block(Identifier id, char encoding, BlockSettings settings) { + Block(Identifier id, char encoding, BlockSettings settings) : Block(id, encoding, Color::RESET, settings) {}; + Block(Identifier id, char encoding, Color color, BlockSettings settings) { this->id = id; this->encoding = encoding; + this->color = color; this->settings = settings; }; @@ -21,6 +26,9 @@ public: Identifier getId() { return id; } + Color getColor() { + return color; + } char getEncoding() { return encoding; } diff --git a/src/blockRegistry.hpp b/src/blockRegistry.hpp index e584a4a..51d82bc 100644 --- a/src/blockRegistry.hpp +++ b/src/blockRegistry.hpp @@ -9,17 +9,23 @@ using std::string; class BlockRegistry { public: Block AIR = Block(Identifier("adventura", "air"), ' ', BlockSettingsBuilder().nonSolid().build()); + Block WATER = Block(Identifier("adventura", "water"), '~', Color::BRIGHT_BLUE, BlockSettingsBuilder().nonSolid().build()); Block PLATFORM = Block(Identifier("adventura", "platform"), '-', BlockSettingsBuilder().build()); - Block LADDER = Block(Identifier("adventura", "ladder"), 'H', BlockSettingsBuilder().climbableFromBottom().climbableFromTop().build()); - Block START = Block(Identifier("adventura", "start"), 'S', BlockSettingsBuilder().build()); - Block GOAL = Block(Identifier("adventura", "goal"), 'O', BlockSettingsBuilder().build()); + Block LADDER = Block(Identifier("adventura", "ladder"), 'H', Color::BRIGHT_MAGENTA, BlockSettingsBuilder().climbableFromBottom().climbableFromTop().build()); + Block START = Block(Identifier("adventura", "start"), 'S', BlockSettingsBuilder().nonSolid().build()); + Block GOAL = Block(Identifier("adventura", "goal"), 'O', Color::BRIGHT_GREEN, BlockSettingsBuilder().nonSolid().build()); + Block WALL = Block(Identifier("adventura", "wall"), '0', Color::BRIGHT_BLACK, BlockSettingsBuilder().collidable().build()); + Block SPIKE = Block(Identifier("adventura", "spike"), '^', Color::BRIGHT_RED, BlockSettingsBuilder().lethal().build()); BlockRegistry() { registerBlock(AIR); + registerBlock(WATER); registerBlock(PLATFORM); registerBlock(LADDER); registerBlock(START); - registerBlock(GOAL); + registerBlock(GOAL); + registerBlock(WALL); + registerBlock(SPIKE); } const Block getByEncoding(char encoding) { diff --git a/src/blockSettings.hpp b/src/blockSettings.hpp index f040d90..1bbb58b 100644 --- a/src/blockSettings.hpp +++ b/src/blockSettings.hpp @@ -4,9 +4,15 @@ class BlockSettings { bool isSolid() { return isSolid_; } + bool hasCollision() { + return hasCollision_; + } bool isMovable() { return isMovable_; } + bool isLethal() { + return isLethal_; + } bool isClimbableFromTop() { return isClimbableFromTop_; } @@ -20,6 +26,12 @@ class BlockSettings { void setMovable(bool isMovable) { this->isMovable_ = isMovable; } + void setCollision(bool hasCollision) { + this->hasCollision_ = hasCollision; + } + void setLethal(bool isLethal) { + this->isLethal_ = isLethal; + } void setClimbableFromTop(bool isClimbableFromTop) { this->isClimbableFromTop_ = isClimbableFromTop; } @@ -32,6 +44,8 @@ class BlockSettings { bool isMovable_ = false; bool isClimbableFromTop_ = false; bool isClimbableFromBottom_ = false; + bool isLethal_ = false; + bool hasCollision_ = false; }; class BlockSettingsBuilder { public: @@ -43,6 +57,14 @@ class BlockSettingsBuilder { blockSettings.setMovable(true); return *this; } + BlockSettingsBuilder collidable() { + blockSettings.setCollision(true); + return *this; + } + BlockSettingsBuilder lethal() { + blockSettings.setLethal(true); + return *this; + } BlockSettingsBuilder climbableFromTop() { blockSettings.setClimbableFromTop(true); return *this; diff --git a/src/color.hpp b/src/color.hpp new file mode 100644 index 0000000..40b0220 --- /dev/null +++ b/src/color.hpp @@ -0,0 +1,16 @@ +#include + +enum class Color { + RESET = 0, + BRIGHT_BLACK= 90, + BRIGHT_RED= 91, + BRIGHT_GREEN= 92, + BRIGHT_YELLOW= 93, + BRIGHT_BLUE= 94, + BRIGHT_MAGENTA= 95, + BRIGHT_CYAN= 96, + BRIGHT_WHITE= 97 +}; +std::ostream& operator<<(std::ostream& os, Color color) { + return os << "\033[" << static_cast(color) << "m"; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 4342aa0..d54a318 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "world.hpp" #include "player.hpp" #include "blockRegistry.hpp" @@ -8,26 +9,33 @@ using std::string; using std::cout; using std::endl; +namespace fs = std::filesystem; void render(World &world, Player &player); void redraw(World &world, Player &player); void jumpBackOneLine(); +bool startWorld(string worldFile); int main() { + for (const auto & entry : fs::directory_iterator("./worlds")) + if (!startWorld(entry.path())) return 0; + + return 0; +} +bool startWorld(string worldFile) { BlockRegistry blockRegistry = BlockRegistry(); World world = World(blockRegistry); - string worldFile = "worlds/world.txt"; world.loadFromFile(worldFile); Player player = Player(world.getStartPos(), world); render(world, player); - while (player.isAlive()) { + while (player.isAlive() && !player.hasReachedGoal()) { char lastChar; cin >> lastChar; if (onInput(lastChar, world, player)) redraw(world, player); else jumpBackOneLine(); } - return 0; + return player.hasReachedGoal(); } void jumpBackOneLine() { std::cout << "\033[1A"; @@ -48,10 +56,10 @@ void render(World &world, Player &player) { for (unsigned int y = 0; y <= world.getMaxY(); y++) { for (unsigned int x = 0; x <= world.getMaxX(); x++) { if (playerTexture.size() > y && playerTexture.at(y).size() > x && playerTexture.at(y).at(x) != ' ') { - cout << playerTexture.at(y).at(x); + cout << Color::BRIGHT_YELLOW << playerTexture.at(y).at(x); } else if (canvas.size() > y && canvas.at(y).size() > x) { - cout << canvas.at(y).at(x).getEncoding(); + cout << canvas.at(y).at(x).getColor() << canvas.at(y).at(x).getEncoding(); } else cout << ' '; } diff --git a/src/movementHandler.hpp b/src/movementHandler.hpp index b1d2c40..c9a3a11 100644 --- a/src/movementHandler.hpp +++ b/src/movementHandler.hpp @@ -2,19 +2,20 @@ #include "world.hpp" #include "blockRegistry.hpp" +bool tryWalk(World& world, Player& player, bool left); bool tryGoDown(World& world, Player& player); bool tryGoUp(World& world, Player& player); bool onInput(char lastChar, World& world, Player& player) { switch (lastChar) { + case ' ': case 'w': case 'W': return tryGoUp(world, player); case 'a': case 'A': - player.move(-1, 0); - return true; + return tryWalk(world, player, true); case 's': case 'S': @@ -22,12 +23,18 @@ bool onInput(char lastChar, World& world, Player& player) { case 'd': case 'D': - player.move(1, 0); - return true; + return tryWalk(world, player, false); default: return false; } } +bool tryWalk(World& world, Player& player, bool left) { + if (!world.getBlockAt(player.getPos()+(left ? BlockPos(-1, 1) : BlockPos(1, 1))).getSettings().hasCollision()) { + player.move(left ? BlockPos(-1, 0) : BlockPos(1,0)); + return true; + } + return false; +} bool tryGoDown(World& world, Player& player) { if (world.getBlockAt(player.getPos()+BlockPos(0, 2)).getSettings().isClimbableFromTop() || world.getBlockAt(player.getPos()+BlockPos(0, 3)).getSettings().isClimbableFromTop()) { player.move(0, 1); @@ -40,5 +47,13 @@ bool tryGoUp(World& world, Player& player) { player.move(0, -1); return true; } + else if (world.getBlockAt(player.getPos()+BlockPos(1, 1)).getSettings().hasCollision() && !world.getBlockAt(player.getPos()+BlockPos(1, 0)).getSettings().isSolid()) { + player.move(1, -1); + return true; + } + else if (world.getBlockAt(player.getPos()+BlockPos(-1, 1)).getSettings().hasCollision() && !world.getBlockAt(player.getPos()+BlockPos(-1, 0)).getSettings().isSolid()) { + player.move(-1, -1); + return true; + } return false; } \ No newline at end of file diff --git a/src/player.hpp b/src/player.hpp index 2cdc6b3..7412b85 100644 --- a/src/player.hpp +++ b/src/player.hpp @@ -30,6 +30,8 @@ public: } this->pos = pos; + if (world.getBlockAt(pos) == world.getBlockRegistry().GOAL) reachedGoal = true; + isFreeFalling = !world.getBlockAt(pos+BlockPos(0, 2)).getSettings().isSolid(); if (isFreeFalling) { move(BlockPos(0, 1)); @@ -37,10 +39,15 @@ public: if (fallLength > 5) alive = false; } else fallLength = 0; + + if (world.getBlockAt(pos+BlockPos(0, 2)).getSettings().isLethal()) alive = false; } bool isAlive() { return alive; } + bool hasReachedGoal() { + return reachedGoal; + } vector> mapToWorldspace() { vector> map; for (unsigned int y = 0; y <= world.getMaxY(); y++) { @@ -69,5 +76,6 @@ private: BlockPos pos = BlockPos(0, 0); bool alive = true; bool isFreeFalling = false; + bool reachedGoal = false; int fallLength = 0; }; \ No newline at end of file diff --git a/worlds/world.txt b/worlds/1.txt similarity index 100% rename from worlds/world.txt rename to worlds/1.txt diff --git a/worlds/2.txt b/worlds/2.txt new file mode 100644 index 0000000..7328ded --- /dev/null +++ b/worlds/2.txt @@ -0,0 +1,15 @@ + + + o + S /|\ + / \ +------------- ----------- + H H + H H + H H + H --------- ------- +-------- H 0 0 + H H 0 0 + H H 0 0 O + H H 0^^^^^0 + ---------------------------------------- \ No newline at end of file diff --git a/worlds/3.txt b/worlds/3.txt new file mode 100644 index 0000000..1e4791c --- /dev/null +++ b/worlds/3.txt @@ -0,0 +1,15 @@ + + ---------------------- + 00 + 00 + 00 +--------- +0 o 00----- O +0 S /|\ 00 0 +0 / \ 00 0 --------------- +---------------- 0 H 0 + 0 H 0 + 0 H 0 + 0 H 0 + 0~~~~~~0--------- + --------