Using Pygame to color a square in the grid but can only color the first box not sure what to do

Tags: ,



I been using pygame to try to color a box I choose in some grid. The box is supposed to be colored when I hover over it with my mouse and press ‘s’ on the keyboard. Only thing is that the wrong box is being colored in the grid. It is always the first box which is being colored and not the one I pick.

The box I choose is supposed to turn green when I hover over it and press ‘s’.

Can someone look at my code to see if I have an obvious mistake? I can’t seem to figure out what’s wrong after trying to debug it for hours.

The class node represents the boxes and the grid class represents the drawn grid that holds the nodes.

This is my main.py that controls the flow of my code:

import sys
from grid import *

# Window details
height = 700
width = 700
window = pygame.display.set_mode((height, width))
window.fill(white)
pygame.display.set_caption("Path Finding Visualizer")
    

# Get the clicked position of the mouse to find the node
def get_clicked_position(mouse_position, rows):
    node_margin = width // rows
    
    x, y = mouse_position

    row = x // node_margin
    column = y // node_margin

    return row, column

# Code is controlled from here
def main(window, width):
    # Initialize pygame
    pygame.init()

    # Create specific sized grid
    amount_of_rows = 20
    amount_of_columns = 20
    grid = Grid(amount_of_rows, amount_of_columns, window, width)
    grid_array = grid.draw_grid()

    # To keep the window running
    run = True
    while run == True:
        for event in pygame.event.get():
            # User closes the window or something, end right away
            if event.type == pygame.QUIT:
                run = False

           # If a button is pressed
            if event.type == pygame.KEYDOWN: 
                # User hovers over square and clicks 's' on the keyboard
                if event.key == pygame.K_s:
                    mouse_position = pygame.mouse.get_pos()

                    clicked_row, clicked_column = get_clicked_position(mouse_position, amount_of_rows)

                    node = grid_array[clicked_row][clicked_column]
                    node.set_start()
                    grid_array[clicked_row][clicked_column] = node
                    
                    print(str(node.x) + ', ' + str(node.y))
                    # Update the grid with any new events
                    grid.update_grid(grid_array)
                    print("Set start")

                # User hovers over square and clicks 'e' on the keyboard
                if event.key == pygame.K_e:
                    mouse_position = pygame.mouse.get_pos()
             
                    clicked_row, clicked_column = get_clicked_position(mouse_position, amount_of_rows)
                    
                    node = grid_array[clicked_row][clicked_column]
                    node.set_end()
                    grid_array[clicked_row][clicked_column] = node

                    # Update the grid with any new events
                    grid.update_grid(grid_array)
                    print("Set end")

            #pygame.display.update()
        
        
main(window, width)

This is my grid.py:

from node import *

class Grid:
    def __init__(self, number_of_rows, number_of_columns, window, window_width):
        self.number_of_rows = number_of_rows
        self.number_of_columns = number_of_columns
        self.window = window
        self.window_width = window_width
        
        # Initialize an empty list to represent the grid and then add nodes to it
        self.grid_list = []

    # Initializes the grid by drawing it onto the screen and returns the grid's array that holds all of the nodes
    def draw_grid(self):
        self.draw_squares()
        self.draw_lines(1)

        pygame.display.update()

        return self.grid_list

    # Draw squares onto the screen
    def draw_squares(self):
        for row in self.grid_list:
            for node in row:
                    pygame.draw.rect(self.window, node.color, (node.x, node.y, node.node_margin, node.node_margin))

    # Draw the lines onto the screen
    def draw_lines(self, initial_grid=None):
        # Initialize the node's margin by doing integer division between the size of the window and amount of rows
        node_margin = self.window_width // self.number_of_rows 
        
        # Kind of complicated but pretty much if the grid_array is empty then intialize it with this, else update the grid
        if(initial_grid != None):
            for x in range(self.number_of_rows):
                # For every row, a list will be appended to grid and add all of the columns and its respective nodes
                self.grid_list.append([])
                
                # Draw the rows onto the window
                pygame.draw.line(self.window, grey, (0, x * node_margin), (self.window_width, x * node_margin))
                
                for y in range(self.number_of_columns):
                    # Initialize the node and make all nodes white. Then append to the row
                    node = Node(white, x, y, node_margin, self.window_width)
                    self.grid_list[x].append(node)
                    
                    # Draw the columns onto the window
                    pygame.draw.line(self.window, grey, (y * node_margin, 0), (y * node_margin, self.window_width))
        
        # Just draws the lines to update the grid since the grid is already initialized
        else:
            for x in range(self.number_of_rows):
                # Draw the rows onto the window
                pygame.draw.line(self.window, grey, (0, x * node_margin), (self.window_width, x * node_margin))
                
                for y in range(self.number_of_columns):
                    # Draw the columns onto the window
                    pygame.draw.line(self.window, grey, (y * node_margin, 0), (y * node_margin, self.window_width))

    # Every time an event occurs the grid will update the nodes that have been changed
    def update_grid(self, new_grid_list):
        self.grid_list = new_grid_list
        
        self.draw_squares()
        self.draw_lines()
        
        pygame.display.update()

This is my node.py:

import pygame

# Board and path colors
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
yellow = (255, 255, 0)
white = (255, 255, 255)
black = (0, 0, 0)
purple = (128, 0, 128)
orange = (255, 165, 0)
grey = (128, 128, 128)
turquoise = (64, 224, 208)

# These are the squares that will be marked in the grid
class Node:
    def __init__(self, color, row, column, node_margin, board_width):
        self.color = color
        self.row = row
        self.column = column
        self.board_width = board_width
        self.x = row * board_width
        self.y = column * board_width
        self.node_margin = node_margin

    # Returns position of node
    def get_position(self):
        return row, column

    # Checks if the node is the starting node for the search algorithm
    def is_start(self):
        if self.color == green:
            return True
        else:
            return False

    # Checks if the node is the ending node for the search algorithm
    def is_end(self):
        if self.color == red:
            return True
        else:
            return False

    # Resets the node to white to show nothing has happened to it
    def reset_node(self):
        self.color = white

    # Sets starting node to green
    def set_start(self):
        self.color = green

    # Sets starting node to red
    def set_end(self):
        self.color = red

Answer

You have to multiply row respectively column by node_margin rather than board_width in the constructor of Node:

class Node:
    def __init__(self, color, row, column, node_margin, board_width):
        # [...]

        self.x = row * node_margin
        self.y = column * node_margin


Source: stackoverflow