giodamelio
giodamelio

Reputation: 5605

pygame class structure

My goal is to make a module that will make a grid on a pygame canvas and allow you to highlight boxes by their x and y coords.

Here is a simple example usage.

from grid import Grid

g = Grid(100, 100, 10) # width and height in cells, cell width in pixels
g.highlightBox(2, 2, (0, 255, 0)) # cell x and y, rgb color tuple
g.clearGrid()

Here is the code I have so far. The problem is, I need to have an event loop to keep the window open and make the close button functional, but I also need to allow the other functions to draw to the screen.

import pygame
import sys

class Grid:
    colors = {"blue":(0, 0, 255), "red":(255, 0, 0), "green":(0, 255, 0), "black":(0, 0, 0), "white":(255, 255, 255)}

    def __init__(self, width, height, cellSize, borderWidth=1):
        self.cellSize = cellSize
        self.borderWidth = borderWidth
        self.width = width * (cellSize + borderWidth)
        self.height = height * (cellSize + borderWidth)
        self.screen = pygame.display.set_mode((self.width, self.height))

        running = True
        while running:
            event = pygame.event.poll()
            if event.type == pygame.QUIT:
                running = False

    def clearGrid(self):
        pass

    def highlightBox(self, x, y, color):
        xx = x * (self.cellSize + self.borderWidth)
        yy = y * (self.cellSize + self.borderWidth)
        pygame.draw.rect(self.screen, color, (xx, yy, self.cellSize, self.cellSize), 0)

When I run the first sample, the code will be stuck in the loop, not allowing me to run the highlightBox function until the loop is done(the exit button is pressed).

Upvotes: 1

Views: 1736

Answers (3)

giodamelio
giodamelio

Reputation: 5605

I got a working version with the multiprocessing library and pipes. It seems kinda unpythonic but it will work for this project.

import pygame
import sys
from multiprocessing import Process, Pipe

class Grid:
    colors = {"blue":(0, 0, 255), "red":(255, 0, 0), "green":(0, 255, 0), "black":(0, 0, 0), "white":(255, 255, 255)}

    def __init__(self, width, height, cellSize, borderWidth=1):
        self.cellSize = cellSize
        self.borderWidth = borderWidth
        self.width = width * (cellSize + borderWidth)
        self.height = height * (cellSize + borderWidth)

        #pygame.draw.rect(self.screen, todo[1], (todo[2], todo[3], todo[4], todo[5]), 0)
        self.parent_conn, self.child_conn = Pipe()
        self.p = Process(target=self.mainLoop, args=(self.child_conn, self.width, self.height,))
        self.p.start()

    def close():
        self.p.join()

    def clearGrid(self):
        pass

    def highlightBox(self, x, y, color):
        xx = x * (self.cellSize + self.borderWidth)
        yy = y * (self.cellSize + self.borderWidth)
        self.parent_conn.send(["box", color, xx, yy, self.cellSize, self.cellSize])

    def mainLoop(self, conn, width, height):
        #make window
        screen = pygame.display.set_mode((self.width, self.height))

        running = True
        while running:
            # is there data to read
            if conn.poll():
                #read all data
                todo = conn.recv()
                print("Recived " + str(todo))

            #do the drawing
            if todo[0] == "box":
                print("drawing box")
                pygame.draw.rect(screen, todo[1], (todo[2], todo[3], todo[4], todo[5]), 0) #color, x, y, width, height
                todo = ["none"]

            #draw to screen
            pygame.display.flip()

            #get events
            event = pygame.event.poll()
            if event.type == pygame.QUIT:
                running = False

Upvotes: 0

CGGJE
CGGJE

Reputation: 465

I think what you need is to disconnect the Grid class from the display of it. You sould make it generate surfaces, that would be printed to the screen Surface by the main game-loop. Your init , highlight_cell, and clear_grid methods could return Surfaces for example, or make a get_surface method that would be called once every game-loop

This would give much more flexibility

Upvotes: 1

Paul Manta
Paul Manta

Reputation: 31567

For starters, I wouldn't put the game loop inside the initialization function; find some other place for it. To solve this, simply put the code you want to execute in the game loop, next to the code for handling events:

running = True
while running:
    event = pygame.event.poll()
    if event.type == pygame.QUIT:
        running = False

    # Print your screen in here
    # Also do any other stuff that you consider appropriate

Upvotes: 1

Related Questions