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)