C# Tutorial – Create a Classic Snake Game in Visual Studio
- Subject: C# Tutorials
- Learning Time: 4 hours
In this tutorial, we will take a look at how to create a super fun classic snake game in visual studio using C# programming language. I still remember this game from my old NOKIA phones, this game has gone through lots of different iterations over the years but the game is still lots of fun. We will be creating this awesome game in Visual Studio using the Windows Form Application template. We wont be using any game engines or external libraries to make this game. All you need is any version of visual studio and you can simply follow the tutorial through.
This tutorial is based on a game created by Michiel Wouters @ https://www.youtube.com/watch?v=i6W-aGhlq7M. He made this awesome game and we have found it to be a very effective tool to teach coding. Therefore we are going to create a text-based tutorial around it. Michiel has a lot more online tutorials and you should check them out.
Lesson Objectives –
- To create a snake game in visual studio
- To create and manage an array of snake parts in the game
- To spawn and respawn food across the screen
- To detect hit test with the border and snakes own body
- Start and restart the game
- Keep score in the game
- Manage the project and follow good programming practice by using comments and indentation
- Using different OOP (object-oriented programming) classes to allocate the snake body and game controls
- Using the system PAINT event to draw and animate SNAKE parts across the screen
- Using Keyboard events and optimising the events to respond to up, down, left and right keys
New Updated Tutorial –
UPDATED – New Create a Snake Game Tutorial with WIndows Form and C# Page with the up dated code
Download Snake Game Project on GitHub
Written Tutorial –
Start a new project in Visual Studio. We will call this project SnakeGame. This project will be saved under the Documents folder / Visual Studio 2017 / Snake Game folder.
Click OK for the project to be created in Visual Studio.
Right click on the SnakeGame inside the Solutions Explorer, hover over Add, click on Class. We will need add a few classes for our game. Let’s set it up and then we can start adding the components for the game on Windows Form.
In the name box type Circle (Capital C) and Click add. Make sure the CLASS object is highlighted in the list not anything else.
The circle class has been added to the program. Visual Studio will also open the class file for us in the code editor. Let’s add the remaining classes for the game.
Add the following 2 classes now –
- Settings
- Input
Now we have all our classes added to the project.
This is a simple practice of Object Oriented Programming. We have created 3 classes for this project that can be imported or removed from the game dynamically, this process allows us to compartmentalize the programming therefore we will not be required to code everything in one file.
Now lets go in to the Design view for the form and change some property settings
Now we have our main game screen set, time to start adding the components to the game screen. In this game we will need the following
1 Picture box – which will be used as the main game area.
3 Labels – for various information to be shown on about the game.
1 Timer Object – This timer will be used as the main game engine
Drag and drop a picture box component from the toolbox to the form.
This what the picture box looks like now. This is an empty picture box added to the form.
Now change the following in the picture boxes properties. (When you select the picture box in the form it will allow you to change several options in the properties window. The Properties window is located right under the Solutions Explorer, if for some reason you cannot find it then right click on the picture box and select properties it will show up.)
This is the picture boxes properties window. Make the following changes to it in the properties window.
Name | pbCanvas |
Back Color | Grey |
Location | 13, 13 |
Size | 541, 560 |
This is what the picture box looks like after the changes we made to its properties.
Lets go back to the ToolBox and get some labels for the game.
Now add 3 labels to the form
In the properties for label 1 change the following
Font | Bold, Size 14 |
Text | Score: |
Note to change the font in the properties window click on the three dotted … button in the properties window
In the properties for label 2 change the following
Font | Bold, Size 14 |
Text | 00 |
In the properties window for label 3 change the following
Font | Bold, Size 14 |
Back Color | Black |
Fore Color | Yellow |
Location | 215, 226 |
Text | End Text |
The main purpose for Label 3 is to show up when the game has ended and give some information. We will be changing the text dynamically using C#, so the End Text is only a place holder for now.
This is what the form looks like, now you can see that we have out Score text and a 00 text also we have the End Text in middle of the picture box.
Now let’s add a Timer to the form
In the Timer’s properties window make the following changes
Name | gameTimer |
You only need to change the of the Timer, the rest of the settings we need we can import them through the code later on. Nice Right!
Adding Events
We need several different types of Events to make this game work. We need a Key down, Key Up for the form and we also need a paint event for the picture box we added earlier.
Form event
Lets click on the form and make sure you haven’t clicked on anything else just the form and click on that little lightning bolt icon in the properties window to take you to the events window.
From the list lets find the Key Down and Key Up event
For key down type keyisdown and press and for key up type keyisup and press enter. They will take you to the code view but come back to the design view for one more event we need to add before going for the codes.
Click on the grey picture box on the form and in the events window find the Paint event and type updateGraphics
See the screen shot above.
Now with all the GUI components in place, lets start coding the game.
As you have followed thus far we have 3 different classes inserted in the game
Circle – This will be used to calculate the snakes head and body
Settings – This class will be used to check the height, width, speed and other default set ups for the game
Input – This class will be linked to the user input for example up, down, left or right
Lets start with Circle First
Double Click On the circle class and open in from the solutions explorer
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SnakeGame { class Circle { public int X { get; set; } // this is a public int class called X public int Y { get; set; } // this is a public int class called Y public Circle() { // this function is resetting the X and Y to 0 X = 0; Y = 0; } } }
Add the highlighted code from above. We are adding two different public INT classes in this Circle Class and then we have public circle function. The main purpose for this class is to give us the X and Y location of the snake object.
Since there might be a lot of back and forth between the code, it will be best if we explain the code in the comments.
// everything after the slash and colored green is a comment and we will be using this to explain the code for you.
The green text doesn’t affect the game in any way and is ignored by the compiler when the game is built so its ok to explain this here
Open the Input Class from the solutions explorer
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Collections; // The hashtable class is in the collections using System.Windows.Forms; // The keys class is in the Forms namespace SnakeGame { class Input { private static Hashtable keyTable = new Hashtable(); // we are creating a new instance of Hashtable class // this class is used to optimize the keys inserted in it public static bool KeyPress(Keys key) { // this function will return a key back to the class if (keyTable[key] == null) { // if the hashtable is empty then we return flase return false; } // if the hastable is not empty then we return true return (bool)keyTable[key]; } public static void changeState(Keys key, bool state) { // this function will change state of the keys and the player with it // this function has two arguments Key and state keyTable[key] = state; } } }
Now to the Settings class
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SnakeGame { public enum Directions { // this is a enum class called Directions // we are using enum because its easier to classify the directions // for this game Left, Right, Up, Down }; class Settings { public static int Width { get; set; } // set the width as int class public static int Height { get; set; } // set the height as int class public static int Speed { get; set; } // set the speed as int class public static int Score { get; set; } // set the score as int class public static int Points { get; set; } // set the points as int class public static bool GameOver { get; set; } // set the game over as Boolean class public static Directions direction { get; set; } // set the direction as the class we mentioned above public Settings() { // this is the default settings function Width = 16; // set the width to 16 Height = 16; // set the height to 16 Speed = 20; // set the speed to 20 Score = 0; // set the score to 0 Points = 100; // set points to 100 GameOver = false; // set game over to false direction = Directions.Down; // the default direction will be down } } }
Now its time to look at the Form1.cs file. This is where we added the key down and key up event earlier.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace SnakeGame { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void keyisdown(object sender, KeyEventArgs e) { } private void keyisup(object sender, KeyEventArgs e) { } private void updateGraphics(object sender, PaintEventArgs e) { } } }
This is the empty section now. These events don’t have anything in them to run the game for us. So we are going to add the contents to make this whole game work. Along with the empty events we have above we will be adding our own to make the game work as it should. So make sure you are following this part of the tutorial as close as you can. If you made any mistakes and visual studio throws an error at you come back and recheck the code.
We also need to the add some more functions to this game to make it work properly. We need to have another function called start game, move player, eat, generate food and die.
Lets take a look below
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace SnakeGame { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void keyisdown(object sender, KeyEventArgs e) { } private void keyisup(object sender, KeyEventArgs e) { } private void updateGraphics(object sender, PaintEventArgs e) { } private void startGame() { } private void movePlayer() { } private void generateFood() { } private void eat() { } private void die() { } } }
As you can see above we have added 4 empty functions for this game, all of this functions will complete a specific task for this game and we will be covering what goes inside of them in this tutorial. Make sure you pay extra attention to the open and closed curly brackets for this game as there are lots of them.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace SnakeGame { public partial class Form1 : Form { private List<Circle> Snake = new List<Circle>(); // creating an list array for the snake private Circle food = new Circle(); // creating a single Circle class called food public Form1() { InitializeComponent(); } } }
In the highlighted lines above we are adding two different variables but of the same class. This is a major benefit of using object oriented programming, we are able create two different objects by using the same class. Later in the program you will see how we can get them both to interact with each other.
Make the sure the lines are entered above the Form1() line. This means that both are Global Variables and they can be accessed from any function in this program. Although they both have the private initial in front they can be accessed from any function only from within this program. We cannot access them from outside the class.
public Form1() { InitializeComponent(); new Settings(); // linking the Settings Class to this Form gameTimer.Interval = 1000 / Settings.Speed; // Changing the game time to settings speed gameTimer.Tick += updateSreen; // linking a updateScreen function to the timer gameTimer.Start(); // starting the timer startGame(); // running the start game function }
Inside the Form1 function add the codes. This function runs when the form is loaded to the memory. In this function we have the initialize component function and we are also going to add our own instructions. We are creating a new settings instance and then we are adding the new values for the game timer object. The interval is like frames per second, in this case 1000 will be divided by the settings speed that was declared in the settings class. Then we are using a += to assign an EVENT to this timer tick. This EVENT will run each time the interval happens on the timer. We then start the game timer and run the start game function.
In MOOICT you have seen how to add an event from the events window, but this is a way to add an event to a component through pure code. Its much more effective to do it this way and sometimes it can save lots of time to implement.
Note – This event below has not been added through the designer so this will need to be added manually, because we are manually calling it so we will need to start with the private void again and type the whole thing over, or you can copy paste the even from below.
private void updateSreen(object sender, EventArgs e) { // this is the Timers update screen function. // each tick will run this function if (Settings.GameOver == true) { // if the game over is true and player presses enter // we run the start game function if (Input.KeyPress(Keys.Enter)) { startGame(); } } else { //if the game is not over then the following commands will be executed // below the actions will probe the keys being presse by the player // and move the accordingly if (Input.KeyPress(Keys.Right) && Settings.direction != Directions.Left) { Settings.direction = Directions.Right; } else if (Input.KeyPress(Keys.Left) && Settings.direction != Directions.Right) { Settings.direction = Directions.Left; } else if (Input.KeyPress(Keys.Up) && Settings.direction != Directions.Down) { Settings.direction = Directions.Up; } else if (Input.KeyPress(Keys.Down) && Settings.direction != Directions.Up) { Settings.direction = Directions.Down; } movePlayer(); // run move player function } pbCanvas.Invalidate(); // refresh the picture box and update the graphics on it }
Above is update screen event that’s linked to our timer object. In the event first we are checking if the game is over then we ask the player to press the enter key to restart and then start the game again. However, if the game is not over then we can do more in this function. First we check the input of the player in up, down, left and right direction. We are running the move player function that’s defined later and then we are invoking the pbsCanvas (the picture box) invalidate function. This function allows us to refresh the picture box in milliseconds, so it looks like the snake is moving in the game area. If we don’t use this invalidate function then the snake will leave a trail of dots where it moves, this way we are going to clear any non-used graphics by the snake’s movements.
private void movePlayer() { // the main loop for the snake head and parts for (int i = Snake.Count - 1; i >= 0; i--) { // if the snake head is active if (i == 0) { // move rest of the body according to which way the head is moving switch (Settings.direction) { case Directions.Right: Snake[i].X++; break; case Directions.Left: Snake[i].X--; break; case Directions.Up: Snake[i].Y--; break; case Directions.Down: Snake[i].Y++; break; } // restrict the snake from leaving the canvas int maxXpos = pbCanvas.Size.Width / Settings.Width; int maxYpos = pbCanvas.Size.Height / Settings.Height; if ( Snake[i].X < 0 || Snake[i].Y < 0 || Snake[i].X > maxXpos || Snake[i].Y > maxYpos ) { // end the game is snake either reaches edge of the canvas die(); } // detect collision with the body // this loop will check if the snake had an collision with other body parts for (int j = 1; j < Snake.Count; j++) { if (Snake[i].X == Snake[j].X && Snake[i].Y == Snake[j].Y) { // if so we run the die function die(); } } // detect collision between snake head and food if (Snake[0].X == food.X && Snake[0].Y == food.Y) { //if so we run the eat function eat(); } } else { // if there are no collisions then we continue moving the snake and its parts Snake[i].X = Snake[i - 1].X; Snake[i].Y = Snake[i - 1].Y; } } }
Above is the move player function. Since the snake has multiple parts or it can have once it starts eating. We have to ensure that the body parts of the snake follows it head. In this function we have also given it a limit of the games area where the snake can and cannot move to. We are also declaring when the snake collides with food then we can run the eat function.
private void keyisdown(object sender, KeyEventArgs e) { // the key down event will trigger the change state from the Input class Input.changeState(e.KeyCode, true); } private void keyisup(object sender, KeyEventArgs e) { // the key up event will trigger the change state from the Input class Input.changeState(e.KeyCode, false); }
Above is the key is down and up event we added to the form earlier. In both of them we are linking the input class’s change state function which will go through the hash table and return the keys back to us.
private void updateGraphics(object sender, PaintEventArgs e) { // this is where we will see the snake and its parts moving Graphics canvas = e.Graphics; // create a new graphics class called canvas if (Settings.GameOver == false) { // if the game is not over then we do the following Brush snakeColour; // create a new brush called snake colour // run a loop to check the snake parts for (int i = 0; i < Snake.Count; i++) { if (i == 0) { // colour the head of the snake black snakeColour = Brushes.Black; } else { // the rest of the body can be green snakeColour = Brushes.Green; } //draw snake body and head canvas.FillEllipse(snakeColour, new Rectangle( Snake[i].X * Settings.Width, Snake[i].Y * Settings.Height, Settings.Width, Settings.Height )); // draw food canvas.FillEllipse(Brushes.Red, new Rectangle( food.X * Settings.Width, food.Y * Settings.Height, Settings.Width, Settings.Height )); } } else { // this part will run when the game is over // it will show the game over text and make the label 3 visible on the screen string gameOver = "Game Over \n" + "Final Score is " + Settings.Score + "\n Press enter to Restart \n"; label3.Text = gameOver; label3.Visible = true; } }
Above is the update graphics event we added to the Paint option for the picture box. As you probably have guessed we are painting all the graphics and then clearing it from the picture box. Therefore, we have used the pbCanvas.Invalidate() function in the timer event. This way we make it look like the player is moving the snake in the game smoothly. In this function we are setting the colours for head, body and food also we are setting up what happens when the game is over. If the game is over, we will show the label 3 on screen with the required information.
private void startGame() { // this is the start game function label3.Visible = false; // set label 3 to invisible new Settings(); // create a new instance of settings Snake.Clear(); // clear all snake parts Circle head = new Circle { X = 10, Y = 5 }; // create a new head for the snake Snake.Add(head); // add the gead to the snake array label2.Text = Settings.Score.ToString(); // show the score to the label 2 generateFood(); // run the generate food function }
Above is the start game function. This function will run when the game actually starts. We are setting the default value for the game when it starts including setting up the head and adding it to the array.
private void generateFood() { int maxXpos = pbCanvas.Size.Width / Settings.Width; // create a maximum X position int with half the size of the play area int maxYpos = pbCanvas.Size.Height / Settings.Height; // create a maximum Y position int with half the size of the play area Random rnd = new Random(); // create a new random class food = new Circle { X = rnd.Next(0, maxXpos), Y = rnd.Next(0, maxYpos) }; // create a new food with a random x and y }
Above is the generate food function. This function will generate the food icon on a random location in the game area.
private void eat() { // add a part to body Circle body = new Circle { X = Snake[Snake.Count - 1].X, Y = Snake[Snake.Count - 1].Y }; Snake.Add(body); // add the part to the snakes array Settings.Score += Settings.Points; // increase the score for the game label2.Text = Settings.Score.ToString(); // show the score on the label 2 generateFood(); // run the generate food function }
Above is the eat function. This function will evoke when the snake and food collide. We are also going to add another sector to the snakes body and add it to the snake array.
private void die() { // change the game over Boolean to true Settings.GameOver = true; }
Above is the die function. It does what it says, it will set the game over when it runs. Usually when the snake will either hit the borders or collide with the snakes body parts.
Now lets summaries what we done
- We have added the GUI components for this game
- We have added the events for this game
- We have created 3 external classes Settings, Input and Circle
- We have added custom events to the Form1.CS file
- We have created custom functions eat(), die(), movePlayer(), generateFood() and startGame().
Now debug the program either by pressing F5 or by clicking on the start button from tool bar
Final Game screens
If you encountered an error during this time, don’t be discouraged but come back here and try to find where the error is. Usually Visual Studio does an excellent job of tracking down the line number where the error has happened and then you can see what’s wrong with it. Most of the time it will be wrong name or spelling kind of stuff, but you can always come back here and check against the code.
I’m positive my code is correct. It runs. I did have to add a line to the Program.cs main to actually get it to do anything. Not sure if I did that correctly [Form1 newGame = new Form1();], but you didn’t show that window. Nothing pops up when I run it. It gets to generateFood() inside startGame(), but after that the code stops running. I feel like the gameTimer.Tick += updateSreen line is supposed to draw something, but it doesn’t.
Hi Kevie, we are using a windows form application for this tutorial. From the comment I’m not sure how you followed the tutorial here, this program has 3 different classes added to it and it has the main game window running with all the components. Did you add the timer for the game.?
hello, iv followed this guide carefully up to writing code in form1.cs..
i went ahead and wrote the first code i was told to enter
public partial class Form1 : Form
{
private List Snake = new List(); // creating a list array for the snake
private Circle food = new Circle(); // creating a single circle class called food
public Form1()
{
InitializeComponent();
new settings();
gameTimer.Interval = 1000 / settings.Speed;
gameTimer.Tick += updateScreen;
gameTimer.Start();
startGame();
all of that is fine but a red line appears under startGame(); and im not sure why? so i left it anyway and carried on following the guide and entering the code, i noticed these things are also being highlighted by a red line
[i] i wrote this non caps like it says in the guide, but its highlighted with a red line
eat
die
these things above including startGame are all highlighted red so i ran the code in debugger because it was annoying me, and it gave me 20 errors saying the things i mentioned above do not exist in the current context, im not sure why as i copied this guide very carefully? iv read through it three times and i can’t see what’s gone wrong, its windows form application ect so i know its not that, can anyone help me please?
i got up to forms1.cs and typed the code very carefully following exactly what it says in the guide case sensitive, immediately i noticed a redline highlighting startGame();
i ignored it and continued up until food function where i stopped because there are multiple words or letters highlighted like this, the following are highlighted red
startGame();
[i] < not capitalised like in the guide
food
die
these are all highlighted red through the code that is written EXACTLY as shown in the guide, i ran it in debuggers and got 20 errors saying, " the name ' die ' doesn't exist in the current context "
each error was the same for each of these words above, i went back through the guide 3 more times before giving up because i really can't find where i've gone wrong i feel like something is missing from the guide that defines these words and letters? it is windows form application, can someone help me please?
how do you work this thing I don`t know how to work it at all
I think you might have missed the die function fro the code. The die function will end the game and show the end text to the form. Can you double check this.
What would be the appropriate coding to have game play with snake running through the edges of the canvas to come out the other side?
Where did you get the updatescreen? i looked all thru the tutorial and nothing is showing up
Tutorials first step incorrect. Need to choose project template visual c#->windows desktop->windows forms apps . Template populate program.cs with required statements.
How do we write that little star in this part:
canvas.FillEllipse(snakeColour,
new Rectangle(
Snake[i].x Settings.Width,
Snake[i].y Settings.Height,
Settings.Width, Settings.Width
));
?
I always get errors regards to Keypress, why is that ?
How can I make this program run by pressing a button?????? The form loads when I use private void button1_Click(object sender, EventArgs e)
{
gameTimer.Start();
startGame();
}
but I can’t play it.
Dear Author,
I followed the instructions in the PDF, and I ended up not having any warning signs, but when I start the game (F5) the head doesn’t show up, Do you have any idea what can cause this?
The code code work, but i don’t understand why it semms that the Food isn’t where my red circle is… When I run in debug with some breakpoints the code works, but normal speed don’t work.
No, but yes it’s the tutorial that worries … Ha bah no! I just did it and everything works flawless … Thanks for your work I’m learning a lot of stuff ..
I specify that I am FR and that the translation does not work on the tutorial so it is very clear!
BEFORE YOU GO TO BUG CHECK “YOUR” CODE;)
i have an System.NullReferenceException in the class Input at the line 22. i check my code and i searsh on google but nothing. please help me
Only Error im getting is with the gameTimer.Tick += updateScreen; its saying no overload for ‘updateScreen’ matches delegate ‘EventHandler’
any suggestions?
i have followed the tutorial but I have ended up with a window without any circles (red-fruit or black – head)! Do you know which step should i have followed better in order to generate those circles at all
it cannot eat the generated food it just passes the food. even though i thoroughly follow the instructions .
For some reason I am unable to see the food, I know it is there because I can accidentally run into it and the Snake gets bigger but I cannot see it.
nevermind, I fixed it
I get an error under this class ” private void movePlayer() ”
else
{
// If there are no collisions then we continue moving the snake and its parts
snake[i].x = snake[i – 1].x;
snake[i].y = snake[i – 1].y;
I can start the game if i change the value from 1 to 0, but then i can only eat 1 apple then its game over. Dont really know whats wrong. I get an unhadled exception error when i try to debug.
I try to add a second form, but when I call it and close, i lost touch with the main form. The form doesn’t read any key. It also happens i place a button
Once I press the start button, a black window pop up and it disappear in a second,i cant find wheres the problem,i hav no error,it is running, but nothings come out
Im 100 percent certain my code is right, yet when I start the program and use the keys on my keyboard it doenst move the snake????
Hallo,
Thanks a lot for your wonderful sharing. I like it and play with my children 🙂
only thing I want to add that you are adding food in snake.count loop. It means you add it a lot of times.
You can not see a problem because it is added a lot of time at same pixels.
Regards
For the people having trouble with the updateScreen method, make sure that when declaring the method you write EventArgs and not KeyEventArgs. Regards 🙂
Code seems to jump around from form to form… INCREDIBLY hard to follow which one to type what in.
my snake is not moving . let me the solution so that i’ll be able to complete this project.
when I run the code, the snake and food don’t appear only the board and score
It helped a lot