Getting Started With Pygame, Making a snake game
Tags: python, gamedev, tutorial, programming
Published: 2020-11-14 15:21:44


# Intro and Setup
Yeah, I know, another snake game... But I wanted to introduce you to [pygame](www.pygame.org), a fun little module capable enough to make simple and fun 2d games in python, so here I am ...

To get started, you must have python and pip installed on your system, 
You can get more info at [here](https://wiki.python.org/moin/BeginnersGuide/Download)
To verify that python is installed, on the terminal, run
```bash
# check if python is installed
python --version

#check if pip is installed
pip --version
```
If you get something in return that means you are successful 🎉🎉🎉 ...
Now it's time to install pygame, just run
```
pip install pygame
```
If you faced any trouble, you can check this [page](https://www.pygame.org/wiki/GettingStarted)

Alternatively, if you don't wanna go through all this setup, you can use repl.it , it has an online pygame compiler that you can use
[check it out here](https://repl.it/languages/pygame)

# Getting Started 
We can finally start writing some code, You can use any favorite ide of yours ... vscode, sublime, atom,pycharm, brackets, etc ... It doesn't matter ╮(╯3╰)╭ ...

Just make a new python file in any directory and name it anything you want 👍 ...
The first job is going to be to import pygame and initialize our game window

```python
import sys,random
import pygame 

# initialize pygame 
pygame.init()

# constants that store our screen width and height ,
# they are in pixels
WIN_X = 800
WIN_Y = 600

# setting up our game window in pygame with 
# our screen width and height constants as tuple
WIN = pygame.display.set_mode((WIN_X,WIN_Y))

# setting the caption of our game
# or more precisely the label that
# you will see on the game window

pygame.display.set_caption('snake game')
```
Let's discuss the code above,
* We import pygame and some other local modules, then use the init method on pygame to start our game or start pygame
* We make two variables or constants, WIN_X and WIN_Y to store our screen dimensions or our screen width and screen height,
(📝 The reason we need this is that pygame creates a game window and we need to declare the width and height of it, you can choose any width and height, I am choosing 800x600)

* Next, we set up our game window, or tell pygame to initialize our game window with __*pygame.display.set_mode()*__ method passing in our screen dimensions in a tuple
* In the end, I just set up a caption or label for the game window using __*pygame.display.set_caption()*__ method passing in the caption string, you can pass any string you want here 👍 ...

Now if you run this code, you will see the game screen for a short time, and then it exits the program ...
Can you guess why this happens 🤔, well cause we didn't define any game loop ...
A game loop is just an infinite loop , that goes on forever until the user exits or closes it ... As we didn't define any game loop, the window was visible for a moment, but then the program ended, and so the game screen was also gone...

Let's go ahead and implement our game loop

```python
#importing modules
import sys,random
import pygame 

pygame.init()

WIN_X = 800
WIN_Y = 600

WIN = pygame.display.set_mode((WIN_X,WIN_Y))

pygame.display.set_caption('snake game')

#initializing pygame.time.Clock() which controls
#The FPS or frame per second or more explicitly
#For how many times per second our game loop 
#below should run
CLOCK = pygame.time.Clock()

#our infinite game loop
while 1:
   #checking for events in pygame.event.get() which
   #returns the event that occurs like 
   #any key presses or user clicking the
   #exit , maximize , minimize button
   for event in pygame.event.get():
        #here we are checking if user has clicked the exit button
        #by checking if the event.type is pygame.QUIT 
        #which is predefined in pygame as the exit button
        if event.type == pygame.QUIT:
            #if user clicked the exit button , quit the game
            #and exit out of the program
            pygame.quit()
            sys.exit()
        
        #using CLOCK variable mentioned above and using
        #tick method on it passing in the fps
        #this means that this loop will run 
        #25 times per second, 
        #feel free to change the value
        CLOCK.tick(25)
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/i2tzx8tgf7koboa92wes.PNG)

Now if you run the program, the window is going to stay until you press the exit button, congrats if you could follow up on this 👍 ...

📝 In the above, I just wrote a simple infinite while loop, 
then I wrote another for loop which checks for events like mouse-clicking, hover and others,   (The method *__pygame.event.get()__* returns the events that are occurring currently, there, I am checking if *event.type* is equal to the event pygame.QUIT or in other words did the user click the cross button, if that's true, quit the program, else continue to run ...) 

You also might have seen the CLOCK variable I declared, it just initializes *__pygame.time.Clock()__* and using it, in the while loop, I used *__CLOCK.tick(25)__*, which just tells pygame to run the while loop 25 times per second, you are more than welcome to change the number ╮(╯3╰)╭  ...

# Planning Core Game logic
Now it's time to plan our core game logic,

 So we will have these 3 functions, *__main__*,  *__main_menu__*,  *__game_over__*, they represent different scenes of our game, for now, we will only focus on the main function or the main game logic ...
 
So first of all, how we will render and move our snake 🤔, that's the first and most obvious thing to do ...

* Well, our snake is going to be a square 🟨, I mean a collection of squares, and whenever he can eat any food, the number of squares in the snake's body will increase 

Now how we will store these squares,  and how we will track the position of the square ...

* To store the squares of the body of the snake, the data structure that comes into my mind first is a list, so we can create a list of the snake body, and for each element of that list, we will render a square-like shape...
*  Now the squares itself are going to be a list, cause in pygame, to draw a rectangle or square, we will need it's x coordinate,y coordinate and it's the width and it's height ...
*  Now for the snake position, we could introduce another list which will contain the snakes starting x and y coordinate, let's say it's [100,50], And then we will increment or decrement it by the snake's speed in the game loop ... 
* We would also need a direction variable to track if the snake is moving up, down, left or right...
*  One thing to note is that the snake pos list will be pushed to the snake body list after each round of the loop, and we will pop the first element in the snake body list after every round in the loop, The reason why we do this will be clear once we start implementing it, snake pos will also help us to keep track of where the snake is going so if the snake hit's the boundaries, or eats a fruit, we can know that and also changing the direction of the snake...

* Now when the user click's W, the snake will go up, for A snake goes the left, D for right, and S for down, You can change these controls or introduce new controls if you want...

* For the fruit, we will create a single square which is going to look like a fruit, You can also use images if you want... We will spawn these fruits randomly on the screen using the random module...

📝For the snake, I could create a snake class and for the fruit, I could create a fruit class, also I could create a game object class from which all game objects are gonna inherit, but for simplicity, I am not going to do that, instead, I will just store them in relevant variables...

# Implementing the game logic

We can start implementing the logic discussed above, first, let's start creating our main function, I am going to shift my game loop there

```python
import sys, random
import pygame

pygame.init()

WIN_X = 800
WIN_Y = 600
WIN = pygame.display.set_mode((WIN_X,WIN_Y))
pygame.display.set_caption('snake game')

#main function
def main():
    CLOCK = pygame.time.Clock()
    #variable to store snake position , default when starting is [200,70],
    #Feel free to change
    snake_pos=[200,70]

    #snake body is going to be a 2d list or matrix storing snakes full body
    #here by default, the snake is going to be 3 squares long
    #individual square in this list contains the x and y coordinate
    #of the square itself
    snake_body=[[200,70] , [200-10 , 70] , [200-(2*10),70]]
    
    #direction of the snake , default is 'right'
    direction = 'right'
    #score of the snake
    score=0
    
    CLOCK = pygame.time.Clock()
    #game loop
    while 1:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
        #filling the window with black color , the (0,0,0)
        #here represents black in rgb , 
        #we are filling the screen for background
        #withouth this your game will act glitchy
        #feel free to change the color
        WIN.fill((0,0,0))

        #for loop that goes through the snake_body
        for square in snake_body:
            #rendering the square of the snake using
            #pygame.draw.rect
            #here the first argument is the surface where
            #YOU wanna draw, in our case, it's the 
            #WIN surface defined above
            #The second argument is the color of the rectangle
            # I chose yellow, feel free to change,
            # color must be RGB
            #third argument is the pos or where to place the rect
            #It takes a tuple with an x coordinate as the first argument
            #AND y coordinate as 2nd argumenT
            #width as 3rd argument and height as 
            #4th argument
            pygame.draw.rect(WIN ,(255, 255, 0), (square[0],square[1],10,10))


        #updating the display with pygame.display.update()
        #withouth this , you wouldn't see anything on the screen
        #You should write all your rendering logic or code
        #that renders things to screen before this line
        pygame.display.update()
        CLOCK.tick(25)

#caliing the main function
main()

```

Here, I just shifted my code to the main function, made a snake_body and snake_pos variable, in the game loop, I rendered the snake, read the comments if you can't understand, the code should be self-explanatory 
( ━☞◔‿ゝ◔)━☞, 

You may be wondering about the coordinate system in pygame, how will pygame draw our objects on the screen, well pygame coordinate system starts from the top leftmost corner, not the bottom leftmost corner like we are used to,

So when we say 20 on the x, 10 on the y  in pygame , it means go 20 to the right from the top leftmost corner and 10 to the down from the top .
If you run the code you should see something like this

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/t03mkwmvwkciojw92u7w.PNG)

Well we can see the snake so that's great news, but the snake is not moving, it's just a static snake on the screen, well that's boring 🥱 , 
let's make it move 🙌 .
At the end of the main function before we run **pygame.display.update()** add the following code
```python
 #remember the direction variable declared at the start
        #of main function , we are checking if direction is
        #up,down,right or left
        if direction == 'right':
            #if direction is right , add 10 to x coordinate
            #of snake_pos , adding to x coordinate makes things
            #move right
            snake_pos[0] += 10
        elif direction == 'left':
            #if direction is left, deduct 10 from x coordinate
            #of snake_pos , deducting from x coordinate 
            #makes things move left
            snake_pos[0] -= 10
        elif direction == 'up':
            #if direction is up, add 10 to y coordinate
            #of snake_pos , adding to y coordinate 
            #makes things move up
            snake_pos[1] -= 10
        elif direction == 'down':
            #if direction is down, deduct 10 from y coordinate
            #of snake_pos , deducting from y coordinate 
            #makes things move down
            snake_pos[1] += 10
```


If you run the code now, absolutely nothing is going to happen, the snake does not move ( º﹃º ) , why is that?
Because we render squares in **snake_body**, we don't render the **snake_pos**, and here we are adjusting **snake_pos**

So what to do now, well to make the snake move, we can insert our **snake_pos** to the beginning of the list, let's see what happens, below the code where we check directions and before pygame.display.update() add this

```python
#appending snake_pos to snake_body
#make sure to convert snake_pos
#explicitly to list or else 
#it won't work
snake_body.append(list(snake_pos))

```

Now if you run the program, you will see something like this,
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/emq2m3jdiezjr1ys08aq.gif)

The snake keeps growing endlessly, but we only want our snake to grow once he eats fruit, we have to fix this...

But why it's behaving this way 🤔, well we are appending **snake_pos** to **snake_body**, but not removing the old squares from the snake_body, so it's growing endlessly, one thing we can do is remove the oldest square by removing the first item from the list, 

Below the code where we append **snake_pos** to **snake_body**, add the following
```python
#remove the first element from snake_body
snake_body.pop(0)
```
Now you should see something like this
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gffu7bu98e17kdgdvxv7.gif)

So our snake is moving at last, but it's only moving the right, well that's not what we want, let's add some controls 

```python
        #The for loop where we check for events
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            #here , we are storing pygame.key_pressed() in 
            #keys variable , pygame.key_pressed() returns what key
            #The user has pressed and we can check that below 
            keys= pygame.key.get_pressed()
            
            #Now in keys , we check if pygame.K_w is true
            #what does that mean
            #well pygame.K_w represents w in pygame
            #and pygame.K_UP represents the up arrow key
            #if keys[pygame.K_w] or keys[pygame.K_UP] 
            #returns true or in other words if the
            #user has clicked the w key or up arrow
            #we change direction to up
            #we then also check clicks on s,a,d,down
            #arrow key,left arrow key and change
            #the direction accordingly
            if (keys[pygame.K_w] or keys[pygame.K_UP]):
                direction = 'up'
            if (keys[pygame.K_s] or keys[pygame.K_DOWN]):
                direction = 'down'
            if (keys[pygame.K_d] or keys[pygame.K_RIGHT]):
                direction = 'right'
            if (keys[pygame.K_a] or keys[pygame.K_LEFT]):
                direction = 'left'
```

If you run the code now, you should be seeing something like this

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/p8znqnyrq1gq9veyhs2g.gif)

So we got our snake moving, now one thing I would like to fix right away is that snake moving instantaneously 💨 ...

What do I mean by that, well if the snake is going up, then when we press down arrow key or s, the snake goes over its own body in a very strange way which should not happen, the same thing occurs when the snake is in left and snake goes right or snake is in down and snake goes up, let me show you what I mean 🙃

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gfxnonxm0kyfzaz5qene.gif)

Saw that right, well luckily it has an easy fix 🎊, when we are changing the snake's direction, we can check if the snake is already in the opposite direction

Suppose the snake's direction is up, the user wants to go down now, but the snake is going up and we don't want any instantaneous movement, so we'll not go down

The place where we are changing direction in the for loop, change those if check's to this

```python
            #preventing instanteous movement
            #here we are checking if user and wants to
            #to go up , but snake's direction is not
            #'down' which is opposite of up , change
            #the direction
            if (keys[pygame.K_w] or keys[pygame.K_UP]) and direction != 'down':
                direction = 'up'
            if (keys[pygame.K_s] or keys[pygame.K_DOWN]) and direction != 'up':
                direction = 'down'
            if (keys[pygame.K_d] or keys[pygame.K_RIGHT]) and direction != 'left':
                direction = 'right'
            if (keys[pygame.K_a] or keys[pygame.K_LEFT]) and direction != 'right':
                direction = 'left'
```

With that, the bug gets fixed 👍.

But now, the snake can go through the boundaries of our screen, and keep going endlessly ...

Well we can exit our application if the snake hit's the boundaries of the window, later on, we will introduce a game_over and main_menu scene ...

At the end of the game loop ,  add this
```python
        #checking if x coordinate of snaake is smaller than 0,
        #if that's true , than snake has crossed left side
        #of screen , we also check if snakes x coordinate is 
        #greater than our screen , if that happens , snake
        #has crossed right side of the screen ,
        if snake_pos[0] <=0 or snake_pos[0] >= WIN_X:
            sys.exit()

        #checking if y coordinate of snake is smaller than 0,
        #if that's true than the snake has crossed the upper side
        #of the screen, we also check if snakes y coordinate is 
        #greater than our screens y coordinate,
        #if that happens, snake
        #has crossed the lower side of the screen,
        if snake_pos[1] <=0 or snake_pos[1] >= WIN_Y:
            sys.exit()
```

This should work however it might be a bit off, might not look pixel-perfect, we can make it better by adding some pixels, worked for me 

```python
        if snake_pos[0]+10 <=0 or snake_pos[0] >= WIN_X:
            sys.exit()
        if snake_pos[1]+10 <=0 or snake_pos[1] >= WIN_Y:
            sys.exit()
```
much better ...

# Bringing the fruits in
Now let's add some grapes 🤤

* For the grapes, we can make two variables
**fruit_pos** and **fruit_spawn**
* **fruit_pos** is going to be the pos of the grape or fruit, it's going to be positioned randomly on the screen ...
* Next we have **fruit_spawn** which checks if new fruit is to be generated, it's going to be true by default ...

At the start of the main function, before the game loop, add this
```python
    fruit_pos = [0,0]
    fruit_spawn = True
```
Then in the game loop, before pygame.display.update(), add this line

```python
#generating a random position for the grape
#for the x coordinate its going to be from
#range 40 to screen_width-40 
#i am not starting from 0 as the grape  can
#be very close to the boundaries then
#same logic for y coordinate
fruit_pos = [random.randrange(40,WIN_X-40),random.randrange(40,WIN_Y-40)]

#Drawing the fruit to the screen using 
#pygame.draw.rect()
pygame.draw.rect(WIN ,(138,43,226),(fruit_pos[0],fruit_pos[1],10,10))
```

Here, we are generating a random position for the grape and drawing a 10x10 Rect.
If you run the code now, it should look something like this

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/czs2xskw7o38iqwafxdp.gif)

Well, its kind of keep on generating grapes and not stopping at all, The reason this occurs is that in every round in the while loop, we are changing the **fruit_pos** and rendering it ( º﹃º ), ...

To fix this we can use our **fruit_spawn** variable, which was set to true initially

The place where we wrote our grape spawning logic, cut that and use this

```python
        #if fruit spawn is true , change fruit_pos
        #and make fruit_spawn false
        if fruit_spawn:
            fruit_pos = [random.randrange(40,WIN_X-40),random.randrange(40,WIN_Y-40)]
            fruit_spawn = False
        pygame.draw.rect(WIN ,(138,43,226),(fruit_pos[0],fruit_pos[1],10,10))
```

Now, only one fruit should be visible,
If you notice, you will see that we only have one fruit, we are
just changing its position

But the snake still can't eat any fruit, let's add that

At the game loop , before **pygame.display.update()** , add this

```python
        if pygame.Rect(snake_pos[0],snake_pos[1],10,10).colliderect(pygame.Rect(fruit_pos[0],fruit_pos[1],10,10)):
            fruit_spawn=True
            score += 5
```

Let me just directly describe what I did instead of commenting 🙃...

Well I am checking if **snake_pos** collides with **fruit_pos** ...

Now the way I did it looks strange 🥴, So let me explain that 👍

* In pygame, we have this thing called **Rect**, [More Info here](https://www.pygame.org/docs/ref/rect.html) ... 
* **Rects** make collision detection easy, You can also use **Rect** on images, any rectangular object works, It can also be circular ..
* Now to make a **Rect**, we have to use **Pygame.Rect()** method

* We have to pass in the x coordinate as the first argument, y coordinate as the 2nd argument, and width and height as the 3rd and 4th argument respectively

* In our case, we first pass the snakes x coordinate, y coordinate, it's width and height

* Now **rects** have a lot of methods available, one is **colliderect()**, This method takes another **Pygame.Rect()** as argument and checks if they two collide with each other

* In our case, we pass **fruit_pos** transforming as **Rect** to the **colliderect** method.
* If this returned true, **fruit_spawn** will be true, so new fruits will be generated and the score will be increased ...
With that out of the way you should see something like this 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6roruznkeamspz0l0g7n.gif)

But our snake doesn't grow, why is that, how we can make him grow?

Well, remember that we were always removing the first item from **snake_body** after we append **snake_pos** to **snake_body**

What if we only remove the first item in the list when the snake could not eat any grape, if the snake collides with the **Rect**, we don't remove the first element from **snake_body** 😮

The place where we remove the first element from **snake_body**, cut that part, then got the part where we check collision between fruit and snake, change that to this

```python
        if pygame.Rect(snake_pos[0],snake_pos[1],10,10).colliderect(pygame.Rect(fruit_pos[0],fruit_pos[1],10,10)):
            fruit_spawn=True
            score += 5
        else:
            snake_body.pop(0)
```

And now the snake will start to grow,
But why is this working 🤔, 
When we first start our game, **snake_body** should be like this
```python
snake_body=[[200,70] , [190 , 70] , [180,70]]
```
in the game loop, we add **snake_pos** to it and remove first element
Then it should be something like this
```python
snake_body=[[190, 70], [180, 70], [210, 70]]
```
Here the snake is 3 squares long, what happens if we don't remove the first element next time
```python
snake_body=[[190, 70], [180, 70], [210, 70], [220, 70]]
```
The snake is 4  squares long

Now we face another problem when the snake collides with his own body, We have to stop the game if that happens

In the game loop, add this line

```python
        for square in snake_body[1:]:
            if pygame.Rect(square[0],square[1],10,10).colliderect(pygame.Rect(snake_pos[0],snake_pos[1],10,10)):
                sys.exit()
```

Now, what did I do here?

* First of I am looping through the **snake_body** and checking if **snake_pos** collides with the other squares.

Now why I excluded the last element in **snake_body** using **snake_body[:-1]** ...

It's a bit confusing but think of the last element as the head of the snake, here we are checking if the head or **snake_pos** collides with other parts of the body, But if we include the last element in the list, we will be checking if head collides with the head when the for loop reaches there, cause the last element in the **snake_body** is going to be **snake_pos** and we would be checking if **snake_pos** collides with **snake_pos** or if head collides with head, which is always true .

With that our game is almost ready 

# Displaying score
We now have to display our score,
In pygame, to show text, first, we have to load a font
at the start of the file, after importing pygame and before the main function, add this

```python
font = pygame.font.SysFont('comicsans',40)
```
Here we are loading a system font using pygame.font.Sysfont() which takes font as first argument and size as 2nd
I chose comicsans, u can choose other system fonts like timesnewroman

Next, we also have to use this font now ...
At the game loop, before pygame.display.update() add these two lines

```python
        #setting the font up
        score_font = font.render(f'{score}' , True , (255,255,255))
        #declaring position of the font to be in center
        #in x coordinate and 30 in y
        font_pos = score_font.get_rect(center=(WIN_X//2-40 , 30))
        WIN.blit(score_font , font_pos)
```

So what did I do here?
* first I made a **score_font** variable, and you can name this anything you want by the way, and set it equal to **font.render**

* Now the font is the variable we declared above, so change that to whatever you named it ...

* Now in this font, we have a render method, this takes the string we want to show as 1st argument, in our case its the score, but the score is a number and 1st argument has to be a string and so I changed it to a string using f strings in python. The next argument can be set to either true or false, your wish, 3rd argument is the color in RGB, I chose white.

* Now only this won't show text on the screen, we have to **Blit** it.
So that's why, I used **WIN.blit()** which takes the thing to blit or display as 1st argument which in our case was a font, and a tuple or list which takes the x and y coordinates, I already declared a **font_pos** above which is a center position at the top of the screen. If you wanna know how to center text in pygame, there are a lot of ways... **You can check this StackOverflow [thread](https://stackoverflow.com/questions/23982907/python-library-pygame-centering-text) for more details.**

Let's run the game now ..................

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gc335jnggu4v455nimum.gif)

That's a fully functioning snake game we have here 🎉🎊🕺...

# The main menu and game over scene

And Before I end this post, let's implement the main menu and game over scene...
Let's start with the main menu

In our game code, before the main function, put this code

```python
#The main menu
def main_menu():
    #creating seperate game loop for the main_menu
    while 1:
        #listening for events
        for event in pygame.event.get():
            #you know what this does
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

            #IF THE user clicks anywhere in the screen
            #call the main function , start the game
            if event.type == pygame.MOUSEBUTTONDOWN:
                main()
        #nothing new here
        WIN.fill((0,0,0))

        #showing the message 
        #'Press anywhere to start'
        # at the center of the screen
        main_menu_message = font.render('Press anywhere to start the game' , True , (255,255,255))
        font_pos = main_menu_message.get_rect(center=(WIN_X//2, WIN_Y//2))
        WIN.blit(main_menu_message , font_pos)
        pygame.display.update()
```
Ok, Let's go through this quick. In this function, we wrote another game loop and another check for **pygame.event.get()**

If the user clicks anywhere, the main function will be called Which means the game will start, We also display a message **'Press anywhere to start'** at the center of the screen

Now at the end of our code, where we call main(), instead

```python
main_menu()
```

We are almost done, The thing which is left is the **game_over** scene
Let's quickly go through that

```python
#game over scene, this takes the score to display as 
#the argument
def game_over(score):
        #I won't explain these again
        while 1:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
            WIN.fill((0,0,0))
            
            #showing 'You lost' in red color
            game_over_message = font.render('You Lost' , True , (255,0,0))
            #showing 'You score was SCORE'
            game_over_score = font.render(f'Your Score was {score}' , True , (255,255,255))

            font_pos_message = game_over_message.get_rect(center=(WIN_X//2, WIN_Y//2))
            font_pos_score = game_over_score.get_rect(center=(WIN_X//2, WIN_Y//2+40))
            WIN.blit(game_over_message , font_pos_message)
            WIN.blit(game_over_score , font_pos_score)
            pygame.display.update()

            #here what we are doing is we
            #use time.sleep() to stop our 
            #program for 3 seconds ,
            #don't forget to import time module at
            #the top ...
            #after 3 seconds, we call our main_menu()
            time.sleep(3)
            main_menu()
```

What the **game_over()** does is show that you have lost and your score. Pauses the program for 3 seconds and then just calls **main_menu()**

Now in the main function, whenever we die, we are calling **sys.exit()**, instead of that, call **game_over()** passing in the score

Your main function should be close to this

```python
def main():
    CLOCK = pygame.time.Clock()
    snake_pos=[200,70]
    snake_body=[[200,70] , [200-10 , 70] , [200-(2*10),70]]
    fruit_pos = [0,0]
    fruit_spawn = True
    direction = 'right'
    score=0
    CLOCK = pygame.time.Clock()
    while 1:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

            keys= pygame.key.get_pressed()
            if (keys[pygame.K_w] or keys[pygame.K_UP]) and direction != 'down':
                direction = 'up'
            if (keys[pygame.K_s] or keys[pygame.K_DOWN]) and direction != 'up':
                direction = 'down'
            if (keys[pygame.K_d] or keys[pygame.K_RIGHT]) and direction != 'left':
                direction = 'right'
            if (keys[pygame.K_a] or keys[pygame.K_LEFT]) and direction != 'right':
                direction = 'left'

        WIN.fill((0,0,0))
        for square in snake_body:
            pygame.draw.rect(WIN ,(255, 255, 0), (square[0],square[1],10,10))
        if direction == 'right':
            snake_pos[0] += 10
        elif direction == 'left':
            snake_pos[0] -= 10
        elif direction == 'up':
            snake_pos[1] -= 10
        elif direction == 'down':
            snake_pos[1] += 10

        snake_body.append(list(snake_pos))

        if fruit_spawn:
            fruit_pos = [random.randrange(40,WIN_X-40),random.randrange(40,WIN_Y-40)]
            fruit_spawn = False

        pygame.draw.rect(WIN ,(138,43,226),(fruit_pos[0],fruit_pos[1],10,10))

        score_font = font.render(f'{score}' , True , (255,255,255))
        font_pos = score_font.get_rect(center=(WIN_X//2-40 , 30))
        WIN.blit(score_font , font_pos)

        if pygame.Rect(snake_pos[0],snake_pos[1],10,10).colliderect(pygame.Rect(fruit_pos[0],fruit_pos[1],10,10)):
            fruit_spawn=True
            score += 5
        else:
            snake_body.pop(0)

        for square in snake_body[:-1]:
            if pygame.Rect(square[0],square[1],10,10).colliderect(pygame.Rect(snake_pos[0],snake_pos[1],10,10)):
                game_over(score)

        if snake_pos[0]+10 <=0 or snake_pos[0] >= WIN_X:
            game_over(score)
        if snake_pos[1]+10 <=0 or snake_pos[1] >= WIN_Y:
            game_over(score)
        pygame.display.update()

        CLOCK.tick(25)
```

With this, We should have a complete snake game...

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0q46h0yqasvujwx37ii4.gif)

The complete code can be found at my GitHub [here](https://github.com/grapeJUICE1/python-mini-projects/blob/main/snake.py)

# Conclusion

So here you have it... A snake game with pygame, feel free to play with the code and adding features like maybe a high score system, some small animations, add difficulty levels, etc...
Also, it would be better if you create something yourselves.
There are many resources to help you work with
First is the pygame website: https://www.pygame.org/news
2nd will be invent with python: https://inventwithpython.com/
check out this article: https://inventwithpython.com/blog/2012/02/20/i-need-practice-programming-49-ideas-for-game-clones-to-code/

You can also check out games I made with pygame, they might not be the coolest, But you'll get some idea

Fruit Ninja clone: Fruit Frowns
Link: https://github.com/grapeJUICE1/Fruit-Frowns
Breakout
Link: https://github.com/grapeJUICE1/Grape-Bricks
Space Invaders
Link: https://github.com/grapeJUICE1/space-invaders

If you found this useful or helpful, please  💓, 🦄, and 🔖.