I have made a console game using c++ without using OOP. The code works, but is it good that way or should I have used OOP?
#include <iostream>
#include <utility>
#include <vector>
#include <Windows.h>
#include <ctime>
enum direction {
STOP, UP, DOWN, RIGHT, LEFT
};
const unsigned short width{ 50 }, height{ 20 };
unsigned short xFruit{}, yFruit{}, xTail{}, yTail{}, score{};
bool lost{ false };
std::vector<std::pair<unsigned short, unsigned short>> snake;
direction dir{ STOP };
void startGame();
void draw();
void input();
void movement();
void eatFruit();
void generateFruit();
void endGame();
void ClearScreen()
{
// Function which cleans the screen without flickering
COORD cursorPosition; cursorPosition.X = 0; cursorPosition.Y = 0; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursorPosition);
}
int main()
{
startGame();
while (!lost) {
srand(static_cast<unsigned int>(time(0)));
draw();
input();
movement();
eatFruit();
if (dir == UP || dir == DOWN)
// To slow the vertical movement
Sleep(40);
else
// To slow the horizontal movement
Sleep(20);
}
endGame();
return 0;
}
void startGame() {
srand(static_cast<unsigned int>(time(0)));
// Start at the center
snake.emplace_back(std::make_pair(width / 2, height / 2));
generateFruit();
}
void draw() {
/*
* '#' the outer frame
* '@' the head
* 'o' the body
* '*' the fruit
*/
ClearScreen();
for (unsigned short y{ 1 }; y <= height; y++) {
for (unsigned short x{ 1 }; x <= width; x++) {
if (x == 1 || x == width)
std::cout << '#';
else if (y == 1 || y == height)
std::cout << '#';
else if (x == snake.at(0).first && y == snake.at(0).second)
std::cout << '@';
else if (std::find(snake.begin() + 1, snake.end(), std::make_pair(x, y)) != snake.end())
std::cout << 'o';
else if (x == xFruit && y == yFruit)
std::cout << '*';
else
std::cout << ' ';
}
std::cout << std::endl;
}
std::cout << "Use arrow keys to move the snake" << std::endl;
std::cout << "Score: " << score << std::endl;
}
void input() {
if (GetAsyncKeyState(VK_UP) && dir != DOWN)
dir = UP;
else if (GetAsyncKeyState(VK_RIGHT) && dir != LEFT)
dir = RIGHT;
else if (GetAsyncKeyState(VK_DOWN) && dir != UP)
dir = DOWN;
else if (GetAsyncKeyState(VK_LEFT) && dir != RIGHT)
dir = LEFT;
}
void movement() {
// Move each part's place of the body to the previous part's place starting from the end of the snake to the second part
for (unsigned int part{snake.size() - 1}; part > 0; part--) {
snake.at(part) = snake.at(part - 1);
}
if (dir == UP) {
snake.at(0).second--;
// if the snake hit the top wall, move to the bottom
if (snake.at(0).second <= 1)
snake.at(0).second = height - 1;
}
else if (dir == DOWN) {
snake.at(0).second++;
// if the snake hit the bottom wall, move to the top
if (snake.at(0).second >= height)
snake.at(0).second = 2;
}
else if (dir == RIGHT) {
snake.at(0).first++;
// if the snake hit the right wall, move to the left
if (snake.at(0).first >= width)
snake.at(0).first = 2;
}
else if (dir == LEFT) {
snake.at(0).first--;
// if the snake hit the left wall, move to the right
if (snake.at(0).first <= 1)
snake.at(0).first = width - 1;
}
// If the snake hit itself
if (std::find(snake.begin()+1, snake.end(), snake.at(0)) != snake.end())
lost = true;
}
void eatFruit() {
if (snake.at(0).first == xFruit && snake.at(0).second == yFruit) {
generateFruit();
score++;
// create new part of the snake
if (dir == UP) {
xTail = snake.back().first;
yTail = snake.back().second + 1;
}
else if (dir == DOWN) {
xTail = snake.back().first;
yTail = snake.back().second - 1;
}
else if (dir == RIGHT) {
xTail = snake.back().first - 1;
yTail = snake.back().second;
}
else if (dir == LEFT) {
xTail = snake.back().first + 1;
yTail = snake.back().second;
}
snake.emplace_back(std::make_pair(xTail, yTail));
}
}
void generateFruit() {
xFruit = rand() % (width - 3) + 2;
yFruit = rand() % (height - 3) + 2;
// To check if the fruit appeared behind the snake
if (std::find(snake.begin(), snake.end(), std::make_pair(xFruit, yFruit)) != snake.end())
generateFruit();
}
void endGame() {
std::cout << "You lost, Score: " << score << std::endl;
std::cin.get();
}
movement()
:part
is declared asunsigned int
, however,snake.size()-1
isstd::size_t
. The brace initialization forbids the conversion. It builds if you declarepart
asstd::size_t
. \$\endgroup\$