I'm approaching PyGame but I stepped on a problem: I am trying to draw a grid made out of single rectangle drawings, I want each one of those rectangle to fill or empty when the left mouse button is released on said rectangle. The grid i represented by a matrix of tuples each one representing each rectangle formatted like this (column, row) to be in line with pygame pixel's coordinates, then I create another matrix of tuples to convert from mouse position tuples (colpixel, rowpixel) to rectangle tuples, I also created a dictionary that pairs rectangle tuples as keys with a value that can be 1 or 0, that value represents whether the rectangle is filled or not, that is the value that I change when the mouse button is released. Here is the code:
import pygame
pygame.init()
SCREEN_WIDTH = 40
SCREEN_HEIGHT = 20
DIM = 20
ROWS = int(SCREEN_HEIGHT / DIM)
COLUMNS = int(SCREEN_WIDTH / DIM)
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Game of Life')
# filling rect_matrix with tuple, each one representing a rectangle of the grid (columns, rows).
# filling rect_map by pairing the tuples from rect_matrix with a value that can be 0 or 1, default 1.
rect_matrix = []
rect_map = {}
for i in range(ROWS):
temp = []
for j in range(COLUMNS):
temp.append(pygame.Rect((j * DIM, i * DIM), (DIM, DIM)))
rect_map[(j, i)] = 1
rect_matrix.append(temp)
# filling mouse_to_rectangle, sort of a decoder to convert from groups of tuples
# (representing mouse coordinates in pixels) to a single tuple (representing single rectangles)
mouse_to_rectangle = []
ii = 0
for i in range(SCREEN_WIDTH):
jj = 0
temp = []
for j in range(SCREEN_HEIGHT):
temp.append((ii, jj))
if ((j + 1) % DIM == 0):
jj += 1
if ((i + 1) % DIM == 0):
ii += 1
mouse_to_rectangle.append(temp)
is_running = True
while is_running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
is_running = False
pygame.quit()
exit()
if event.type == pygame.MOUSEBUTTONUP:
if rect_map[mouse_to_rectangle[pygame.mouse.get_pos()[0]][pygame.mouse.get_pos()[1]]] == 1:
rect_map[mouse_to_rectangle[pygame.mouse.get_pos()[0]][pygame.mouse.get_pos()[1]]] = 0
else:
rect_map[mouse_to_rectangle[pygame.mouse.get_pos()[0]][pygame.mouse.get_pos()[1]]] = 1
for i, ii in zip(rect_matrix, range(len(rect_matrix))):
for j, jj in zip(i, range(len(i))):
pygame.draw.rect(screen, (100, 100, 100), j, rect_map[(jj, ii)])
pygame.display.update()
I managed to fill (relative value in rect_map goes to 1) a rectangle upon releasing the left button when pointing it but when I try to click again on a rectangle that is now filled it won't empty. I represented the "filled or not" property with ones or zeroes beacuse the rectangle is filled when the width
parameter in pygame.draw.rect
is set to 0, if a >0
value is used then the rectangle will have a border as thick as the specified value in pixel.
You missed to clear the display before drawing the grid. Thus all the rectangles which hav been draw stayed there for ever:
screen.fill((0, 0, 0))
Anyway you've over complicated the algorithm. The position in the grind can be computed by dividing the components of the mouse position by DIM
(//
(floor division) operator):
mousepos = pygame.mouse.get_pos()
gridpos = mousepos[0] // DIM, mousepos[1] // DIM
Finally it the grid state can be changed with ease and mouse_to_rectangle
is not need at all:
if rect_map[gridpos] == 1:
rect_map[gridpos] = 0
else:
rect_map[gridpos] = 1
See the example:
import pygame
pygame.init()
SCREEN_WIDTH = 200
SCREEN_HEIGHT = 200
DIM = 20
ROWS = int(SCREEN_HEIGHT / DIM)
COLUMNS = int(SCREEN_WIDTH / DIM)
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Game of Life')
# filling rect_matrix with tuple, each one representing a rectangle of the grid (columns, rows).
# filling rect_map by pairing the tuples from rect_matrix with a value that can be 0 or 1, default 1.
rect_matrix = []
rect_map = {}
for i in range(ROWS):
temp = []
for j in range(COLUMNS):
temp.append(pygame.Rect((j * DIM, i * DIM), (DIM, DIM)))
rect_map[(j, i)] = 1
rect_matrix.append(temp)
is_running = True
while is_running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
is_running = False
pygame.quit()
exit()
if event.type == pygame.MOUSEBUTTONUP:
mousepos = pygame.mouse.get_pos()
gridpos = mousepos[0] // DIM, mousepos[1] // DIM
if rect_map[gridpos] == 1:
rect_map[gridpos] = 0
else:
rect_map[gridpos] = 1
screen.fill((0, 0, 0))
for i, ii in zip(rect_matrix, range(len(rect_matrix))):
for j, jj in zip(i, range(len(i))):
pygame.draw.rect(screen, (100, 100, 100), j, rect_map[(jj, ii)])
pygame.display.update()