Game Logic and Food Object

Game Logic Overview

Before we create our Food object let’s think about the game logic. To make our lives easier as game developers, we are going to use a technique very common in game development. We are going to create a grid, that is we are going to divide the game screen in a large number of identical cells. This grid will be invisible in reality, we will just use it to help us with the positioning and the movement of the objects on the display. So, if we want to display a food object, we are going to display it inside a cell.

The food object (and the snake object) will work within the context of the grid using pygame functions.

Creating the Grid

Let’s create the grid now and we will discuss more about it later on.

We are going to create a variable that will store the size of each cell. Let’s call it cell_size and we will set it to 30.

Now let’s create a variable for the number cells for each row and column of the grid.

I will call it number_of_cells. We are going to set it to 25.

This means that the grid will cover an area of 750x750pixels.

That’s exactly the resolution of our game screen. So, let’s remove it and replace it with this expression:

cell_size * number_of_cells,  cell_size * number_of_cells. 

Let’s now run the game. As you can see, the game window is exactly the same as before, 750x750 pixels which is 25 times 30 pixels. Let’s now create the food class which will create the food object of our game.

We type:

class Food: 

Init Function

And then we create the init function.

def __init__ (self): 

The __init__ function is a special function in Python that is used when creating an object of a class. It is used to set up, or initialize, the object by defining the attributes that the object will have when it is created. This allows objects to be customized when they are created and makes it easier to create multiple objects with different attributes. Now let’s think about the attributes the object is going to have.

What do we want to know about the food? First of all we need to know its position on the grid.

The obvious way to implement this is to use x and y attributes for the position on the grid. But, there is another way to do it which will make our lives easier later on: The Vector2 class.

Pygame Vector2 Class

You can think of the Vector2 Class as a data structure that contains x and y attributes, the same attributes that we want for our class. That’s only one of the many advantages of the Vector2 class: the class also provides a lot of useful methods that we are going to use later. For now, let’s use a Vector2 variable to hold the position of the food object. So in our Food class we type:

self.position = Vector2(5, 6) 

This line of code creates a Vector2 object to hold the position of the food object. The two numbers in the parentheses (5, 6) are the x and y coordinates of the food.

For example, the food's x-coordinate can be accessed by self.position.x and its y-coordinate by self.position.y.

Remember that these numbers do not represent pixels, but cells.

This means that the food's position is at the 6th column and 7th row in our grid, with the counting starting from 0.

To use the Vector2 class we have to import it:

from pygame.math import Vector2 

Drawing the Food Object

Now let’s draw the food object on the screen. We are going to create a new method for the Food class and we are going to name it draw()

Def draw(self): 

Now, before we draw something let’s talk about how pygame draws on the screen.

We have three basic concepts to consider:

  1. display surface set_mode and update
  2. regular surface
  3. rect (rectangular area) Pygame.Rect

The display surface is the surface where we see all the game objects. It's like the blank canvas we talked about before.

The display surface is created when we call the set_mode() function and it's the object we use when we call the update() function. A regular surface is a surface like the display surface that we can draw on it.

We can have as many surfaces as we want in a game, unlike the display_surface which we can only have one per game. We are going to use surfaces to draw text on the display surface, and display the food image later on. A rect is a rectangular area. It has a position and a size.

We use rects for the collision detection and easy manipulation of objects and for easy drawing on a surface as you are going to find out in a minute.

Food Object

Now that we know the basics of how drawing works in pygame let's draw our first object, the food object. First we have to create a rect to contain the food. This rectangle will be invisible but it will help us draw the food on the screen.

So we type:

food_rect = pygame.Rect(x, y, w, h) 

We need to know four things to create the rect object. The x and y coordinate of its top left corner and its width and its height.

Let's start with the x. Since we are using a grid we have to multiply x by the cell_size:

self.position.x * cell_size

Do the same for the y:

self.position.y * cell_size. 

The width is going to be cell_size, and the height is also going to be cell_size.

Now we can draw the food object. Let’s draw it as a square for now. Later we will load an image for this object. We are going to call the pygame.draw.rect method. This method requires 3 arguments:

  1. The surface to draw the object on,
  2. a color, and a
  3. rect.

The surface we are going to draw on is the display surface, named screen, the color is DARK_GREEN and the rect we want to draw is the food_rect.

Our draw method is ready to code. First of all we have to create a Food object.

So, before the game loop we type:

food = Food() 

Now all we have to do is to call the draw method of the food object in the main loop.

So, after this line of code we type food.draw() If we now run the game we can see a dark green square on the screen!

Our first game object is visible. Now that we have successfully drawn a square to represent the food object in your game, it's time to take it to the next level by using an actual image.

Using Graphic Image (20:24)

To load an image for the food object, we need to use the pygame.image.load() function. This function takes the file path of the image as an argument and returns a surface that you can use to draw the image on the screen. The image for the food object needs to be in folder. In our example it is named graphics and is in the 560-snake-game folder .

The name of the image in our example project is food.png. So outside of the game loop we type:

food_surface =  pygame.image.load(“graphics/food.png”) 

This line of code, returns a surface that contains our image. We need to display that surface on top of the display surface.

Pygame blit() method (21:21)

blit = block image transfer

To display the image, we will have to modify the draw method of the Food class. Instead of calling the pygame.draw.rect method, we will use the blit method of the display surface to draw the image on the screen screen.blit(). The blit method requires two arguments: the surface to draw, which is food_surface and the rect object that defines the position and size of the image on the screen which is the food_rect. Test code and confirm that the food object is is now being displayed with an image, making the game more visually appealing. For more information on the blit() function, check out:

This improvement brings us one step closer to creating a complete and polished game experience. (21:57)

Randomizing the Food position

We first coded the food in a fixed position so we could confirm that it was displaying properly. This will not work for our game because the food object will be created at the same spot every time we run the game. Let’s randomize it. In the Food class let’s create a new method called def generate_random_pos(self):

Now it is time make it appear in random positions. To do this we will need to import the random module on line 1 of our code.

import, pygame, sys, random

def generate_random_pos(self):

We need a number from 0 to 24 because we have 25 cells on each row of the grid.

x = random.randint(0, number_of_cells - 1) 

We do the same for the y coordinate of the food object.

Y = random.randint(0, number_of_cells – 1) 

Now we have to set these values to a vector2 object to return it.

position = Vector2(x,y) 

and return that position.

return position. Now in the init function all we have to do is to call this function when we set the position

of the object. So.

self.position = self.generate_random_pos() 

Now if we run the game multiple times, we can see that the food object is created in a different cell each time. Very cool! Our food object is ready, another step is now complete.

This will progress more quickly from now on!