In this blog, we will learn how to create a Snake game using C++. The Snake game is a classic and popular game in which the player controls a snake that moves around the screen, trying to eat food and avoid colliding with walls or its own tail. We will go through the process step by step and explain the necessary functions and parameters used in the code.
Prerequisites
Before we start coding, make sure you have a basic understanding of C++ programming language and the concepts of variables, loops, and functions.
Also, make sure you have a C++ compiler installed on your system. You can choose any popular compiler such as GCC or Microsoft Visual C++. Set up your development environment by installing the compiler and a suitable integrated development environment (IDE) such as Code::Blocks or Visual Studio.
Setting Up the Snake Game
Let’s start by setting up the basic structure of our Snake game. We will define the necessary variables and initialize the game’s initial state.
#include <iostream>
#include <conio.h>
#include <stdio.h>
#include <Windows.h>
bool gameOver;
const int width = 20;
const int height = 20;
int x, y, fruitX, fruitY, score;
int tailX[100], tailY[100];
int nTail;
std::string fruit = "*";
enum eDirections
{
STOP = 0,
LEFT,
RIGHT,
UP,
DOWN
};
eDirections dir;
void Setup()
{
gameOver = false;
dir = STOP;
x = width / 2;
y = height / 2;
fruitX = rand() % width + 1;
fruitY = rand() % height + 1;
score = 0;
}
In the code above, we have declared the necessary variables for the game. Here’s a brief explanation of each variable:
gameOver
: Keeps track of whether the game is over or not.width
andheight
: Define the dimensions of the game screen.x
andy
: Represent the current position of the snake.fruitX
andfruitY
: Represent the position of the fruit that the snake needs to eat.score
: Stores the player’s score.tailX
andtailY
: Arrays to store the positions of the snake’s tail.nTail
: Keeps track of the length of the snake’s tail.fruit
: Represents the character used to display the fruit on the screen.eDirections
: An enumeration to represent the possible directions the snake can move.
The Setup()
function initializes these variables with their initial values, positioning the snake at the center of the screen and randomly placing the fruit.
Draw Boundary for the Snake Game
Next, we’ll implement the Draw()
function, which will be responsible for rendering the game screen and displaying the snake, fruit, and score.
void Draw()
{
system("cls");
for (int i = 0; i < width + 2; i++)
{
std::cout << "#";
}
std::cout << std::endl;
for (int i = 1; i <= height; i++)
{
for (int j = 1; j <= width + 1; j++)
{
if (j == 1 || j == width + 1)
std::cout << "#";
if (i == y && j == x)
{
std::cout << "O";
}
else if (j == fruitX && i == fruitY)
{
std::cout << fruit;
}
else
{
bool print = false;
for (int k = 0; k < nTail; k++)
{
if (tailX[k] == j && tailY[k] == i)
{
std::cout << "o";
print = true;
}
}
if (!print)
std::cout << " ";
}
}
std::cout << std::endl;
}
for (int i = 0; i < width + 2; i++)
{
std::cout << "#";
}
std::cout << std::endl;
std::cout << "Score: " << score << std::endl;
}
The Draw()
function uses a combination of loops and conditional statements to draw each element of the game on the console screen. Here’s what each part of the code does:
system("cls")
: Clears the console screen.- The first loop prints the top border of the game screen, consisting of “#” characters.
- The second loop iterates over each row of the game screen.
- The nested loop iterates over each column of the game screen.
- If the current position matches the snake’s head (x, y), it prints “O” to represent the snake’s head.
- If the current position matches the fruit’s position (fruitX, fruitY), it prints the fruit character.
- If the current position matches any segment of the snake’s tail, it prints “o” to represent the snake’s tail.
- If none of the above conditions are met, it prints an empty space.
- After each row, a new line is printed.
- Finally, the bottom border and the player’s score are displayed.
Handling User Input in Snake Game
Now, let’s implement the Input()
function, which will be responsible for handling user input and updating the snake’s direction accordingly.
void Input()
{
if (_kbhit())
{
switch (_getch())
{
case 'a':
dir = LEFT;
break;
case 'd':
dir = RIGHT;
break;
case 'w':
dir = UP;
break;
case 's':
dir = DOWN;
break;
case 'x':
gameOver = true;
break;
}
}
}
The Input()
function uses the _kbhit()
and _getch()
functions from the conio.h
library to detect keyboard input. Here’s what each part of the code does:
_kbhit()
: Checks if a key is currently being pressed._getch()
: Retrieves the character of the pressed key.
The switch
statement checks the value of the pressed key and updates the dir
variable accordingly. The possible directions are:
- ‘a’: LEFT
- ‘d’: RIGHT
- ‘w’: UP
- ‘s’: DOWN
- ‘x’: Exit the game
Updating the Snake Game Logic
The Logic()
function is responsible for updating the game’s logic, including moving the snake, detecting collisions, and updating the score.
void Logic()
{
int prevX = tailX[0];
int prevY = tailY[0];
int prev2X, prev2Y;
tailX[0] = x;
tailY[0] = y;
for (int i = 1; i < nTail; i++)
{
prev2X = tailX[i];
prev2Y = tailY[i];
tailX[i] = prevX;
tailY[i] = prevY;
prevX = prev2X;
prevY = prev2Y;
}
switch (dir)
{
case LEFT:
x--;
break;
case RIGHT:
x++;
break;
case UP:
y--;
break;
case DOWN:
y++;
break;
}
if ((x > width || x < 0) || (y > height || y < 0))
{
std::cout << "\t\tGame Over" << std::endl;
std::cout << "\t You Hit the wall!";
gameOver = true;
}
for (int i = 0; i < nTail; i++)
{
if (tailX[i] == x && tailY[i] == y)
{
std::cout << "\t\tGame Over" << std::endl;
std::cout << "\t You Hit the Tail!";
gameOver = true;
}
}
if (x == fruitX && y == fruitY)
{
score += 10;
nTail++;
fruitX = rand() % width + 1;
fruitY = rand() % height + 1;
}
}
In the Logic()
function, we update the snake’s position based on the current direction. Here’s what each part of the code does:
- We store the previous position of the snake’s head in
prevX
andprevY
. - We update the first element of the tail arrays (
tailX[0]
andtailY[0]
) with the new position of the snake’s head (x
andy
). - We update the rest of the tail by shifting the previous positions forward.
- We update the snake’s head position based on the current direction.
- We check if the snake has hit the wall. If it has, we set
gameOver
to true and display a game over message. - We check if the snake has collided with its own tail. If it has, we set
gameOver
to true and display a game over message. - We check if the snake has eaten the fruit. If it has, we increase the score, increase the length of the tail, and generate a new random position for the fruit.
Putting It All Together
Now that we have implemented all the necessary functions, let’s write the main()
function to put everything together and run the game.
int main()
{
Setup();
while (!gameOver)
{
Draw();
Input();
Logic();
Sleep(150);
}
std::cout << fruitX << " " << fruitY;
return 0;
}
In the main()
function, we call the Setup()
function to initialize the game. Then, we enter a game loop that continues until gameOver
is true. Inside the loop, we call the Draw()
, Input()
, and Logic()
functions to update and render the game. We also add a small delay between each frame using the Sleep()
function to control the speed of the game.
Wrapping Up
Congratulations! You have successfully created a Snake game in C++ using the console. You learned how to handle user input, update the game logic, and display the game screen. Feel free to experiment and add new features to the game, such as sound effects or additional levels.
I hope you enjoyed this tutorial and found it informative. If you have any questions or suggestions, feel free to leave a comment below. Happy coding!
Reference
- Snake Game GitHub Code: https://github.com/divshekhar/SnakeGameCPP