Implementing the Snake Game in Python

Editor
26 Min Read


cellphone my mother had is closely related to the game it had. Yes, the classical snake game, so simple yet so addicting. I remember playing this game on end on my mother’s phone, losing and then trying again and again!

In this article, we will learn to build a simple Snake Game. We will use Python’s turtle module in order to generate this game. Note that this is a beginners to intermediate level Python tutorial, and expects the reader to be familiar with Python fundamentals such as functions and loops, importing and accessing modules, and using conditional statements. It also requires one to have a surface-level understanding of Object Oriented Programming, especially creating objects instances from classes. For the sake of simplicity, I will explain each and every line of code. Let’s get started!

Snake Game (Image by Author)

Understanding the Game

The classical Snake game involves a small snake with a plain background. Food is provided on the screen. As the snake eats the food, it grows in size, and the score increases. As soon as the snake collides with the boundary wall or itself, the game ends, and one loses.

In order to code this game in Python, we will need to address the following points:

  1. Setting up the Game Screen – in the classical Snake game, the background is a dull neon yellow-green screen
  2. Creating the Snake body – the game starts with a small black snake, which gradually increases in size as it eats the food
  3. Moving the Snake – the snake can move in the 4 directions: up, down, left, and right through the arrow keys on the keyboard or corresponding buttons on the phone
  4. Creating the Food – the food for the snake appears at random locations on the screen
  5. The Snake eating the Food – as the snake’s body collides with the food created, the score is increased as well as the length of the snake, and new food is generated randomly, and the game continues.
  6. The Snake Colliding with itself or the Boundary Wall – if the snake’s body collides with itself or the boundary of the game screen, the game ends.

Let us start coding.

Setting up the Game Screen

First things first, we will create a new project in our IDE, let’s call it “Snake Game”. I am using PyCharm to code. Next, we will create a new “snake game.py” file. First of all, we will import the Turtle module, specifically its Screen and Turtle classes.

from turtle import Screen, Turtle

The Turtle Module is a built-in Python package that allows one to draw shapes, lines, patterns, and animations on a screen through code. The module works as if there is a turtle with a brush on its back, and whatever you command it to go to, it will go there, thereby creating drawings. You can ask the turtle to move forward, to turn left by a certain angle, draw a circle etc. The turtle will draw exactly that, and it is an easy tool to visualize one’s code. It helps practising variables, loops, functions, coordinates, and basic animation logic with instant visual outputs.

You can check out the Turtle Official Documentation here.

As can be seen in the line of code above, we have imported two elements: Screen and Turtle. These are classes that are defined in the module. In Python, a class is a blueprint used to create objects. Turtle and Screen are classes which will be used to create corresponding objects. These objects will have attributes (variables) and methods (functions) as defined in their blueprint, with the provision of customization.

Let us first create the background for our game. We will use the Screen class for this purpose and customise it according to our requirements. For reference, check the Screen methods from the official documentation here.

#Setting up the Game Screen
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("green yellow")
screen.title("Snake Game")
screen.tracer(0)

screen.exitonclick()

As can be seen in the code above, we first created the screen object from the Screen Class. Next, we have used the setup() method of the Screen class and set the width of the Game Screen to 600×600. We have customized the background color to “green yellow” using the bgcolor() method. The name of the color can be found through this link. I selected the color that closely resembled the color in the original game. After that, we have named the screen “Snake Game” using the title() method. The tracer() method from the Turtle class lets us control the animation. By giving an argument of “0”, we have turned it off. This will be better understood when we create the snake and food. Lastly, we have used the exitonclick() method to set the window to close only when we click on it. Otherwise, the window closes as soon as it pops up and executes the whole code.

Running the code above would output the following:

The Game Screen (Image by Author)

Creating the Snake Body

Once we have created the Game Screen, the next task is to create the snake. The snake will also be created using the Turtle class. We will create 3 turtle objects that won’t resemble a turtle at all. Rather, they will be square segments, and when placed together, will resemble a snake’s body, just like in the game. For this purpose, we will use a for loop to create the 3 segments. Each segment will be placed at a specified position. Let us code this:

#Creating the Snake
segments = []
starting_positions = [(0,0), (-20,0), (-40,0)]
for position in starting_positions:
    new_segment = Turtle("square")
    new_segment.color("black")
    new_segment.penup()
    new_segment.shapesize(1,1)
    new_segment.goto(position)
    segments.append(new_segment)

screen.update()

In the code above, we first created an empty list of segments. This list will contain the snake segments. Once the snake segments are created, it will consist of 3 segments, and whenever the snake eats its food, the number of segments will increase. We have created a tuple starting_positions. This will contain 3 positions specified in terms of their x and y coordinates, and will be the positions where the snake segments will be created. We will create the first segment at (0,0), the second at (-20,0), and the third segment at (-40,0). Using the for loop, we have created 3 segments from the variable new_segment as a turtle object, of square shape and standard size 20×20. The arguments to shapesize() method is given as 1×1 as it stretches the size of the drawing cursor relative to its default 20×20 pixel size. The penup() method allows us to hide the pen, and just output the shape of the turtle object. The goto() method allows us to create the shape starting from that position. Lastly, we have appended the newly created segment to the empty list we created in the beginning of this code block. In this way, 2 more segments will be created as there are 2 more positions in the starting_positions tuple.

In the end, we will update our screen so that it now shows both the customized screen and the newly created snake. This will be the output:

Creating the Snake Body (Image by Author)

Notice that we have created the segments using just the for loop. As we go ahead in our program, we will need to increase the snake’s segments as it eats the food. In order to make this addition convenient to us, let us modify the code block and add a function called add_segments, to create the snake as well as use it later when adding segments to the snake when it eats the food. This will be a better approach to programming in the current scenario:

#Creating the Snake
segments = []
starting_positions = [(0,0), (-20,0), (-40,0)]

#Adding Segments Function
def add_segments(position):
    new_segment = Turtle("square")
    new_segment.color("black")
    new_segment.penup()
    new_segment.goto(position)
    segments.append(new_segment)

for position in starting_positions:
    add_segments(position)

screen.update()

In the above code block, we have done exactly what we were previously doing, that is, creating the snake body, except that we have used a Python function to do so. We have defined a function called add_segments, whose purpose is just to add the segments to the snake’s body, and the segments list. Moreover, now is where the screen’s tracer() method comes to use. If you comment out the screen.tracer() line that we added in the begining you will see the animation of the snake’s body being created one segment at a time (and we don’t want that in our game!). This can better be visualized by first importing the time module and using the sleep() function. The animation will be more visible.

import time

#Keep the rest of the code same

for position in starting_positions:
    add_segments(position)
    time.sleep(1)
screen.update()

Snake Movement

The next task is to code the snake’s movement. To begin with, let us just make the snake move forward. We will first create a variable game_is_on that will be True as long as the game is running, and will be switched to False once we lose or the game ends. This variable will be used in the while loop. As long as the game is on, the snake will continue moving, and we will only be able to change its direction using the arrow keys. This is going to be the part of our program that will keep the game on.

Now comes the complex part. To move the snake forward, we need to move all of its segments ahead. The way to make the entire snake body move forward is by making each segment, except for the first one, to move to the one before it. This means that at the beginning, when the snake is only 3 segments long, segment 3 will move to the place of segment 2, and segment 2 will move to the place of segment 1, and segment 1 will move forward using the turtle forward() method. This can be coded in the for loop, by giving it a starting value of the last element of the list, which is the element at the 2nd position (list elements start from 0, thus 0, 1, 2) when the snake is created (having 3 segments) or otherwise calculated as the length of the segments, minus 1. The for loop will end at position 0, and as it is moving in reverse, we will give it a step size of -1. This whole scenario is coded as below:

game_is_on = True
while game_is_on:
    screen.update()
    time.sleep(0.1)
    for seg_num in range(len(segments)-1, 0, -1):
        new_x = segments[seg_num - 1].xcor()
        new_y = segments[seg_num - 1].ycor()
        segments[seg_num].goto(new_x, new_y)
    segments[0].forward(20)

Notice that we have added the screen’s update() method, as well as defined the speed of the snake using the time module’s sleep() function. By giving it an argument of 0.1, the snake segments will move forward with a time delay of 0.1 seconds, and this speed can be adjusted. If given an argument of 1, the time delay will be 1 second, and the speed of the snake will be slow. You can experiment with the snake’s speed by changing the values given to the sleep() function.

The inside of the for loop elaborates how the segments will move to the previous segments’ position using its coordinates. And at the end, we have the first segment of our snake moving ahead by 20 using the turtle’s forward() method. Running our code would output a moving snake:

Snake Moving Forward (Image by Author)

Controlling the Snake

Now that we have seen how to make the snake move, the next thing is to control the up/down/left/right movements of the snake. For this, we will use the screen listeners. We will code the program so that on pressing the up, down, left, and right keys, the snake will move accordingly by changing its head.

One more feature that we need to add, taking it from the original snake game, is that when the snake is moving left, it cannot directly turn right, when it is moving up, it can not directly turn downwards. In short, the snake cannot turn 180 degrees from where it is moving. Let us add this feature to our code. Make sure to add these lines of code before the game’s while loop we coded earlier.


#Controlling the Snake
screen.listen()
def turn_up():
    if segments[0].heading() != 270:
        segments[0].setheading(90)
def turn_down():
    if segments[0].heading() != 90:
        segments[0].setheading(270)
def turn_left():
    if segments[0].heading() != 0:
        segments[0].setheading(180)
def turn_right():
    if segments[0].heading() != 180:
        segments[0].setheading(0)

screen.onkey(turn_up, "Up")
screen.onkey(turn_down, "Down")
screen.onkey(turn_left, "Left")
screen.onkey(turn_right, "Right")

As can be seen above, we first used the screen’s listen() method that lets us listen to the screen’s input keys. Next, we have defined functions which will be called later in the screen’s onkey() method, which calls a function based on a keyboard key pressed. We have defined 4 functions, each to turn to a direction other than the complete opposite, using the turtle’s method setheading(). This method sets the head of the turtle, which is the first segment or segment[0] to 0, 90, 180, or 270, that is, right, up, left, or down. The if conditional statements in each function make sure that the snake does not turn in its opposite direction, as we can see in the original game.

Running the complete code with this code block addition will let us move our snake:

Controlling Snake’s Movement with Arrow Keys (Image by Author)

Food Creation

Once the snake has been created and programmed to move using the arrow keys, the next task is to create the food which the snake will eat and grow. This food will also be created as a turtle object in a circular shape, in red. We will set the shapesize to 0.5 so the food is 10×10 pixels on the screen. We have also set the speed() to “fastest” so the animation is fast, and there is no delay in food creation. Here, we will import Python’s random module to create the food at random positions on the game screen. We have set the boundary of food as -275 to 275 on both the x and y axes. This is so that it is easier for the snake to eat its food without colliding with the outer screen boundary.

Moreover, whenever the snake eats its food, new food needs to be generated. For this purpose, we will define a function refresh() and generate new random coordinates where the turtle object called food will move to. Check out the code below:

#Creating the Food
import random
food = Turtle()
food.color("red")
food.shape("circle")
food.penup()
food.shapesize(stretch_len=0.5, stretch_wid=0.5)
food.speed("fastest")
random_x = random.randint(-275, 275)
random_y = random.randint(-275, 275)
food.goto(random_x, random_y)

def refresh():
    random_x = random.randint(-275, 275)
    random_y = random.randint(-275, 275)
    food.goto(random_x, random_y)
Food Creation (Image by Author)

Detect Collision with Food

Once we have created the food, we now have to create a mechanism whereby the snake eats the food. This means that whenever the snake touches the food, the food vanishes, and the snake grows by one segment. We will code this scenario such that whenever the snake and food are in close proximity, so that their distance is less than 15, it means the snake has eaten the food. We will make use of the turtle module’s distance() method that calculates the distance between a turtle and a specific point or another turtle object. If this distance is less than 15 (through trial and error), it would mean the snake has touched or eaten its food, and the food should now move to a new location for game continuity. Hence, we will now call the refresh() function that we defined earlier to move the food object to a new location. Eating the food should increase the snake’s size by a segment. For this, we will define a function called extend() outside the while loop and call it inside the if conditional statement when the snake eats the food.

#Snake extending
def extend():
    add_segments(segments[-1].position())

As can be seen, the extend() function will add a new segment to the last segment of the snake’s body. Now moving on to the main game’s loop:


game_is_on = True
while game_is_on:
    ...
    #Retain the original code here
    ...
    #Detect Collision with Food
    if segments[0].distance(food) < 15:
        refresh()
        extend()
Snake Eating Food and Extending (Image by Author)

Scoreboard and Score Updation

Next is to create a scoreboard that would display the score. To do this, we will code outside the while loop. We will create this scoreboard and the score as 2 turtle objects using turtle’s write() method, which allows us to display text on screen. First, we will initialize a variable called score as 0. As the snake eats its food, the score variable will be increased by 1 each time. Next, we will create 2 turtle instances, scoreboard and my_score. The scoreboard object will display the text on screen “Score = “, whereas the my_score object will display the score variable, which will change as the snake eats its food. As can be seen in the code below, both of these turtle objects have been customized for the screen text display according to the need.

#Creating the Scoreboard & Score
score = 0

scoreboard = Turtle()
scoreboard.color("black")
scoreboard.penup()
scoreboard.hideturtle()
scoreboard.goto(0,250)
scoreboard.write("Score = ", True, align="center", font=("Arial", 12, "normal"))

my_score = Turtle()
my_score.color("black")
my_score.penup()
my_score.hideturtle()

Once we have created the above, we will now proceed to add the provision of changing the core within the while loop of the game, inside the if conditional statement when the snake collides with the food. Check the code below and update the specific lines of code:

game_is_on = True
while game_is_on:
    ...
    #Retain the original code here
    ...
    #Detect Collision with Food
    if segments[0].distance(food) < 20:
        refresh()
        extend()
        score = score + 1
        my_score.goto(40, 250)
        my_score.clear()
        my_score.write(score, True, align="center", font=("Arial", 12, "normal"))

The following is displayed on the screen after running the program with the above additions:

Scoreboard and Score Display (Image by Author)

Game Ending

When the game ends, we need to tell the user that the game is over, rather than just closing the display screen. For this we will define a function and call it whenever the game ends: either by collision with a wall or by collision with tail. We will use the turtle object for this as well. This is the function, and it will be called when game_is_on variable turns to False.

#Game Over Pop Up
def game_over():
    game_over = Turtle()
    game_over.color("black")
    game_over.penup()
    game_over.hideturtle()
    game_over.write("GAME OVER", True, align="center", font=("Arial", 40, "normal"))

Detect Collision with Wall

Another condition of the game’s continuity is to make sure the snake does not collide with the boundary wall of the screen. In order to code this, and knowing that the game’s screen is 600×600, we will consider the boundary wall a square with its corners to be at these points: (290, 290), (290, -290), (-290, -290) and (-290, 290). The wall detection block will be within the game loop in a separate if conditional statement as follows:

game_is_on = True
while game_is_on:
    ...
    #Retain the original code here
    ... 
    # Detect Collision with Wall
    if segments[0].xcor() > 290 or segments[0].xcor() < -290 or segments[0].ycor() > 290 or segments[0].ycor() < -290:
        game_is_on = False
        game_over()
 

In the above lines of code, we have accessed the x and y coordinates of the first segment of the snake and checked whether it falls inside or outside of the boundary wall.

Detect Collision with Tail

Lastly, we will end this program with another condition of the game, which is that if the snake’s head collides with itself, that is, the first segment collides with any other segment, the game ends. We will use the for loop to code this scenario:

game_is_on = True
while game_is_on:
    ...
    #Retain the original code here
    ...   
    # Detect Tail Collision
    for segment in segments[1:]:
        if segments[0].distance(segment) < 10:
            game_is_on = False
            game_over()
 

When the game ends, we need to tell the user that the game is over, rather than just closing the display screen. For this, we will call the game_over function we defined earlier.

Game Over (Image by Author)

Conclusion

In this tutorial, we have successfully implemented the snake game in Python. We have used our understanding of Python basics, such as defining and calling functions, using lists and tuples, using for and while loops as well as conditional statements. We have also implemented our basic understanding of Object Oriented Programming to create objects from a module’s classes. If you have any queries regarding any piece of code or a suggestion to make the code more robust and efficient, feel free to comment and share your ideas. Until then, code, play, and challenge your friends to the Snake Game you have designed!

Share this Article
Please enter CoinGecko Free Api Key to get this plugin works.