I wrote a Snake Game in C++ and I have practiced some OOP approaches. I would really appreciate criticism and some advice.
snakeGame.h
#ifndef _SNAKEGAME_H
#define _SNAKEGAME_H
#include<SFML/Graphics.hpp>
#include<map>
#include<memory>
#define maxSnakeLenght 100
class SnakeGame{
public:
SnakeGame(int size=16, int width=25, int height=25, int timeDelay=60000)
:size(size), width(width), height(height),
widthWindow(size*width),
heightWindow(size*height),
timeDelay(timeDelay)
{}
void mainLogic();
private:
int size, width, height, timeDelay;
std::size_t widthWindow, heightWindow,sizeOfSnake=3;
class KeyboardEvents;
std::map<sf::Keyboard::Key, std::shared_ptr<KeyboardEvents>> mapOfEvents;
sf::RenderWindow window;
sf::Texture texRed,texGreen;
sf::Sprite redFoodSprite,greenSnakeSprite;
sf::Keyboard::Key mainEvent=sf::Keyboard::Down; // always correct keyboard code
sf::Keyboard::Key codeFromKeyboard;
sf::Event event;
struct Snake{ int xCoor,yCoor; }snake[100];
struct Food{ int xCoor=10,yCoor=10; }food;
//functions
//
//bind with snake actions
void snakeMovements();
bool snakeAteFood();
bool enmeshingSnake(); // when snake will enmeshing itself, it's size will be reduced
void moveSnakeForward();
void turnSnakeUp();
void makeNewFood();
bool selfCollision(int);
bool collisionSnakeWithFood();
void snakeOutOfFrame(); // change coordinates when snake is beyond of frame
void snakeSpeed(int);
void delayTimeDecrease();
void updateEvents();
void updateMovements();
//bind with frame
void drawScreen(sf::Sprite&,sf::Sprite&,sf::RenderWindow&);
void draw();
void loadImage(const std::string&,sf::Texture&,sf::Sprite&);
void initWindow();
//bind with keyboard
void chooseMethodByKeyboard();
void chooseMethodFromKeyboardEvents(sf::Keyboard::Key);
void initializeEventsMap();
/*********************************************************************************************************
/
/ EventsFromKeyboard Familly
/
/
**********************************************************************************************************/
class KeyboardEvents{
public:
virtual ~KeyboardEvents(){};
virtual void event(SnakeGame&)=0;
};
class GoRight:public KeyboardEvents{
private:
void event(SnakeGame& snakeObj);
};
class GoLeft:public KeyboardEvents{
private:
void event(SnakeGame& snakeObj);
};
class GoUp:public KeyboardEvents{
private:
void event(SnakeGame& snakeObj);
};
class GoDown:public KeyboardEvents{
private:
void event(SnakeGame& snakeObj);
};
class Exit:public KeyboardEvents{
private:
void event(SnakeGame& snakeObj);
};
class Pause:public KeyboardEvents{
private:
void event(SnakeGame& snakeObj);
};
};
#endif
snakeGame.cpp
#include"snakeGame.h"
#include<SFML/Graphics.hpp>
#include<map>
#include<ctime>
#include<iostream>
#include<unistd.h>
void SnakeGame::mainLogic(){
initWindow();
while(window.isOpen()){
updateEvents();
updateMovements();
draw();
}
}
/*********************************************************************************************************
/
/
/ PRIVATE FUNCTIONS
/
/
/
/
**********************************************************************************************************/
void SnakeGame::initWindow(){
srand(time(0));
initializeEventsMap();
window.create( sf::VideoMode(widthWindow, heightWindow), "SnakeGame", sf::Style::Titlebar);
loadImage("images/red.png", texRed, redFoodSprite);
loadImage("images/green.png", texGreen, greenSnakeSprite);
}
void SnakeGame::snakeMovements(){
moveSnakeForward();
if(snakeAteFood()){
++sizeOfSnake;
delayTimeDecrease();
}
snakeOutOfFrame(); //change coordinates when snake is beyond of frame
turnSnakeUp();
}
void SnakeGame::updateEvents(){
while(window.pollEvent(event)){
if(event.type == sf::Event::Closed)
window.close();
}
}
void SnakeGame::updateMovements(){
snakeMovements();
chooseMethodFromKeyboardEvents(codeFromKeyboard);
codeFromKeyboard=event.key.code; // take direction form keyboard
snakeSpeed(timeDelay);
}
void SnakeGame::chooseMethodFromKeyboardEvents(sf::Keyboard::Key codeFromKeyboard){
auto iterator = mapOfEvents.find(codeFromKeyboard);
if(iterator!=mapOfEvents.end()){
iterator->second->event(*this);//left , right,up , down, pause
mainEvent=codeFromKeyboard;
}
else mapOfEvents[mainEvent]->event(*this);
}
bool SnakeGame::snakeAteFood(){
if(collisionSnakeWithFood()){
makeNewFood();
return true;
}
return false;
}
bool SnakeGame::collisionSnakeWithFood(){
return (snake[0].xCoor==food.xCoor) && (snake[0].yCoor==food.yCoor);
}
bool SnakeGame::enmeshingSnake(){
for(int i=2;i<sizeOfSnake;++i)
if(selfCollision(i))
return true;
return false;
}
bool SnakeGame::selfCollision(int i){
return ((snake[0].xCoor==snake[i].xCoor) && (snake[0].yCoor==snake[i].yCoor));
}
void SnakeGame::snakeOutOfFrame(){
if(snake[0].yCoor>height-2){
snake[0].yCoor=0;
}
if(snake[0].xCoor<0){
snake[0].xCoor=width;
}
if(snake[0].xCoor>width){
snake[0].xCoor=0;
}
if(snake[0].yCoor<0){
snake[0].yCoor=height-2;
}
}
void SnakeGame::snakeSpeed(int delay){
usleep(delay);
}
void SnakeGame::delayTimeDecrease(){
timeDelay=timeDelay-1500;
}
void SnakeGame::initializeEventsMap(){
mapOfEvents[sf::Keyboard::Right] = std::shared_ptr<KeyboardEvents>(new GoRight);
mapOfEvents[sf::Keyboard::Left] = std::shared_ptr<KeyboardEvents>(new GoLeft);
mapOfEvents[sf::Keyboard::Up] = std::shared_ptr<KeyboardEvents>(new GoUp);
mapOfEvents[sf::Keyboard::Down] = std::shared_ptr<KeyboardEvents>(new GoDown);
mapOfEvents[sf::Keyboard::Space] = std::shared_ptr<KeyboardEvents>(new Pause);
mapOfEvents[sf::Keyboard::Escape] = std::shared_ptr<KeyboardEvents>(new Exit);
}
void SnakeGame::draw(){
window.clear();
drawScreen(redFoodSprite, greenSnakeSprite, window);
window.display();
}
void SnakeGame::drawScreen( sf::Sprite& redFood, sf::Sprite& greenSnake, sf::RenderWindow& window){
for(int i=0;i<sizeOfSnake;++i){
greenSnake.setPosition(snake[i].xCoor*size, snake[i].yCoor*size);
window.draw(greenSnake);
}
redFood.setPosition(food.xCoor*size,food.yCoor*size);
window.draw(redFood);
}
void SnakeGame::loadImage( const std::string& path, sf::Texture& tex, sf::Sprite& sprite){
tex.loadFromFile(path);
sprite.setTexture(tex);
}
void SnakeGame::moveSnakeForward(){
for(int i=sizeOfSnake;i>0;--i){ // slither snake
snake[i].xCoor=snake[i-1].xCoor;
snake[i].yCoor=snake[i-1].yCoor;
}
}
void SnakeGame::turnSnakeUp(){
if(enmeshingSnake()){
if(sizeOfSnake>5){
sizeOfSnake=sizeOfSnake-3;
timeDelay=timeDelay+3000; // come back to orginal timeDelay
}
}
}
void SnakeGame::makeNewFood(){
food.xCoor = rand()%width;
food.yCoor = rand()%height;
}
/*********************************************************************************************************
/
/
/ EVENTS FORM KEYBOARD FAMILLY
/
/
/
/
**********************************************************************************************************/
/*********************************************************************************************************
* DIRECTIONS
**********************************************************************************************************/
void SnakeGame::GoRight::event(SnakeGame& snakeObj){
snakeObj.snake[0].xCoor+=1;
}
void SnakeGame::GoLeft::event(SnakeGame& snakeObj){
snakeObj.snake[0].xCoor-=1;
}
void SnakeGame::GoUp::event(SnakeGame& snakeObj){
snakeObj.snake[0].yCoor-=1;
}
void SnakeGame::GoDown::event(SnakeGame& snakeObj){
snakeObj.snake[0].yCoor+=1;
}
/*********************************************************************************************************
* SPECIAL EVENTS
**********************************************************************************************************/
void SnakeGame::Pause::event(SnakeGame& snakeObj){ }
void SnakeGame::Exit::event(SnakeGame& snakeObj){
snakeObj.window.close();
}
length
, notlenght
! \$\endgroup\$