C++ Snake Tutorial!
Posted: Sat Oct 24, 2015 7:52 pm
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:
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:
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:
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:
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:
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:
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!
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
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
}
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
}
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;
}
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;
}
}
}
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
}
}
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!