So I've been trying to make a simple maze game in pygame. Currently, I'm having problems with wall collision: The current collision system I'm using is buggy and doesn't work as intended:
import pygame
import random
# mazes
mazes = [
[
"wwwwwwwwwwwwwwwwwwwwwww",
"w w",
"w D",
"w D",
"w w",
"wwwwwwwwwwwwwwwwwwwwwww"
]
,
[
"wwwwwwwwwwwwwwwwwwwwwww",
"w w w",
"w w wwwwwwwwwwwwwwwww w",
"w w wD w w",
"w w wwwwwwwwwwwwwww w w",
"w w w w",
"w wwwwwwwwwwwwwwwwwww w",
"w w",
"wwwwwwwwwwwwwwwwwwwwwww"
]
]
pygame.init()
# Asset and text properties
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
# Display properties
FPS = 30
display_width = 800
display_height = int(display_width * 2 / 3)
clock = pygame.time.Clock()
block_size = display_width / 40
level = 0
def message_to_screen(msg, color, fontSize, x_axis, y_axis):
font = pygame.font.SysFont(None, fontSize)
screen_text = font.render(msg, True, color)
gameDisplay.blit(screen_text, [x_axis, y_axis])
# Create a game display
gameDisplay = pygame.display.set_mode([display_width, display_height])
pygame.display.set_caption("Mazer - Use arrow keys to move")
def gameloop(): # main function
global level
wall_maze, door_maze = buildMaze(mazes[1])
gameExit = False
gameOver = False
movementSpeed_x = 0
movementSpeed_y = 0
player_x = display_width / 10
player_y = display_height / 1.2
speed = block_size / 2
while not gameExit: #running game loop
while gameOver:
gameDisplay.fill(white)
message_to_screen("Press Q to quit",
red, 40, display_width / 7, display_height / 3 )
message_to_screen("Press N for next level", red, 40,
display_width / 7, display_height / 3 + 40)
pygame.display.update()
for event in pygame.event.get():
if event == pygame.QUIT:
gameExit = True
gameOver = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameExit = True
gameOver = False
elif event.key == pygame.K_n:
level += 1
gameOver = False
gameloop()
# Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
# Movement control
if movementSpeed_y == 0:
if event.key == pygame.K_LEFT:
movementSpeed_x = -speed
if event.key == pygame.K_RIGHT:
movementSpeed_x = speed
if movementSpeed_x == 0:
if event.key == pygame.K_DOWN:
movementSpeed_y = speed
if event.key == pygame.K_UP:
movementSpeed_y = -speed
if event.type == pygame.KEYUP and event.type != pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_DOWN or \
event.key == pygame.K_UP or event.key == pygame.K_RIGHT:
movementSpeed_x = 0
movementSpeed_y = 0
if movementSpeed_x > 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_x = 0
player_x -= speed
elif movementSpeed_x < 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_x = 0
player_x += speed
if movementSpeed_y > 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_y = 0
player_y -= speed
elif movementSpeed_y < 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_y = 0
player_y += speed
player_x += movementSpeed_x
player_y += movementSpeed_y
# Movement control
# Rendering
gameDisplay.fill(white)
mazer = player(block_size, player_x, player_y)
movingSprites = pygame.sprite.Group()
movingSprites.add(mazer)
wall_maze.draw(gameDisplay)
door_maze.draw(gameDisplay)
movingSprites.draw(gameDisplay)
pygame.display.update()
clock.tick(FPS) # FPS tick
if pygame.sprite.spritecollideany(mazer, door_maze):
gameOver = True
pygame.quit()
quit()
class asset(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class player(asset): # Class for player
def __init__(self, size, x, y):
# Image properties for player
super().__init__()
self.image = pygame.Surface([size, size])
self.image.fill(red)
self.rect = self.image.get_rect()
# Player's position
self.rect.x = x
self.rect.y = y
class wall(asset): # Class for wall blocks
def __init__(self, size, x , y):
# Image properties for wall
super().__init__()
self.image = pygame.Surface([size, size])
self.image.fill(black)
self.rect = self.image.get_rect()
# Wall's position
self.rect.x = x
self.rect.y = y
class door(asset):
def __init__(self, size, x, y):
super().__init__()
self.image = pygame.Surface([size, size])
self.image.fill(blue)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def buildMaze(Maze):
wall_list = pygame.sprite.Group()
door_list = pygame.sprite.Group()
pos_x = display_width / 10 - block_size
pos_y = display_height / 1.2 + block_size
for row in Maze:
for space in row:
if space == "w":
wall_maze = wall(block_size, pos_x, pos_y)
wall_list.add(wall_maze)
elif space == "D":
door_maze = door(block_size, pos_x, pos_y)
door_list.add(door_maze)
pos_x += block_size
pos_y -= block_size
pos_x = display_width / 10 - block_size
return wall_list, door_list
gameloop()
If you try to run the code and play around with the game, you'll notice that when you move toward a wall, the player will usually stay inside the wall and the control is inverted (move right when pressing left). I suspected that it has to do with how I constructed my collision detector:
if movementSpeed_x > 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_x = 0
player_x -= speed
elif movementSpeed_x < 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_x = 0
player_x += speed
if movementSpeed_y > 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_y = 0
player_y -= speed
elif movementSpeed_y < 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_y = 0
player_y += speed
One more thing, I thought that by having this code before pygame.display.update(), it wouldn't show the player hitting the wall because the position is supposed to be updated before that but somehow it doesn't work as intended. Thank you for looking at my code.