C++ Snake Tutorial!

Post all your tuts or request for tuts here.
Post Reply
User avatar
62896dude
Posts: 516
Joined: Thu Jan 20, 2011 2:39 am

C++ Snake Tutorial!

Post by 62896dude »

Thissssss (bad snake joke) is my first tutorial on here, but I hope to be able to do more in the future!

This is a very simple snake game programmed in C++ (to be played through the console). I myself followed a tutorial to make this, and then made some minor modifications. I also then went through and commented almost every line of the code to help others understand what is happening. If you have any questions, feel free to let me know. Otherwise, let's get started!

Definitions/opening comments:

Code: Select all

//C++ Snake Game
//10/12/15
//Code written by following a tutorial from: https://www.youtube.com/watch?v=PSoLD9mVXTA
//Adjustments and comments written by Kevin Hill
//The main purpose of this is to use the comments to better understand what is happening throughout the program

#include "stdafx.h"
#include "windows.h"
#include <iostream>
#include <conio.h>
using namespace std;
bool gameOver;
const int width = 20;//border width
const int height = 20;//border height
int x, y, fruitX, fruitY, score;
int tailX[100], tailY[100];//max number of tails is 100
int nTail;//number of tails
enum eDirection { STOP = 0, LEFT, RIGHT, UP, DOWN };//different possible directions
eDirection dir;//variable to hold active direction
All of the variable definitions are reasonably self explanatory. All of those #include X lines are to ensure that proper libraries are being drawn from when using certain bits of code (such as eDirection). It's worth noting that <iostream> is essential and can be though of as the main library to make just about any C++ program run.


Main() function:

Code: Select all

int main()
{
	Setup();
	while (!gameOver) {
		Draw();//builds the map, snake, and fruit
		Input();//detects key inputs
		Logic();//all game logic
		Sleep(100);//change this number based on how fast your CPU is
	}
    return 0;//for those unfamiliar with C++, all main functions should end with this
}
The main() function is very straightforward. The idea is to make it as clean as possible, and save the complexities for each of the individual functions. "while (!gameOver)" ensures that this is a continuous loop since the default for gameOver is false. As soon as it becomes true, the loop will end and the console will close. As a side note, I generally put my main() function at the very end of my code, but I figured it would be best to show it near the beginning to give a preview/idea of how this program works logically. So now for the fun stuff, let's dive into each of those functions!


Setup() function:

Code: Select all

void Setup() {
        gameOver = false;//game is running, snake still alive
	dir = STOP;//start the game not moving
	x = width / 2;//center of screen x
	y = height / 2;//center of screen y
	fruitX = rand() % width;//random fruit x location
	fruitY = rand() % height;//random fruit y location
	score = 0;//score counter
}
The purpose of the Setup() function is, you guessed it, to setup the needed variables that will be called upon in other functions. The fruit is what the snake will be eating to increase its size, so we want to make sure that the position is both randomized and within the bounds of the grid. We also want "dir = STOP" because we don't want the snake moving until the player is ready.


Draw() function:

Code: Select all

void Draw() {
	system("cls");//clear screen
	//draw border along x axis (top)
	for (int i = 0; i < width+1; i++)
		cout << "#";
	cout << endl;//move on to next line
	//scan along y axis
	for (int i = 0; i < height; i++) {
		//scan along x axis
		for (int j = 0; j < width; j++) {
			//draw border along y axis (left)
			if (j == 0)
				cout << "#";
			//draw snake head
			if (i == y && j == x)
				cout << "O";
			//draw fruit "F"
			else if (i == fruitY && j == fruitX)
				cout << "F";
			else {
				bool print = false;//default is to print extra space
				//run through every tail in the tail array
				for (int k = 0; k < nTail; k++) {
					//check for printing snake tail
					if (tailX[k] == j && tailY[k] == i) {
						cout << "o";//print snake tail "o"
						print = true;//print "o" instead of extra space
					}
				}
				//if not printing a tail, print a blank space
				if (!print)
					cout << " ";
			}
			//draw border along y axis (right)
			if (j == width - 1)
				cout << "#";
		}
		cout << endl;//move on to next line
	}
	//draw border along x axis (bottom)
	for (int i = 0; i < width+1; i++)
		cout << "#";
	cout << endl;
	cout << "Score: " << score << endl;
}
Here is where it starts to get a little more complicated, but bear with me on this one. The basic idea of the Draw() function is to draw out the map based upon the variables we have already set in place. Note that Draw() is within the for loop, so it will constantly be drawing the map/updating based upon how the game is unfolding. It consists of numerous for loops so that it can properly scan through the window and draw as needed. It will draw a "#" for the borders, and "O" for the snake head, and "o" for the snake tail. The way this is programmed to work is that the for loops are constantly checking to see if it should be printing the Snake/tail somewhere, and wherever it ISN'T, it will print blank space to ensure the map is always filled out evenly. I've done my best to comment through this, but if you have any confusions with it don't hesitate to ask!


Input() function:

Code: Select all

void Input() {
	//if a key is hit
	if (_kbhit()) {
		//fetch the character that was hit
		switch (_getch()) {
		//if character was "a", switch left
		case 'a':	dir = LEFT;
					break;
		//if character was "d", switch right
		case 'd':	dir = RIGHT;
					break;
		//if character was "w", switch up
		case 'w':	dir = UP;
					break;
		//if character was "s", switch down
		case 's':	dir = DOWN;
					break;
		//if character was "x", end the game
		case 'x':	gameOver = true;
					break;
		}
	}
}
This is a very simple function. It strictly is checking for keyboard input from the user to change the direction of the snake. "x" ends the game, and "w,a,s,d" is used as the standard arrows. By changing the direction, the snake will constantly move in that direction. It is only ever set to STOP when the game is first started.


Logic() function:

Code: Select all

void Logic() {
	int prevX = tailX[0];
	int prevY = tailY[0];
	int prev2X, prev2Y;
	tailX[0] = x;//tail x goes to where snake x just was
	tailY[0] = y;//tail y goes to where snake y just was
	//update tail location(s)
	for (int i = 1; i < nTail; i++) {
		prev2X = tailX[i];
		prev2Y = tailY[i];
		tailX[i] = prevX;
		tailY[i] = prevY;
		prevX = prev2X;
		prevY = prev2Y;
	}
	//change direction
	switch (dir) {
	//left
	case LEFT:
		x--;
		break;
	//right
	case RIGHT:
		x++;
		break;
	//up
	case UP:
		y--;
		break;
	//down
	case DOWN:
		y++;
		break;
	default:
		break;
	}
	//terminate if snake goes out of bounds
	if (x > width || x < 0 || y > height || y < 0)
		gameOver = true;
	//increment through every "o" in the tail
	for (int i = 0; i < nTail; i++) {
		//terminate if snake head touches tail
		if (tailX[i] == x && tailY[i] == y)
			gameOver = true;
	}
	//if snake runs into the fruit
	if (x == fruitX && y == fruitY) {
		score += 10;//increase score by 10
		fruitX = rand() % width;//set new rand X
		fruitY = rand() % height;//set new rand Y
		nTail++;//grow tail
	}
}
The Logic() function is the brains of the operation. This is where score is updated, tail movements are recorded, and where it is constantly checking for game over actions (running into the wall or catching your tail. This game is not advised for dogs.) Also important is the fruit location, which is immediately regenerated in a random location once the user successfully eats it.

That's all I've got for you guys on this one. If you have any questions or suggested improvements, feel free to let me know and I'd be happy to address or incorporate them. I'm always looking to improve, and I hope that this was helpful for some of you!
Languages: C++, C#, Javascript + Angular, PHP
Programs: Webstorm 2017, Notepad++, Photoshop
Current Project: HP Destiny
Post Reply

Return to “Tutorials”