Making a clickable grid using Pygame

Viewed 34

I'm making a minesweeper game using python. I have the game working in a text only form and I'm adding a GUI now.

I have three difficulty options with different dimensions. Is there any way to generate a grid without having to make it manually. This is how I generated a square matrix in text form:

for count in range(side):
    count2 = 0
    temp1 = []
    temp2 = []
    for count2 in range(side):
        temp1.append(0)
        temp2.append("x")
    grid.append(temp1)
    field.append(temp2)
    count+=1

Is there any way to automatically generate a grid like this in pygame? I am also using custom sprites and every cell needs to be clickable. Will I just have to make the grids manually and use them according to the difficulty?

2 Answers

There is no simple solution to draw a grid. You have to loop over each cell as you did in your example. You can find all functions to draw in the pygame wiki.

Example for grid creation:

size = (100, 100)
cell_width = 10
cell_height = 10

grid_surface = pygame.Surface(size) # here you draw
grid = [] # simple list to save your data

for x in range(side):
    grid.append([]) # new column for the list
    
    for y in range(side):
        # save data to grid
        grid[x][y] = "x"

        # draw something
        # e.g.: this draws a red rectangle in each cell
        pygame.draw.rect(grid_surface, (200, 0, 0), (x * cell_width, y * cell_height, cell_width, cell_height)

Potential event loop:

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        running = False
    elif event.type == pygame.MOUSEBUTTONDOWN:
        x, y = (event.pos[0] // cell_width, event.pos[1] // cell_height)

        # do something
        print(grid[x][y])
        grid[x][y] = "a"

        pygame.draw.rect(grid_surface, (0, 200, 0), (x * cell_width, y * cell_height, cell_width, cell_height)

I will give you a very simple start. You should create a class that represents a cell in the grid. Create a matrix of cells to represent your board:

class Cell:
    def __init__(self):
        self.clicked = False

grid_size = 10
board = [[Cell() for _ in range(grid_size)] for _ in range(grid_size)]

Calculate the index of a cell when the mouse button is clicked and change the attributes in the cell:

for event in pygame.event.get():
    # [...]

    if event.type == pygame.MOUSEBUTTONDOWN:
        if event.button == 1:
            row = event.pos[1] // 20
            col = event.pos[0] // 20
            board[row][col].clicked = True

Draw the board in 2 nested loops:

for iy, rowOfCells in enumerate(board):
    for ix, cell in enumerate(rowOfCells):
        color = (64, 64, 64) if cell.clicked else (164, 164, 164)
        pygame.draw.rect(window, color, (ix*20, iy*20, 20, 20))

Minimal example:

import pygame

class Cell:
    def __init__(self):
        self.clicked = False

grid_size = 10
board = [[Cell() for _ in range(grid_size)] for _ in range(grid_size)]

pygame.init()
window = pygame.display.set_mode((200, 200))
clock = pygame.time.Clock()

run = True
while run:
    clock.tick(100)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False 
        if event.type == pygame.MOUSEBUTTONDOWN:    
            if event.button == 1:
                row = event.pos[1] // 20
                col = event.pos[0] // 20
                board[row][col].clicked = True

    window.fill(0)
    for iy, rowOfCells in enumerate(board):
        for ix, cell in enumerate(rowOfCells):
            color = (64, 64, 64) if cell.clicked else (164, 164, 164)
            pygame.draw.rect(window, color, (ix*20+1, iy*20+1, 18, 18))
    pygame.display.flip()

pygame.quit()
exit()
Related