commit bf2edd9fc20eed8fc4eed4a5dbb40fcde137ac22 Author: VissaMoutafis Date: Fri Feb 21 14:47:46 2020 +0200 Controller ready, Input methods ready, Board Ready, Snake collision events to be made and Snack class to be implemented diff --git a/.vscode/.easycpp b/.vscode/.easycpp new file mode 100755 index 0000000..15aa62c --- /dev/null +++ b/.vscode/.easycpp @@ -0,0 +1 @@ +This file is created by Easy C++ Projects, please ignore and do not delete it \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100755 index 0000000..7a19006 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C++ Debug (gdb)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/bin/main", + "preLaunchTask": "Build C++ project", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": true, + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100755 index 0000000..f4aa9e6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.associations": { + "*.tpp": "cpp" + }, + "terminal.integrated.shell.windows": "cmd.exe" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100755 index 0000000..f4ebfa7 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,26 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build C++ project", + "type": "shell", + "group": { + "kind": "build", + "isDefault": true + }, + "command": "make", + }, + { + "label": "Build & run C++ project", + "type": "shell", + "group": { + "kind": "test", + "isDefault": true + }, + "command": "make", + "args": [ + "run" + ] + } + ] +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..bbd3780 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +CXX := g++ +CXX_FLAGS := -Wall -Wextra -std=c++11 -ggdb + +BIN := bin +SRC := src +INCLUDE := include +LIB := lib + +LIBRARIES := -lncurses +EXECUTABLE := main + + +all: $(BIN)/$(EXECUTABLE) + +run: clean all + clear + ./$(BIN)/$(EXECUTABLE) + +$(BIN)/$(EXECUTABLE): $(SRC)/*.cpp + $(CXX) $(CXX_FLAGS) -I$(INCLUDE) -L$(LIB) $^ -o $@ $(LIBRARIES) + +clean: + -rm $(BIN)/* diff --git a/bin/main b/bin/main new file mode 100755 index 0000000..54f2636 Binary files /dev/null and b/bin/main differ diff --git a/include/Controller.h b/include/Controller.h new file mode 100644 index 0000000..723254c --- /dev/null +++ b/include/Controller.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Graphics.h" +#include "Snake.h" + +class Controller{ +private: + Snake *snake; //the figure the controler controls + graphics_input inpt; +public: + Controller(Snake* _snake); + Controller(); + ~Controller(); //default destructor + + graphics_input readInput(void); //basic input methods: sets inpt to what it read if i tread something + + void act(void); //basic act method: acts like a joystick + + bool wantsToQuit(void); //returns true of the user wants to quit +}; \ No newline at end of file diff --git a/include/Game.h b/include/Game.h new file mode 100755 index 0000000..e69de29 diff --git a/include/Graphics.h b/include/Graphics.h new file mode 100644 index 0000000..7379cfa --- /dev/null +++ b/include/Graphics.h @@ -0,0 +1,20 @@ +#pragma once + +#include //include library for terminal graphics + +#define UP KEY_UP +#define DOWN KEY_DOWN +#define LEFT KEY_LEFT +#define RIGHT KEY_RIGHT +#define EXIT_GAME 'q' +typedef int graphics_input; //the type of the graphics input + + + +void initializeGraphics(void); +void endGraphics(void); +void refreshScreen(void); +void printChar(int y, int x, graphics_input img); +void printMsg(int y, int x, char *str); +char readChar(int y, int x); +int readInpt(); \ No newline at end of file diff --git a/include/Player.h b/include/Player.h new file mode 100755 index 0000000..e69de29 diff --git a/include/Point.h b/include/Point.h new file mode 100755 index 0000000..bee87c3 --- /dev/null +++ b/include/Point.h @@ -0,0 +1,26 @@ +#pragma once + +#include "Graphics.h" + +class Point{ +private: + int x; + int y; + graphics_input img; +public: + Point(); + Point(int y = 10, int x = 10, graphics_input img = '*'); + ~Point(); + void setPoint(int y, int x); + int getX(); + int getY(); + void moveUp(); + void moveDown(); + void moveLeft(); + void moveRight(); + graphics_input getImg(); + void setImg(graphics_input image); + void printImg(); + void erase(); + void randomize(); +}; \ No newline at end of file diff --git a/include/Snake.h b/include/Snake.h new file mode 100755 index 0000000..ccd2dd2 --- /dev/null +++ b/include/Snake.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "Point.h" //the library we need to implement the snake +#define SNACK '*' +#define BODY 'o' +class Snake{ +private: + std::list snake; //the snake will be implemented as a list of points where the first element is the head + graphics_input direction; + void updateHead(void); + void printSnake(void); +public: + Snake(int headY = LINES/2, int headX = COLS/2); //default constructor + ~Snake(); //destructor + + //basic move functions + void moveUp(void); + void moveDown(void); + void moveLeft(void); + void moveRight(void); + + bool isBitten(void); //function to check if the snake bit its self + bool hasBitSnack(int snackY, int snackX);//checks if the snake has bitten a snack + + int getSize(void); //get the current length + void incSize(void); //function to increase the length + + void move(void); //function to refresh the image of the snake +}; diff --git a/src/Controller.cpp b/src/Controller.cpp new file mode 100644 index 0000000..7bfa8eb --- /dev/null +++ b/src/Controller.cpp @@ -0,0 +1,50 @@ +#include "Controller.h" +#include +#include +using namespace std; + +Controller::Controller() +:inpt{0} +{ + snake = new Snake(); +} + +Controller::Controller(Snake *_snake) +: snake{_snake}, inpt{0} { + + assert(this->snake != NULL); +} + +Controller::~Controller(){} + +void Controller::act(void){ + switch (this->inpt) + { + case UP: + snake->moveUp(); + break; + case DOWN: + snake->moveDown(); + break; + case LEFT: + snake->moveLeft(); + break; + case RIGHT: + snake->moveRight(); + break; + default: + snake->move(); + break; + } + refreshScreen(); +} + +graphics_input Controller::readInput(void){ + this->inpt = readInpt(); + refreshScreen(); + return inpt; +} + +bool Controller::wantsToQuit(void){ + return this->inpt == EXIT_GAME; +} \ No newline at end of file diff --git a/src/Graphics.cpp b/src/Graphics.cpp new file mode 100644 index 0000000..4e271af --- /dev/null +++ b/src/Graphics.cpp @@ -0,0 +1,72 @@ +#include "Graphics.h" +#include +#include +///Utillities for the graphics +unsigned int sleepTime = 50000000; +static WINDOW *_box = NULL; + +static void createBox(void){ + _box = newwin(LINES-2, COLS, 2, 0); + box(_box, 0, 0); + wrefresh(_box); +} +static void destroyBox(void){ + wborder(_box, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wrefresh(_box); + delwin(_box); +} +//Initialization function +void initializeGraphics(void){ + initscr(); //initialize curses + cbreak(); //set line buffering to false + noecho(); //set input echo to false + keypad(stdscr, TRUE); //this step enables the use of arrow keys and other function keys + nodelay(stdscr, true); + //We must clear the screen from unecessary garbage + clear(); + //Print the title + mvprintw(0, (COLS/2) - 12, "~Snake Game by VissaM~"); + refresh(); + + //create the game box + createBox(); +} + +//Exit function +void endGraphics(void){ + destroyBox(); + endwin(); +} + +//Typical refresh function (ease the eye with a custom function instead of the actual one) +void refreshScreen(void){ + using namespace std::this_thread; // sleep_for, sleep_until + using namespace std::chrono; // nanoseconds, system_clock, seconds + sleep_for(nanoseconds(sleepTime)); + + refresh(); // just use the curses version ;p + wrefresh(_box); +} + +void printChar(int y, int x, graphics_input img){ + mvwaddch(_box, y, x, img); + refresh(); + wrefresh(_box); +} + +void printMsg(int y, int x, char* str){ + mvwaddstr(_box, y, x, str); + refresh(); + wrefresh(_box); +} + +char readChar(int y, int x){ + mvwgetch(_box, y, x); + refresh(); + wrefresh(_box); +} + +int readInpt(){ + return getch(); +} + diff --git a/src/PointClassImpl.cpp b/src/PointClassImpl.cpp new file mode 100755 index 0000000..25d9b92 --- /dev/null +++ b/src/PointClassImpl.cpp @@ -0,0 +1,62 @@ +#include +#include +#include "Point.h" + +/*snake will be an array of points*/ + +using namespace std; +Point::Point(int y, int x, graphics_input img) +: x {x}, y{y}, img{img} +{} +//delegating the previous constructor +Point::Point() +:Point(10, 10, '*') +{ + +} + +Point::~Point(){ + /*No need to do something */ +} + +void Point::setPoint(int y, int x){ + this->x = x; + this->y = y; +} + +int Point::getX(void){ + return this->x; +} + +int Point::getY(void){ + return this->y; +} + +void Point::moveUp(void){ + y--; +} + +void Point::moveDown(void){ + y++; +} + +void Point::moveLeft(void){ + x--; +} + +void Point::moveRight(void){ + x++; +} + +graphics_input Point::getImg(){ + return this->img; +} +void Point::setImg(graphics_input image){ + this->img = image; +} +void Point::printImg(){ + printChar(this->y, this->x, this->img); +} +void Point::erase(void){ + this->img = ' '; +} \ No newline at end of file diff --git a/src/SnakeImpl.cpp b/src/SnakeImpl.cpp new file mode 100755 index 0000000..2e2fc68 --- /dev/null +++ b/src/SnakeImpl.cpp @@ -0,0 +1,148 @@ +#include "Snake.h" +#include +using namespace std; + +Snake::Snake(int headY, int headX) +:direction{LEFT} +{ + snake.push_back(Point{headY, headX, '>'}); //add the head of the snake + for(int i=1; i<=3; i++) + snake.push_back(Point{headY, headX+i, BODY}); + this->printSnake(); +} + +Snake::~Snake(){} + +bool Snake::isBitten(void){ + Point head = *snake.begin(); + + list::iterator body_part = snake.begin(); + body_part++; + while(body_part != snake.end()){ + if(body_part->getX() == head.getX() && body_part->getY() == head.getY()) + return true; + } + + return false; +} + +bool Snake::hasBitSnack(int snackY, int snackX){ + return readChar(snackY, snackX) == SNACK; +} + +int Snake::getSize(void){ + return snake.size(); +} + +void Snake::incSize(void){ + auto tail = snake.end(); + //since list::end() returns one element past the actual last one we will decrease by one the tail iterator + tail--; //now we actually pointing to the tail + int tailX = tail->getX(); + int tailY = tail->getY(); + + //now we must determine the direction which is easy by just fiding the coordinates of the previous to tail element + auto prev = --tail; + int prevX = prev->getX(); + int prevY = prev->getY(); + + if(prevY == tailY){ + //if the 2 part are on the same 'height' + if (prevX < tailX) //if the tail continues to the left: + snake.push_back(Point{tailY, tailX + 1, BODY}); // add one part to the right of the tail + else if(prevX > tailX) //if the tail continues to the right: + snake.push_back(Point{tailY, tailX - 1, BODY}); // add one part to the left of the tail + }else{ + if (prevY < tailY) //if the tail continues to the upper side: + snake.push_back(Point{tailY + 1, tailX, BODY}); // add one part facing down + else if (prevY > tailY) //if the tail continues to the lower side: + snake.push_back(Point{tailY - 1, tailX, BODY}); // add one part facing up + } +} + +void Snake::updateHead(void){ + auto head = snake.begin(); + switch (this->direction) + { + case UP: + head->moveUp(); + break; + + case DOWN: + head->moveDown(); + break; + + case LEFT: + head->moveLeft(); + break; + + case RIGHT: + head->moveRight(); + break; + } +} + +void Snake::printSnake(void){ + //We print each element of the snake-list + for(auto bodyPart : snake){ + bodyPart.printImg(); + } + + refreshScreen(); //finally call the previously implemented function at Graphics.cpp + //to update the screen so the changes become noticed +} + +void Snake::move(void){ + //now delete the tail print since teh snake moves forward + auto tail = snake.end(); + tail--; + printChar(tail->getY(), tail->getX(), ' '); + + //and now we have to update all the other nodes of the body + + auto bodyP1 = tail; + auto bodyP2 = --tail; + + while(bodyP2 != snake.begin()){ + *bodyP1 = *bodyP2; + bodyP1--; + bodyP2--; + } + + //update the previous to head node + auto headPrev = snake.begin(); + headPrev++; + *headPrev = *snake.begin(); + headPrev->setImg(BODY); + + //based on direction, update the head + this->updateHead(); + + this->printSnake(); // print the snake and update the screen +} + +//Move Functions: +//For the move functions we must change +void Snake::moveUp(void){ + snake.begin()->setImg('v'); + this->direction = UP; + this->move(); +} + +void Snake::moveDown(void){ + snake.begin()->setImg('^'); + this->direction = DOWN; + this->move(); +} + +void Snake::moveLeft(void){ + snake.begin()->setImg('>'); + this->direction = LEFT; + this->move(); +} + +void Snake::moveRight(void){ + snake.begin()->setImg('<'); + this->direction = RIGHT; + this->move(); +} \ No newline at end of file diff --git a/src/a.out b/src/a.out new file mode 100755 index 0000000..f23747f Binary files /dev/null and b/src/a.out differ diff --git a/src/main.cpp b/src/main.cpp new file mode 100755 index 0000000..15a3386 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,20 @@ + +#include +#include +#include "Controller.h" +using namespace std; + +int main() { + initializeGraphics(); + Controller c; + /* CODE TO BE WRITTEN... */ + graphics_input in; + while(c.wantsToQuit() == false){ + c.readInput(); + c.act(); + + } + endGraphics(); + return 0; + +} \ No newline at end of file