Browse Source

Controller ready, Input methods ready, Board Ready, Snake collision events to be made and Snack class to be implemented

pull/1/head
VissaMoutafis 5 years ago
commit
bf2edd9fc2
  1. 1
      .vscode/.easycpp
  2. 26
      .vscode/launch.json
  3. 6
      .vscode/settings.json
  4. 26
      .vscode/tasks.json
  5. 23
      Makefile
  6. BIN
      bin/main
  7. 20
      include/Controller.h
  8. 0
      include/Game.h
  9. 20
      include/Graphics.h
  10. 0
      include/Player.h
  11. 26
      include/Point.h
  12. 31
      include/Snake.h
  13. 50
      src/Controller.cpp
  14. 72
      src/Graphics.cpp
  15. 62
      src/PointClassImpl.cpp
  16. 148
      src/SnakeImpl.cpp
  17. BIN
      src/a.out
  18. 20
      src/main.cpp

1
.vscode/.easycpp

@ -0,0 +1 @@
This file is created by Easy C++ Projects, please ignore and do not delete it

26
.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
}
]
}
]
}

6
.vscode/settings.json

@ -0,0 +1,6 @@
{
"files.associations": {
"*.tpp": "cpp"
},
"terminal.integrated.shell.windows": "cmd.exe"
}

26
.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"
]
}
]
}

23
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)/*

BIN
bin/main

20
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
};

0
include/Game.h

20
include/Graphics.h

@ -0,0 +1,20 @@
#pragma once
#include <curses.h> //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();

0
include/Player.h

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

31
include/Snake.h

@ -0,0 +1,31 @@
#pragma once
#include <list>
#include "Point.h" //the library we need to implement the snake
#define SNACK '*'
#define BODY 'o'
class Snake{
private:
std::list<Point> 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
};

50
src/Controller.cpp

@ -0,0 +1,50 @@
#include "Controller.h"
#include <assert.h>
#include <iostream>
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;
}

72
src/Graphics.cpp

@ -0,0 +1,72 @@
#include "Graphics.h"
#include <chrono>
#include <thread>
///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();
}

62
src/PointClassImpl.cpp

@ -0,0 +1,62 @@
#include <iostream>
#include <string>
#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 = ' ';
}

148
src/SnakeImpl.cpp

@ -0,0 +1,148 @@
#include "Snake.h"
#include <iostream>
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<Point>::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();
}

BIN
src/a.out

20
src/main.cpp

@ -0,0 +1,20 @@
#include <ncurses.h>
#include <iostream>
#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;
}
Loading…
Cancel
Save