0

this code is for a simple, yet pretty famous game.
At the end of the page is the code that is all I have thus far. My problem lies in the is_close_to_void function, where the void is the empty square. I have a separate sprite for "the void", and use the function pygame.sprite.spritecollide()to find the cells next to the void by moving the void a few pixels, and using the command.

To activate anything, you can click on the screen, or click on any cell near the void to swap them. It does so 2 or so times, but after that, the problem begins.

So for debugging purposes, on the screen, it will show the void as a white square, and show what the is_close_to_void function does, by showing where the void moves, and printing in the console a list of numbers that pygame.sprite.spritecollide() returns.

The only clue that I have, as to what is wrong, can be seen in the console, as it prints numbers for cells that are nowhere near colliding with the void, and prints numbers for more than 1 cell in a row, even though I made sure the void only collides with only 1 cell.

What is happening here is. When the user clicks, the event.type == pygame.MOUSEBUTTONDOWN function gets triggered, which triggers is_close_to_void which looks for squares that are next to the void, changing the self.close_to_void parameter for each cell accordingly, and triggers the update function in the cell class, which swaps cells depending on the direction written in self.close_to_void.

from asyncio.windows_events import NULL
from textwrap import fill
import pygame
from sys import exit
from random import randint, choice

# init pygame

win_w = 640
win_h = 480

pygame.init()
screen = pygame.display.set_mode((win_w,win_h))
pygame.display.set_caption('Slide puzzle')
clock = pygame.time.Clock()

# class template for a cell
class cell(pygame.sprite.Sprite):
    # init() can create the rectangle and text num for each cell
    def __init__(self, number, position):
        super().__init__()
        self.image = pygame.Surface([80, 80])
        self.image.fill(green)
        self.rect = self.image.get_rect()
        self.rect.centerx = position[0]
        self.rect.centery = position[1]
        self.number = number
        self.close_to_void = False
        self.text = cell_font.render(str(number), True, white).convert_alpha()
        self.rect_t = self.text.get_rect()
        self.rect_t.centerx = position[0]
        self.rect_t.centery = position[1]


    def update(self):
        if self.close_to_void == 'left':
            for event in events:
                if event.type == pygame.MOUSEBUTTONDOWN:
                    if pygame.Rect.collidepoint(self.rect, event.pos[0], event.pos[1]):
                        self.rect.x += 81
                        self.rect_t.x += 81
                        void_cell.rect.x -= 81
                        void_cell.rect_t.x -= 81
                        self.close_to_void = False
        
        elif self.close_to_void == 'right':
            for event in events:
                if event.type == pygame.MOUSEBUTTONDOWN:
                    if pygame.Rect.collidepoint(self.rect, event.pos[0], event.pos[1]):
                        self.rect.x -= 81
                        self.rect_t.x -= 81
                        void_cell.rect.x += 81
                        void_cell.rect_t.x += 81
                        self.close_to_void = False
                        
        elif self.close_to_void == 'top':
            for event in events:
                if event.type == pygame.MOUSEBUTTONDOWN:
                    if pygame.Rect.collidepoint(self.rect, event.pos[0], event.pos[1]):
                        self.rect.y += 81
                        self.rect_t.y += 81
                        void_cell.rect.y -= 81
                        void_cell.rect_t.y -= 81
                        self.close_to_void = False
                        
        elif self.close_to_void == 'bottom':
            for event in events:
                if event.type == pygame.MOUSEBUTTONDOWN:
                    if pygame.Rect.collidepoint(self.rect, event.pos[0], event.pos[1]):
                        self.rect.y -= 81
                        self.rect_t.y -= 81
                        void_cell.rect.y += 81
                        void_cell.rect_t.y += 81
                        self.close_to_void = False


# function to make a list of cells close to the void
def is_close_to_void():

    void_cell.rect.x -= 15

    info = pygame.sprite.spritecollide(void_cell, cell_group, 0)
    for i in info:
        print(i.number)
    print('')
    screen.fill(dark_turquoise)
    cell_group.draw(screen)
    void_group.draw(screen)
    pygame.display.update()
    pygame.time.wait(1000)
    if info != []:
        info[0].close_to_void = 'left'

    void_cell.rect.x += 30
    info = pygame.sprite.spritecollide(void_cell, cell_group, 0)
    for i in info:
        print(i.number)
    print('')
    screen.fill(dark_turquoise)
    cell_group.draw(screen)
    void_group.draw(screen)
    pygame.display.update()
    pygame.time.wait(1000)
    if info != []:
        info[0].close_to_void = 'right'
    
    void_cell.rect.x -= 15
    void_cell.rect.y -= 15

    info = pygame.sprite.spritecollide(void_cell, cell_group, 0)
    for i in info:
        print(i.number)
    print('')
    screen.fill(dark_turquoise)
    cell_group.draw(screen)
    void_group.draw(screen)
    pygame.display.update()
    pygame.time.wait(1000)
    if info != []:
        info[0].close_to_void = 'top'

    void_cell.rect.y += 30

    info = pygame.sprite.spritecollide(void_cell, cell_group, 0)
    for i in info:
        print(i.number)
    print('')
    screen.fill(dark_turquoise)
    cell_group.draw(screen)
    void_group.draw(screen)
    pygame.display.update()
    pygame.time.wait(1000)
    if info != []:
        info[0].close_to_void = 'bottom'

    void_cell.rect.y -=15

# constants
fps = 3
board_w = 4  # number of columns in the board
board_h = 4 # number of rows in the board
tile_s = 80
cell_font = pygame.font.Font(None, 20)
global events

#                  R    G    B
black =         (  0,   0,   0)
white =         (255, 255, 255)
bright_blue =    (  0,  50, 255)
dark_turquoise = (  3,  54,  73)
green =         (  0, 204,   0)

# create cells for each number and put them in a group
cell_group = pygame.sprite.Group()
void_group = pygame.sprite.GroupSingle()

counter = 1

for y in range(int(-board_h/2), int(board_h/2)):
    for x in range(int(-board_w/2), int(board_w/2)):
        cell_group.add(cell(counter, (win_w/2 + tile_s/2 + 81*x, win_h/2 + tile_s/2 + 81*y)))
        counter += 1


for cell in cell_group:
    if cell.number == board_h*board_w:
        cell.number = None
        void_group.add(cell)
        cell_group.remove(cell)
        void_group.sprite.rect.w = 160
        void_group.sprite.rect.h = 160
        void_cell = void_group.sprite
        pygame.Surface.fill(void_cell.image, white)

# Main game loop:
while True:

    # check for the classic event stuff
    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if event.type == pygame.MOUSEBUTTONDOWN:
            # update classes
            is_close_to_void()
            cell_group.update()
            cell_group.draw(screen)
            void_group.draw(screen)



    # draw whatever necessare
    screen.fill(dark_turquoise)
    cell_group.draw(screen)
    void_group.draw(screen)
    for cell in cell_group:
        screen.blit(cell.text, cell.rect_t)

    # remember what moves were played 

    # make sure to have fps
    pygame.display.update()
    clock.tick(fps)
hellwraiz
  • 359
  • 2
  • 13
  • Why do you continuously wait for 1 second (`pygame.time.wait(1000)`)? – Rabbid76 May 20 '22 at 14:15
  • @Rabbid76 I move the white void square and then check for collisions to identify green squares next to it, and the app waits for 1 second to show where the square went. It is to show that I moved the square to the left, but the app says that the white square collided with the square on the right, or some other random square. – hellwraiz May 20 '22 at 14:20
  • Basically, this is what I used to identify the pygame.sprite.spritecollide command as the problem. – hellwraiz May 20 '22 at 14:21

0 Answers0