@@ -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(); | |||
}; |