@@ -0,0 +1,3 @@ | |||||
BasedOnStyle: LLVM | |||||
IndentWidth: 4 | |||||
AccessModifierOffset: -2 |
@@ -0,0 +1,3 @@ | |||||
*.o | |||||
main | |||||
CPPLINT.cfg |
@@ -0,0 +1,17 @@ | |||||
CXX = g++ | |||||
CXXFLAGS = -g -Wall -std=c++17 | |||||
LDFLAGS = -lpthread | |||||
SRC = main.cpp object.cpp world.cpp | |||||
OBJ = ${SRC:.cpp=.o} | |||||
all: main | |||||
.o: ${OBJ} | |||||
${CXX} -c ${CXXFLAGS} $< | |||||
main: ${OBJ} | |||||
${CXX} -o $@ ${OBJ} ${LDFLAGS} | |||||
clean: | |||||
rm -f main ${OBJ} |
@@ -0,0 +1,8 @@ | |||||
#pragma once | |||||
#define TICKRATE 16 | |||||
#define WORLD_HEIGHT 32 | |||||
#define WORLD_WIDTH 32 | |||||
#define DEFAULT_CHAR '.' | |||||
@@ -0,0 +1,133 @@ | |||||
#include "config.h" | |||||
#include "world.h" | |||||
#include <chrono> | |||||
#include <iostream> | |||||
#include <string> | |||||
#include <thread> | |||||
#include <vector> | |||||
#include <termios.h> //termios, TCSANOW, ECHO, ICANON | |||||
#include <unistd.h> //STDIN_FILENO | |||||
constexpr int ticktime = 1000.0 / TICKRATE; | |||||
static struct termios oldt, newt; | |||||
enum gamestatus { RUNNING, PAUSED, STOPPED } game; | |||||
void initTerminal() { | |||||
/*tcgetattr gets the parameters of the current terminal | |||||
STDIN_FILENO will tell tcgetattr that it should write the settings | |||||
of stdin to oldt*/ | |||||
tcgetattr(STDIN_FILENO, &oldt); | |||||
/*now the settings will be copied*/ | |||||
newt = oldt; | |||||
/*ICANON normally takes care that one line at a time will be processed | |||||
that means it will return if it sees a "\n" or an EOF or an EOL*/ | |||||
newt.c_lflag &= ~(ICANON); | |||||
/*ECHO - don't print user input */ | |||||
newt.c_lflag &= ~(ECHO); | |||||
/*Those new settings will be set to STDIN | |||||
TCSANOW tells tcsetattr to change attributes immediately. */ | |||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt); | |||||
} | |||||
void restoreTerminal() { | |||||
/*restore the old settings*/ | |||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); | |||||
} | |||||
void input(Object &o) { | |||||
while (game != STOPPED) { | |||||
char c = getchar(); | |||||
if (game == PAUSED) { | |||||
if (c == 'p') | |||||
game = RUNNING; | |||||
continue; | |||||
} | |||||
bool ok = 1; | |||||
switch (c) { | |||||
case 'w': | |||||
o.changePosition(0, -1); | |||||
break; | |||||
case 's': | |||||
o.changePosition(0, 1); | |||||
break; | |||||
case 'd': | |||||
o.changePosition(1, 0); | |||||
break; | |||||
case 'a': | |||||
o.changePosition(-1, 0); | |||||
break; | |||||
case 'p': | |||||
game = PAUSED; | |||||
break; | |||||
case 'e': | |||||
ok = 0; | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
if (!ok) | |||||
break; | |||||
} | |||||
} | |||||
void botAI(Object &o) { | |||||
while (game != STOPPED) { | |||||
if (game == PAUSED) | |||||
continue; | |||||
o.changePosition(rand() % 3 - 1, rand() % 3 - 1); | |||||
std::this_thread::sleep_for(std::chrono::milliseconds(500)); | |||||
} | |||||
} | |||||
void gameloop(World &world) { | |||||
while (game != STOPPED) { | |||||
if (game == RUNNING) | |||||
world.update(); | |||||
world.print(std::cout); | |||||
switch (game) { | |||||
case RUNNING: | |||||
std::cout << "GAME RUNNING!\n"; | |||||
break; | |||||
case PAUSED: | |||||
std::cout << "GAME PAUSED\n"; | |||||
break; | |||||
default: | |||||
std::cout << "GAME UNDEFINED\n"; | |||||
break; | |||||
} | |||||
std::this_thread::sleep_for(std::chrono::milliseconds(ticktime)); | |||||
std::cout << "\x1B[2J\x1B[H"; | |||||
} | |||||
} | |||||
int main() { | |||||
initTerminal(); | |||||
srand(time(NULL)); | |||||
game = RUNNING; | |||||
World world; | |||||
Object &objtest = | |||||
world.createObject(Object(Object::Position(3, 3), 3, '*')); | |||||
Object &objtestAI = | |||||
world.createObject(Object(Object::Position(20, 20), 4, '=')); | |||||
std::thread m(gameloop, std::ref(world)); | |||||
std::thread bot(botAI, std::ref(objtestAI)); | |||||
std::thread in(input, std::ref(objtest)); | |||||
in.join(); | |||||
game = STOPPED; | |||||
bot.join(); | |||||
m.join(); | |||||
restoreTerminal(); | |||||
} | |||||
@@ -0,0 +1,29 @@ | |||||
#include "config.h" | |||||
#include "object.h" | |||||
Object::Object() : m_symbol('*'), m_size(1), m_pos(0, 0) {} | |||||
Object::Object(Position pos, int size, char symbol) | |||||
: m_symbol(symbol), m_size(size), m_pos(pos) {} | |||||
char Object::getSymbol() { return m_symbol; } | |||||
Object::Position Object::getPosition() { return m_pos; } | |||||
int Object::getSize() { return m_size; } | |||||
void Object::setPosition(Object::Position p) { m_pos = p; } | |||||
void Object::changePosition(double dx, double dy) { | |||||
if (m_pos.X + dx + (-(m_size + 1) / 2 + 1) < 0) | |||||
dx = -(m_pos.X + (-(m_size + 1) / 2 + 1)); | |||||
if (m_pos.Y + dy + (-(m_size + 1) / 2 + 1) < 0) | |||||
dy = -(m_pos.Y + (-(m_size + 1) / 2 + 1)); | |||||
if (m_pos.X + dx + m_size / 2 >= WORLD_WIDTH) | |||||
dx = (WORLD_WIDTH-1) - (m_pos.X + m_size / 2); | |||||
if (m_pos.Y + dy + m_size / 2 >= WORLD_HEIGHT) | |||||
dy = (WORLD_HEIGHT-1) - (m_pos.Y + m_size / 2); | |||||
m_pos.X += dx, m_pos.Y += dy; | |||||
} | |||||
@@ -0,0 +1,38 @@ | |||||
#pragma once | |||||
class Object { | |||||
public: | |||||
struct Position { | |||||
double X, Y; | |||||
Position(): X(0), Y(0) { | |||||
} | |||||
Position(double x, double y): X(x), Y(y) { | |||||
} | |||||
void setPos(double x, double y) { | |||||
X = x, Y = y; | |||||
} | |||||
const Position& operator=(const Position &p) { | |||||
this->X = p.X, this->Y = p.Y; | |||||
return *this; | |||||
} | |||||
}; | |||||
Object(); | |||||
Object(Position pos, int size, char symbol); | |||||
virtual char getSymbol(); | |||||
Position getPosition(); | |||||
int getSize(); | |||||
void setPosition(Position p); | |||||
void changePosition(double dx, double dy); | |||||
protected: | |||||
char m_symbol; | |||||
int m_size; | |||||
Position m_pos; | |||||
}; |
@@ -0,0 +1,45 @@ | |||||
#include "world.h" | |||||
World::World() | |||||
: m_height(WORLD_HEIGHT), m_width(WORLD_WIDTH), | |||||
m_c(WORLD_HEIGHT, std::vector<char>(WORLD_WIDTH, DEFAULT_CHAR)) { | |||||
init(); | |||||
} | |||||
void World::init() {} | |||||
Object &World::createObject(Object &&o) { | |||||
m_objects.push_front(o); | |||||
return m_objects.front(); | |||||
} | |||||
void World::draw(Object &o) { | |||||
double x = o.getPosition().X, y = o.getPosition().Y; | |||||
int sz = o.getSize(); | |||||
char c = o.getSymbol(); | |||||
for (int i = -(sz + 1) / 2 + 1; i <= sz / 2; ++i) | |||||
for (int j = -(sz + 1) / 2 + 1; j <= sz / 2; ++j) | |||||
m_c[y + i][x + j] = c; | |||||
} | |||||
void World::update() { | |||||
for (auto &i : m_c) | |||||
for (auto &j : i) | |||||
j = DEFAULT_CHAR; | |||||
for (auto &it : m_objects) { | |||||
draw(it); | |||||
} | |||||
} | |||||
void World::print(std::ostream &out) { | |||||
for (const auto &i : m_c) { | |||||
for (const auto &j : i) | |||||
out << j; | |||||
out << '\n'; | |||||
} | |||||
} | |||||
void World::destroy() {} | |||||
World::~World() { destroy(); } |
@@ -0,0 +1,24 @@ | |||||
#pragma once | |||||
#include "config.h" | |||||
#include "object.h" | |||||
#include <iostream> | |||||
#include <list> | |||||
#include <vector> | |||||
class World { | |||||
size_t m_height, m_width; | |||||
std::vector<std::vector<char>> m_c; | |||||
std::list<Object> m_objects; | |||||
public: | |||||
World(); | |||||
void init(); | |||||
Object &createObject(Object &&); | |||||
void draw(Object &o); | |||||
void update(); | |||||
void print(std::ostream &out); | |||||
void destroy(); | |||||
~World(); | |||||
}; |