mirror of
https://github.com/Motschen/Adventura.git
synced 2025-12-13 10:25:09 +01:00
Support multiple and custom levels
This commit is contained in:
@@ -1,16 +1,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "identifier.hpp"
|
#include "identifier.hpp"
|
||||||
|
#include "color.hpp"
|
||||||
#include "blockSettings.hpp"
|
#include "blockSettings.hpp"
|
||||||
|
|
||||||
class Block {
|
class Block {
|
||||||
private:
|
private:
|
||||||
Identifier id = Identifier("adventure", "missing");
|
Identifier id = Identifier("adventure", "missing");
|
||||||
char encoding;
|
char encoding;
|
||||||
|
Color color;
|
||||||
BlockSettings settings;
|
BlockSettings settings;
|
||||||
|
|
||||||
public:
|
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->id = id;
|
||||||
this->encoding = encoding;
|
this->encoding = encoding;
|
||||||
|
this->color = color;
|
||||||
this->settings = settings;
|
this->settings = settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -21,6 +26,9 @@ public:
|
|||||||
Identifier getId() {
|
Identifier getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
Color getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
char getEncoding() {
|
char getEncoding() {
|
||||||
return encoding;
|
return encoding;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,17 +9,23 @@ using std::string;
|
|||||||
class BlockRegistry {
|
class BlockRegistry {
|
||||||
public:
|
public:
|
||||||
Block AIR = Block(Identifier("adventura", "air"), ' ', BlockSettingsBuilder().nonSolid().build());
|
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 PLATFORM = Block(Identifier("adventura", "platform"), '-', BlockSettingsBuilder().build());
|
||||||
Block LADDER = Block(Identifier("adventura", "ladder"), 'H', BlockSettingsBuilder().climbableFromBottom().climbableFromTop().build());
|
Block LADDER = Block(Identifier("adventura", "ladder"), 'H', Color::BRIGHT_MAGENTA, BlockSettingsBuilder().climbableFromBottom().climbableFromTop().build());
|
||||||
Block START = Block(Identifier("adventura", "start"), 'S', BlockSettingsBuilder().build());
|
Block START = Block(Identifier("adventura", "start"), 'S', BlockSettingsBuilder().nonSolid().build());
|
||||||
Block GOAL = Block(Identifier("adventura", "goal"), 'O', BlockSettingsBuilder().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() {
|
BlockRegistry() {
|
||||||
registerBlock(AIR);
|
registerBlock(AIR);
|
||||||
|
registerBlock(WATER);
|
||||||
registerBlock(PLATFORM);
|
registerBlock(PLATFORM);
|
||||||
registerBlock(LADDER);
|
registerBlock(LADDER);
|
||||||
registerBlock(START);
|
registerBlock(START);
|
||||||
registerBlock(GOAL);
|
registerBlock(GOAL);
|
||||||
|
registerBlock(WALL);
|
||||||
|
registerBlock(SPIKE);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Block getByEncoding(char encoding) {
|
const Block getByEncoding(char encoding) {
|
||||||
|
|||||||
@@ -4,9 +4,15 @@ class BlockSettings {
|
|||||||
bool isSolid() {
|
bool isSolid() {
|
||||||
return isSolid_;
|
return isSolid_;
|
||||||
}
|
}
|
||||||
|
bool hasCollision() {
|
||||||
|
return hasCollision_;
|
||||||
|
}
|
||||||
bool isMovable() {
|
bool isMovable() {
|
||||||
return isMovable_;
|
return isMovable_;
|
||||||
}
|
}
|
||||||
|
bool isLethal() {
|
||||||
|
return isLethal_;
|
||||||
|
}
|
||||||
bool isClimbableFromTop() {
|
bool isClimbableFromTop() {
|
||||||
return isClimbableFromTop_;
|
return isClimbableFromTop_;
|
||||||
}
|
}
|
||||||
@@ -20,6 +26,12 @@ class BlockSettings {
|
|||||||
void setMovable(bool isMovable) {
|
void setMovable(bool isMovable) {
|
||||||
this->isMovable_ = isMovable;
|
this->isMovable_ = isMovable;
|
||||||
}
|
}
|
||||||
|
void setCollision(bool hasCollision) {
|
||||||
|
this->hasCollision_ = hasCollision;
|
||||||
|
}
|
||||||
|
void setLethal(bool isLethal) {
|
||||||
|
this->isLethal_ = isLethal;
|
||||||
|
}
|
||||||
void setClimbableFromTop(bool isClimbableFromTop) {
|
void setClimbableFromTop(bool isClimbableFromTop) {
|
||||||
this->isClimbableFromTop_ = isClimbableFromTop;
|
this->isClimbableFromTop_ = isClimbableFromTop;
|
||||||
}
|
}
|
||||||
@@ -32,6 +44,8 @@ class BlockSettings {
|
|||||||
bool isMovable_ = false;
|
bool isMovable_ = false;
|
||||||
bool isClimbableFromTop_ = false;
|
bool isClimbableFromTop_ = false;
|
||||||
bool isClimbableFromBottom_ = false;
|
bool isClimbableFromBottom_ = false;
|
||||||
|
bool isLethal_ = false;
|
||||||
|
bool hasCollision_ = false;
|
||||||
};
|
};
|
||||||
class BlockSettingsBuilder {
|
class BlockSettingsBuilder {
|
||||||
public:
|
public:
|
||||||
@@ -43,6 +57,14 @@ class BlockSettingsBuilder {
|
|||||||
blockSettings.setMovable(true);
|
blockSettings.setMovable(true);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
BlockSettingsBuilder collidable() {
|
||||||
|
blockSettings.setCollision(true);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
BlockSettingsBuilder lethal() {
|
||||||
|
blockSettings.setLethal(true);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
BlockSettingsBuilder climbableFromTop() {
|
BlockSettingsBuilder climbableFromTop() {
|
||||||
blockSettings.setClimbableFromTop(true);
|
blockSettings.setClimbableFromTop(true);
|
||||||
return *this;
|
return *this;
|
||||||
|
|||||||
16
src/color.hpp
Normal file
16
src/color.hpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
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<int>(color) << "m";
|
||||||
|
}
|
||||||
18
src/main.cpp
18
src/main.cpp
@@ -1,5 +1,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <filesystem>
|
||||||
#include "world.hpp"
|
#include "world.hpp"
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
#include "blockRegistry.hpp"
|
#include "blockRegistry.hpp"
|
||||||
@@ -8,26 +9,33 @@
|
|||||||
using std::string;
|
using std::string;
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
void render(World &world, Player &player);
|
void render(World &world, Player &player);
|
||||||
void redraw(World &world, Player &player);
|
void redraw(World &world, Player &player);
|
||||||
void jumpBackOneLine();
|
void jumpBackOneLine();
|
||||||
|
bool startWorld(string worldFile);
|
||||||
|
|
||||||
int main() {
|
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();
|
BlockRegistry blockRegistry = BlockRegistry();
|
||||||
World world = World(blockRegistry);
|
World world = World(blockRegistry);
|
||||||
|
|
||||||
string worldFile = "worlds/world.txt";
|
|
||||||
world.loadFromFile(worldFile);
|
world.loadFromFile(worldFile);
|
||||||
Player player = Player(world.getStartPos(), world);
|
Player player = Player(world.getStartPos(), world);
|
||||||
render(world, player);
|
render(world, player);
|
||||||
while (player.isAlive()) {
|
while (player.isAlive() && !player.hasReachedGoal()) {
|
||||||
char lastChar;
|
char lastChar;
|
||||||
cin >> lastChar;
|
cin >> lastChar;
|
||||||
if (onInput(lastChar, world, player)) redraw(world, player);
|
if (onInput(lastChar, world, player)) redraw(world, player);
|
||||||
else jumpBackOneLine();
|
else jumpBackOneLine();
|
||||||
}
|
}
|
||||||
return 0;
|
return player.hasReachedGoal();
|
||||||
}
|
}
|
||||||
void jumpBackOneLine() {
|
void jumpBackOneLine() {
|
||||||
std::cout << "\033[1A";
|
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 y = 0; y <= world.getMaxY(); y++) {
|
||||||
for (unsigned int x = 0; x <= world.getMaxX(); x++) {
|
for (unsigned int x = 0; x <= world.getMaxX(); x++) {
|
||||||
if (playerTexture.size() > y && playerTexture.at(y).size() > x && playerTexture.at(y).at(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) {
|
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 << ' ';
|
else cout << ' ';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,20 @@
|
|||||||
#include "world.hpp"
|
#include "world.hpp"
|
||||||
#include "blockRegistry.hpp"
|
#include "blockRegistry.hpp"
|
||||||
|
|
||||||
|
bool tryWalk(World& world, Player& player, bool left);
|
||||||
bool tryGoDown(World& world, Player& player);
|
bool tryGoDown(World& world, Player& player);
|
||||||
bool tryGoUp(World& world, Player& player);
|
bool tryGoUp(World& world, Player& player);
|
||||||
|
|
||||||
bool onInput(char lastChar, World& world, Player& player) {
|
bool onInput(char lastChar, World& world, Player& player) {
|
||||||
switch (lastChar) {
|
switch (lastChar) {
|
||||||
|
case ' ':
|
||||||
case 'w':
|
case 'w':
|
||||||
case 'W':
|
case 'W':
|
||||||
return tryGoUp(world, player);
|
return tryGoUp(world, player);
|
||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
case 'A':
|
case 'A':
|
||||||
player.move(-1, 0);
|
return tryWalk(world, player, true);
|
||||||
return true;
|
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
@@ -22,12 +23,18 @@ bool onInput(char lastChar, World& world, Player& player) {
|
|||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'D':
|
case 'D':
|
||||||
player.move(1, 0);
|
return tryWalk(world, player, false);
|
||||||
return true;
|
|
||||||
|
|
||||||
default: return 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) {
|
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()) {
|
if (world.getBlockAt(player.getPos()+BlockPos(0, 2)).getSettings().isClimbableFromTop() || world.getBlockAt(player.getPos()+BlockPos(0, 3)).getSettings().isClimbableFromTop()) {
|
||||||
player.move(0, 1);
|
player.move(0, 1);
|
||||||
@@ -40,5 +47,13 @@ bool tryGoUp(World& world, Player& player) {
|
|||||||
player.move(0, -1);
|
player.move(0, -1);
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,8 @@ public:
|
|||||||
}
|
}
|
||||||
this->pos = pos;
|
this->pos = pos;
|
||||||
|
|
||||||
|
if (world.getBlockAt(pos) == world.getBlockRegistry().GOAL) reachedGoal = true;
|
||||||
|
|
||||||
isFreeFalling = !world.getBlockAt(pos+BlockPos(0, 2)).getSettings().isSolid();
|
isFreeFalling = !world.getBlockAt(pos+BlockPos(0, 2)).getSettings().isSolid();
|
||||||
if (isFreeFalling) {
|
if (isFreeFalling) {
|
||||||
move(BlockPos(0, 1));
|
move(BlockPos(0, 1));
|
||||||
@@ -37,10 +39,15 @@ public:
|
|||||||
if (fallLength > 5) alive = false;
|
if (fallLength > 5) alive = false;
|
||||||
}
|
}
|
||||||
else fallLength = 0;
|
else fallLength = 0;
|
||||||
|
|
||||||
|
if (world.getBlockAt(pos+BlockPos(0, 2)).getSettings().isLethal()) alive = false;
|
||||||
}
|
}
|
||||||
bool isAlive() {
|
bool isAlive() {
|
||||||
return alive;
|
return alive;
|
||||||
}
|
}
|
||||||
|
bool hasReachedGoal() {
|
||||||
|
return reachedGoal;
|
||||||
|
}
|
||||||
vector<vector<char>> mapToWorldspace() {
|
vector<vector<char>> mapToWorldspace() {
|
||||||
vector<vector<char>> map;
|
vector<vector<char>> map;
|
||||||
for (unsigned int y = 0; y <= world.getMaxY(); y++) {
|
for (unsigned int y = 0; y <= world.getMaxY(); y++) {
|
||||||
@@ -69,5 +76,6 @@ private:
|
|||||||
BlockPos pos = BlockPos(0, 0);
|
BlockPos pos = BlockPos(0, 0);
|
||||||
bool alive = true;
|
bool alive = true;
|
||||||
bool isFreeFalling = false;
|
bool isFreeFalling = false;
|
||||||
|
bool reachedGoal = false;
|
||||||
int fallLength = 0;
|
int fallLength = 0;
|
||||||
};
|
};
|
||||||
15
worlds/2.txt
Normal file
15
worlds/2.txt
Normal file
@@ -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
|
||||||
|
----------------------------------------
|
||||||
15
worlds/3.txt
Normal file
15
worlds/3.txt
Normal file
@@ -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---------
|
||||||
|
--------
|
||||||
Reference in New Issue
Block a user