By the end of this tutorial you will have a program similar to :

Image

Rules to follow:

  1. The length of snake increases by one unit if it eats the fruit.
  2. Fruit appears at random position at the screen every time it is eaten.
  3. Game is over if snake bites its own tail.

Index:

  1. Installing pygame.
  2. Creating a screen.
  3. Creating Snake Head.
  4. Defining snake movements.
  5. Adding the food.
  6. Eating food and redrawing food at new coordinates .
  7. Increasing snakes length.
  8. Setting score.
  9. Game over when snake bites its tail.
  10. Adding quit or play again option.
Installing pygame.

Firstly, you should have python Installed on your system, and pip (Python installation manager) added to path.

How to add pip to path?

Now, if open command prompt for windows and type:

/pip install pygame

Now you can import pygame module and start with your game development.

Creating a screen.

To create a screen use display.set_mode( ) method, also the init( ) and quit( ) method to initialize and uninitialize the code at starting and end.

import pygame
pygame.init()
screen = pygame.display.set_mode((450,450))
pygame.display.update()
pygame.quit()

But if you run this code the screen will appear and disappear quickly.

To solve this we will create a while loop. Anything we want to display and stay on our screen will be inside this while loop.

Also set screen color to White using screen.fill( )

import pygame
pygame.init()
screen = pygame.display.set_mode((450,450))

running = True
while running:
     screen.fill((255,255,255))   #RGB value for white
     pygame.display.update()
pygame.quit()

But in the above code there is no condition for the while loop to end, hence it will create a infinite loop and program will keep running and eventually hang.

So lets add a condition where running = False so the loop will end.

import pygame
pygame.init()

screen = pygame.display.set_mode((450,450))
running = True
while running:
    screen.fill((255,255,255))   #RGB value for white
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
            
    pygame.display.update()

pygame.quit()

Now when we press Cross the program will terminate.

Image

NOTE : This code will be common to all your pygame codes, so learn and understand it.

Creating Snake Head

The snake head will be a rectangle of dimensions 10×10.

To create a rectangle in pygame use:

rectangle = pygame.Rect(x , y , width, length )
pygame.draw.rect(screen , (color) , rectangle)

# where x, y are the top left coordinates of the rectangle

Now, we created snake_head at snakeX,snakeY.

Also we created a game( ) function and moved our main loop inside it.

import pygame
pygame.init()

red = (255,0,0)
snake_width = 10

screen = pygame.display.set_mode((450,450))

def game():
    snakeX = 200
    snakeY = 200
    running = True
    while running:
        screen.fill((255,255,255))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

        snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
        pygame.draw.rect(screen, red, snake_head)

        pygame.display.update()

    pygame.quit()

game()
Image
Defining snake movements

We create two variables snakeX_speed and snakeY_speed which will represent the change in snakeX and snakeY with time.

Also, a direction variable to keep track of the direction in which the snake is moving because it can not reverse its direction immediately. For instance, is the snake is moving towards right it can not start to move towards left in one keystroke.

import pygame
pygame.init()

red = (255, 0, 0)
snake_width = 10

screen = pygame.display.set_mode((450,450))
def game():

    snakeX = 200
    snakeY = 200

    snakeX_speed = 0.1
    snakeY_speed = 0
    direction = "right"

    running = True
    while running:
        screen.fill((255,255,255))

        snakeX += snakeX_speed
        snakeY += snakeY_speed

        snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
        pygame.draw.rect(screen, red, snake_head)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP and direction != "down":
                    snakeY_speed = -0.1
                    snakeX_speed = 0
                    direction = "up"
                if event.key == pygame.K_DOWN and direction != "up":
                    snakeY_speed = 0.1
                    snakeX_speed = 0
                    direction = "down"
                if event.key == pygame.K_LEFT and direction != "right":
                    snakeX_speed = -0.1
                    snakeY_speed = 0
                    direction = "left"
                if event.key == pygame.K_RIGHT and direction != "left":
                    snakeX_speed = 0.1
                    snakeY_speed = 0
                    direction = "right"

        pygame.display.update()

    pygame.quit()

game()

Also if the snake goes out of the screen we will have it reappear from other side of the screen.

import pygame
pygame.init()

red = (255, 0, 0)
snake_width = 10

screen = pygame.display.set_mode((450,450))
def game():

    snakeX = 200
    snakeY = 200

    snakeX_speed = 0.1
    snakeY_speed = 0
    direction = "right"

    running = True
    while running:
        screen.fill((255,255,255))

        snakeX += snakeX_speed
        snakeY += snakeY_speed

        snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
        pygame.draw.rect(screen, red, snake_head)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP and direction != "down":
                    snakeY_speed = -0.1
                    snakeX_speed = 0
                    direction = "up"
                if event.key == pygame.K_DOWN and direction != "up":
                    snakeY_speed = 0.1
                    snakeX_speed = 0
                    direction = "down"
                if event.key == pygame.K_LEFT and direction != "right":
                    snakeX_speed = -0.1
                    snakeY_speed = 0
                    direction = "left"
                if event.key == pygame.K_RIGHT and direction != "left":
                    snakeX_speed = 0.1
                    snakeY_speed = 0
                    direction = "right"

        # snake does not go outside the screen
        if snakeX < 0:
            snakeX = 450
        if snakeX > 450:
            snakeX = 0
        if snakeY < 0:
            snakeY = 450
        if snakeY > 450:
            snakeY = 0
            
        pygame.display.update()

    pygame.quit()

game()
Adding the food

Lets create a function to draw food on screen.

Also import random module to randomize the position of food.

import pygame
import random

pygame.init()

red = (255, 0, 0)
snake_width = 10

screen = pygame.display.set_mode((450,450))

def draw_food(x, y):
    food = pygame.Rect(x, y, snake_width, snake_width)
    pygame.draw.rect(screen, (0, 255, 255), food)

def game():

    snakeX = 200
    snakeY = 200

    snakeX_speed = 0.1
    snakeY_speed = 0
    direction = "right"

    foodX = random.randint(20, 420)
    foodY = random.randint(20, 420)

    running = True
    while running:
        screen.fill((255,255,255))

        snakeX += snakeX_speed
        snakeY += snakeY_speed

        snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
        pygame.draw.rect(screen, red, snake_head)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP and direction != "down":
                    snakeY_speed = -0.1
                    snakeX_speed = 0
                    direction = "up"
                if event.key == pygame.K_DOWN and direction != "up":
                    snakeY_speed = 0.1
                    snakeX_speed = 0
                    direction = "down"
                if event.key == pygame.K_LEFT and direction != "right":
                    snakeX_speed = -0.1
                    snakeY_speed = 0
                    direction = "left"
                if event.key == pygame.K_RIGHT and direction != "left":
                    snakeX_speed = 0.1
                    snakeY_speed = 0
                    direction = "right"

        # snake does not go outside the screen
        if snakeX < 0:
            snakeX = 450
        if snakeX > 450:
            snakeX = 0
        if snakeY < 0:
            snakeY = 450
        if snakeY > 450:
            snakeY = 0

        draw_food(foodX, foodY)

        pygame.display.update()

    pygame.quit()

game()
Eating food and redrawing food at new coordinates

To solve this problem we will use the collision method.

We will calculate the distance between the snake_head and food and when this distance is relatively less we will assume that collision has occurred and draw food to a new location.

Pythagoras Theorem

Import math module and create a lenth_of_snake variable for future reference.

import pygame
import random
import math

pygame.init()

red = (255, 0, 0)
snake_width = 10

screen = pygame.display.set_mode((450,450))

def draw_food(x, y):
    food = pygame.Rect(x, y, snake_width, snake_width)
    pygame.draw.rect(screen, (0, 255, 255), food)

def collision(snakeX, snakeY, foodX, foodY):
    d = math.sqrt((snakeX - foodX) ** 2 + (snakeY - foodY) ** 2)
    if d < 15:
        return True
    else:
        return False

def game():

    snakeX = 200
    snakeY = 200

    snakeX_speed = 0.1
    snakeY_speed = 0
    direction = "right"

    foodX = random.randint(20, 420)
    foodY = random.randint(20, 420)

    lenth_of_snake = 1

    running = True
    while running:
        screen.fill((255,255,255))

        snakeX += snakeX_speed
        snakeY += snakeY_speed

        snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
        pygame.draw.rect(screen, red, snake_head)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP and direction != "down":
                    snakeY_speed = -0.1
                    snakeX_speed = 0
                    direction = "up"
                if event.key == pygame.K_DOWN and direction != "up":
                    snakeY_speed = 0.1
                    snakeX_speed = 0
                    direction = "down"
                if event.key == pygame.K_LEFT and direction != "right":
                    snakeX_speed = -0.1
                    snakeY_speed = 0
                    direction = "left"
                if event.key == pygame.K_RIGHT and direction != "left":
                    snakeX_speed = 0.1
                    snakeY_speed = 0
                    direction = "right"

        # snake does not go outside the screen
        if snakeX < 0:
            snakeX = 450
        if snakeX > 450:
            snakeX = 0
        if snakeY < 0:
            snakeY = 450
        if snakeY > 450:
            snakeY = 0

        # eating food
        if collision(snakeX, snakeY, foodX, foodY):
            lenth_of_snake += 1
            foodX = random.randint(5, 420)
            foodY = random.randint(5, 420)


        draw_food(foodX, foodY)

        pygame.display.update()
    pygame.quit()

game()
Increasing snakes length

This is the most challenging part of this program.

We will create a pos[ ] list which will contain the position of snake head at all point in the loop but when the length of position list becomes greater than lenth_of_snake we delete the pos[0] element to maintain the length of snake.

And for every element in pos list we draw a rectangle which will represent the snake body.

import pygame
import random
import math

pygame.init()

red = (255, 0, 0)
snake_width = 10
pos = []

screen = pygame.display.set_mode((450,450))

def inc_length():
    for x in pos:
        snake_head = pygame.Rect(x[0], x[1], snake_width, snake_width)
        pygame.draw.rect(screen, red, snake_head)

def draw_food(x, y):
    food = pygame.Rect(x, y, snake_width, snake_width)
    pygame.draw.rect(screen, (0, 255, 255), food)

def collision(snakeX, snakeY, foodX, foodY):
    d = math.sqrt((snakeX - foodX) ** 2 + (snakeY - foodY) ** 2)
    if d < 15:
        return True
    else:
        return False

def game():

    snakeX = 200
    snakeY = 200

    snakeX_speed = 0.1
    snakeY_speed = 0
    direction = "right"

    foodX = random.randint(20, 420)
    foodY = random.randint(20, 420)

    lenth_of_snake = 1

    running = True
    while running:
        screen.fill((255,255,255))

        snakeX += snakeX_speed
        snakeY += snakeY_speed

        snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
        pygame.draw.rect(screen, red, snake_head)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP and direction != "down":
                    snakeY_speed = -0.1
                    snakeX_speed = 0
                    direction = "up"
                if event.key == pygame.K_DOWN and direction != "up":
                    snakeY_speed = 0.1
                    snakeX_speed = 0
                    direction = "down"
                if event.key == pygame.K_LEFT and direction != "right":
                    snakeX_speed = -0.1
                    snakeY_speed = 0
                    direction = "left"
                if event.key == pygame.K_RIGHT and direction != "left":
                    snakeX_speed = 0.1
                    snakeY_speed = 0
                    direction = "right"

        # snake does not go outside the screen
        if snakeX < 0:
            snakeX = 450
        if snakeX > 450:
            snakeX = 0
        if snakeY < 0:
            snakeY = 450
        if snakeY > 450:
            snakeY = 0

        # eating food
        if collision(snakeX, snakeY, foodX, foodY):
            lenth_of_snake += 1
            foodX = random.randint(5, 420)
            foodY = random.randint(5, 420)

        # increasing snakes length
        snake_head = []
        snake_head.append(snakeX)
        snake_head.append(snakeY)
        pos.append(snake_head)
        if len(pos) > lenth_of_snake:
            del pos[0]

        draw_food(foodX, foodY)

        pygame.display.update()
    pygame.quit()

game()

But if you run the above code you will not be able to spot any progress from our last code.

It is due to the speed at which the process is taking place, the body is drawn at the same position as the head hence it is not visible thus to delay the loop we will use the pygame.time.clock( ) method.

Also as we slow the loop we will have to increase the speed of snake to compensate.

import pygame
import random
import math

pygame.init()

red = (255, 0, 0)
snake_width = 10
pos = []
snake_speed = 15

clock = pygame.time.Clock()
screen = pygame.display.set_mode((450,450))

def inc_length():
    for x in pos:
        snake_head = pygame.Rect(x[0], x[1], snake_width, snake_width)
        pygame.draw.rect(screen, red, snake_head)

def draw_food(x, y):
    food = pygame.Rect(x, y, snake_width, snake_width)
    pygame.draw.rect(screen, (0, 255, 255), food)

def collision(snakeX, snakeY, foodX, foodY):
    d = math.sqrt((snakeX - foodX) ** 2 + (snakeY - foodY) ** 2)
    if d < 15:
        return True
    else:
        return False

def game():

    snakeX = 200
    snakeY = 200

    snakeX_speed = snake_width
    snakeY_speed = 0
    direction = "right"

    foodX = random.randint(20, 420)
    foodY = random.randint(20, 420)

    lenth_of_snake = 1

    running = True
    while running:
        screen.fill((255,255,255))

        snakeX += snakeX_speed
        snakeY += snakeY_speed

        snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
        pygame.draw.rect(screen, red, snake_head)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP and direction != "down":
                    snakeY_speed = -snake_width
                    snakeX_speed = 0
                    direction = "up"
                if event.key == pygame.K_DOWN and direction != "up":
                    snakeY_speed = snake_width
                    snakeX_speed = 0
                    direction = "down"
                if event.key == pygame.K_LEFT and direction != "right":
                    snakeX_speed = -snake_width
                    snakeY_speed = 0
                    direction = "left"
                if event.key == pygame.K_RIGHT and direction != "left":
                    snakeX_speed = snake_width
                    snakeY_speed = 0
                    direction = "right"

        # snake does not go outside the screen
        if snakeX < 0:
            snakeX = 450
        if snakeX > 450:
            snakeX = 0
        if snakeY < 0:
            snakeY = 450
        if snakeY > 450:
            snakeY = 0

        # eating food
        if collision(snakeX, snakeY, foodX, foodY):
            lenth_of_snake += 1
            foodX = random.randint(5, 420)
            foodY = random.randint(5, 420)

        # increasing snakes length
        snake_head = []
        snake_head.append(snakeX)
        snake_head.append(snakeY)
        pos.append(snake_head)
        if len(pos) > lenth_of_snake:
            del pos[0]

        clock.tick(snake_speed)
        draw_food(foodX, foodY)
        inc_length()

        pygame.display.update()
    pygame.quit()

game()
Setting score

Score will be equal to lenth_of_snake – 1.

Lets create a function to print text on our screen. Also import sys module.

def print_message(msg, x, y, size):
    font = pygame.font.SysFont("comicsansms", size)
    text = font.render(msg, True, (0, 0, 0))
    screen.blit(text, (x, y))

Now call this function inside of main loop

print_message("Score : " + str(lenth_of_snake - 1), 10, 10, 15)

Game over when snake bites its tail

Write this inside the main loop.

 # game over
        for x in pos[:-1]:
            if x == snake_head:
                game_over = True
                time.sleep(1)
                pos.clear()

If at anytime the position of snake_head and snake body are equal the game_over = True

Adding quit or play again option

Now we will create a while loop that will run until game_over is true

Image

THE FINAL CODE IS:

import pygame
import random
import math, sys, time

pygame.init()

screen = pygame.display.set_mode((450, 450))

snake_width = 10
red = (255, 0, 0)
snake_speed = 15
pos = []
clock = pygame.time.Clock()


def inc_length():
    for x in pos:
        snake_head = pygame.Rect(x[0], x[1], snake_width, snake_width)
        pygame.draw.rect(screen, red, snake_head)


def draw_food(x, y):
    food = pygame.Rect(x, y, snake_width, snake_width)
    pygame.draw.rect(screen, (0, 255, 255), food)


def collision(snakeX, snakeY, foodX, foodY):
    d = math.sqrt((snakeX - foodX) ** 2 + (snakeY - foodY) ** 2)
    if d < 15:
        return True
    else:
        return False


def print_message(msg, x, y, size):
    font = pygame.font.SysFont("comicsansms", size)
    text = font.render(msg, True, (0, 0, 0))
    screen.blit(text, (x, y))


def game():
    snakeX = 100
    snakeY = 100
    snakeX_speed = 10
    snakeY_speed = 0
    foodX = random.randint(20, 420)
    foodY = random.randint(20, 420)
    lenth_of_snake = 1
    direction = "right"
    game_over = False

    # main loop
    running = True
    while running:

        screen.fill((255, 255, 255))

        snakeX += snakeX_speed
        snakeY += snakeY_speed

        snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
        pygame.draw.rect(screen, red, snake_head)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP and direction != "down":
                    snakeY_speed = -snake_width
                    snakeX_speed = 0
                    direction = "up"
                if event.key == pygame.K_DOWN and direction != "up":
                    snakeY_speed = snake_width
                    snakeX_speed = 0
                    direction = "down"
                if event.key == pygame.K_LEFT and direction != "right":
                    snakeX_speed = -snake_width
                    snakeY_speed = 0
                    direction = "left"
                if event.key == pygame.K_RIGHT and direction != "left":
                    snakeX_speed = snake_width
                    snakeY_speed = 0
                    direction = "right"

        # snake does not go outside the screen
        if snakeX < 0:
            snakeX = 450
        if snakeX > 450:
            snakeX = 0
        if snakeY < 0:
            snakeY = 450
        if snakeY > 450:
            snakeY = 0

        # eating food
        if collision(snakeX, snakeY, foodX, foodY):
            lenth_of_snake += 1
            foodX = random.randint(5, 420)
            foodY = random.randint(5, 420)

        # increasing snakes length
        snake_head = []
        snake_head.append(snakeX)
        snake_head.append(snakeY)
        pos.append(snake_head)
        if len(pos) > lenth_of_snake:
            del pos[0]

        # game over
        for x in pos[:-1]:
            if x == snake_head:
                game_over = True
                time.sleep(1)
                pos.clear()
        while game_over == True:
            screen.fill((255, 150, 0))
            print_message("GAME OVER, Press P to play again or q to quit.", 30, 200, 16)
            pygame.display.update()
            # quit or play again option
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                    game_over = False
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        quit()
                    if event.key == pygame.K_p:
                        game_over = False
                        game()

        clock.tick(snake_speed)
        draw_food(foodX, foodY)
        inc_length()
        print_message("Score : " + str(lenth_of_snake - 1), 10, 10, 15)

        pygame.display.update()


game()