Snake - Part 4: Grid lock

Drawing a grid

Since we are trying to build a snake game, which by its nature is based on cells, I suggest we utilize cell borders to draw the grid.

As we will be strictly painting cells as a whole, I have written a function which takes cell coordinates and colors as input and translates those to window coordinates, perfectly drawing a cell just where we want one.
Setting the border color is optional, since we want it to be the same color most of the time anyway.

This funcion utlizies pygame.Rect(x_coordinate,y_coordinate,width,height) to define the location and shape of the cell, we would like to draw and pygame.draw.rect(window,color,rectangle,[border_size])

def draw_cell(x,y,color,border_color=(0,0,0)):
    border_width_as_divisor = 10 #how much of the cells width will be border? e.g. 1/10
    rect = pygame.Rect(x*cell_size,y*cell_size,cell_size,cell_size) #define rectangle to draw
    pygame.draw.rect(display_surf,color,rect) #draw the cell
    pygame.draw.rect(display_surf,border_color,rect,cell_size//border_width_as_divisor) #draw the border

This game will always have a square playing field, with a fixed number of cells, so we will need to derive the actual size of the cells from the size of the window.
More precisely, we will need to derive the cell size from the smaller side of the window.

For tackling just this task, I have written a simple function, which takes a tuple, just like when we set the window size, and returns the smaller of the dimensions.

Now, we just need to define the size of our playing field and draw it.
To calculate the cell size, we can divide the shorter dimension of our window by the number of cells we want to draw.
Since we already have a function which takes care of where to draw the cells, all we need to do is recurse through the possible cell coordinates and draw them.

def smaller_side(tuple):
    a,b=tuple
    if(a<=b):
        return a
    else:
        return b

...

playing_field_size = 10
cell_size = smaller_side(display_surf.get_size())//playing_field_size

...

#while:
    for x in range(0,playing_field_size):
        for y in range(0,playing_field_size):
            draw_cell(x,y,(0,0,0))

To finish this step off, I have made the window resizable as per part one of the series.

After resizing, we will need to redefine the size of our display surface.
To do this, we can process the pygame.VIDEORESIZE event to get the current width and height of our window.

Now, if we move the definition of our display surface and cell size inside the loop and set display_size whenever the window size changes, we can resize the window on the fly and our playing field will change with it.

import pygame
is_running = True
pygame.init()
display_size = (600,600)

playing_field_size = 10

def draw_cell(x,y,color,border_color=(0,0,0)):
    border_width_as_divisor = 10
    rect = pygame.Rect(x*cell_size,y*cell_size,cell_size,cell_size)
    pygame.draw.rect(display_surf,color,rect)
    pygame.draw.rect(display_surf,border_color,rect,cell_size//border_width_as_divisor)

def smaller_side(tuple):
    a,b=tuple
    if(a<=b):
        return a
    else:
        return b

while(is_running):
    display_surf = pygame.display.set_mode(display_size, pygame.HWSURFACE | pygame.DOUBLEBUF | pygame.RESIZABLE)
    cell_size = smaller_side(display_surf.get_size())//playing_field_size

    for x in range(0,playing_field_size):
        for y in range(0,playing_field_size):
            draw_cell(x,y,(150,150,150))

    pygame.display.update()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            is_running = False
        if event.type == pygame.VIDEORESIZE:
            display_size = [event.w,event.h]

pygame.quit()

Next up we will take a look at OOP1, defining some more functions and classes.


  1. Object oriented programming ↩︎