Adding collision to maze walls

Can someone please help me adding collision points to my sprites. I had a past code where I layered a bitmap over images but the same code does not integrate well for physically drawing lines rather than detecting where the black/grey is on an image

import random
import pygame
pygame.init()

WHITE = (255,255,255)
GREY = (20,20,20)
BLACK = (0,0,0)
PURPLE = (100,0,100)
RED = (255,0,0)

size = (701,701)
screen = pygame.display.set_mode(size)

pygame.display.set_caption("Maze Generator")

done = False

clock = pygame.time.Clock()

width = 25
cols = int(size[0] / width)
rows = int(size[1] / width)

stack = []

pos = (0,0)
class Player(pygame.sprite.Sprite):
    def __init__(self, image, pos, background):
        super().__init__()
        self.image = image
        self.pos = pygame.Vector2(pos)
        self.rect = self.image.get_rect(center=self.pos)
        self.background = background

    def update(self, events, dt):
        pressed = pygame.key.get_pressed()
        move = pygame.Vector2((0, 0))
        if pressed[pygame.K_w]: move += (0, -1)
        if pressed[pygame.K_a]: move += (-1, 0)
        if pressed[pygame.K_s]: move += (0, 1)
        if pressed[pygame.K_d]: move += (1, 0)
        #if move.length() > 0: move.normalise_ip()

        self.pos = self.pos + move*(dt/5)
        self.rect.center = self.pos        

        if self.background:

            new_rect.clamp_ip(self.background.get_rect())
            new_pos = new_rect.center

            hit_box = self.background.subsurface(new_rect)
            for x in range(new_rect.width):
                for y in range(new_rect.height):
                    if sum(hit_box.get_at((x, y))) < 500:
                        return

def load_background(filename=None):
    name = filename if filename else "background.jpg"
    background = pygame.image.load(name)
    background = pygame.transform.rotate(background, -90)
    background = pygame.transform.scale(background, (800,600))
    return background

def load_player(background):
    pimg = pygame.Surface((10, 10))
    pimg.fill((200, 20, 20))
    return Player(pimg, (25, 325), background)

class Cell():
    def __init__(self,x,y):
        global width
        self.x = x * width
        self.y = y * width

        self.visited = False
        self.current = False

        self.walls = [True,True,True,True] # top , right , bottom , left

        # neighbors
        self.neighbors = []

        self.top = 0
        self.right = 0
        self.bottom = 0
        self.left = 0

        self.next_cell = 0

    def draw(self):
        if self.current:
            pygame.draw.rect(screen,RED,(self.x,self.y,width,width))
        elif self.visited:
            pygame.draw.rect(screen,WHITE,(self.x,self.y,width,width))

            if self.walls[0]:
                pygame.draw.line(screen,BLACK,(self.x,self.y),((self.x + width),self.y),1) # top
            if self.walls[1]:
                pygame.draw.line(screen,BLACK,((self.x + width),self.y),((self.x + width),(self.y + width)),1) # right
            if self.walls[2]:
                pygame.draw.line(screen,BLACK,((self.x + width),(self.y + width)),(self.x,(self.y + width)),1) # bottom
            if self.walls[3]:
                pygame.draw.line(screen,BLACK,(self.x,(self.y + width)),(self.x,self.y),1) # left

    def checkNeighbors(self):
        #print("Top; y: " + str(int(self.y / width)) + ", y - 1: " + str(int(self.y / width) - 1))
        if int(self.y / width) - 1 >= 0:
            self.top = grid[int(self.y / width) - 1][int(self.x / width)]
        #print("Right; x: " + str(int(self.x / width)) + ", x + 1: " + str(int(self.x / width) + 1))
        if int(self.x / width) + 1 <= cols - 1:
            self.right = grid[int(self.y / width)][int(self.x / width) + 1]
        #print("Bottom; y: " + str(int(self.y / width)) + ", y + 1: " + str(int(self.y / width) + 1))
        if int(self.y / width) + 1 <= rows - 1:
            self.bottom = grid[int(self.y / width) + 1][int(self.x / width)]
        #print("Left; x: " + str(int(self.x / width)) + ", x - 1: " + str(int(self.x / width) - 1))
        if int(self.x / width) - 1 >= 0:
            self.left = grid[int(self.y / width)][int(self.x / width) - 1]
        #print("--------------------")

        if self.top != 0:
            if self.top.visited == False:
                self.neighbors.append(self.top)
        if self.right != 0:
            if self.right.visited == False:
                self.neighbors.append(self.right)
        if self.bottom != 0:
            if self.bottom.visited == False:
                self.neighbors.append(self.bottom)
        if self.left != 0:
            if self.left.visited == False:
                self.neighbors.append(self.left)

        if len(self.neighbors) > 0:
            self.next_cell = self.neighbors[random.randrange(0,len(self.neighbors))]
            return self.next_cell
        else:
            return False

def removeWalls(current_cell,next_cell):
    x = int(current_cell.x / width) - int(next_cell.x / width)
    y = int(current_cell.y / width) - int(next_cell.y / width)
    if x == -1: # right of current
        current_cell.walls[1] = False
        next_cell.walls[3] = False
    elif x == 1: # left of current
        current_cell.walls[3] = False
        next_cell.walls[1] = False
    elif y == -1: # bottom of current
        current_cell.walls[2] = False
        next_cell.walls[0] = False
    elif y == 1: # top of current
        current_cell.walls[0] = False
        next_cell.walls[2] = False

grid = []

for y in range(rows):
    grid.append([])
    for x in range(cols):
        grid[y].append(Cell(x,y))

current_cell = grid[0][0]
next_cell = 0

# -------- Main Program Loop -----------
def main():
    global current_cell

    player = None
    initialized = False
    current_maze = None
    dt = 0  
    screen_rect = screen.get_rect()
    clock = pygame.time.Clock()
    sprites = pygame.sprite.Group()

    if not initialized:
        #current_maze = 0
        background = load_background()
        background = None
        player = load_player(background)
        sprites.add(player)
        initialized = True

    play = False 
    while not done:
        # --- Main event loop
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return

        for y in range(rows):
            for x in range(cols):
                grid[y][x].draw()

        if play == True:
            pygame.init()

            while not done:
                events = pygame.event.get()

                for e in events:
                    if e.type == pygame.QUIT:
                        return

                player_x = player.pos[0]
                player_y = player.pos[1]

                sprites.update(None, dt)

                #screen.fill(pygame.Color('grey'))
                #screen.blit(background, (0, 0))

                sprites.draw(screen)
                pygame.display.flip()
                dt = clock.tick(60)
        else:
            current_cell.visited = True
            current_cell.current = True

            next_cell = current_cell.checkNeighbors()
            if next_cell != False:
                current_cell.neighbors = []
                stack.append(current_cell)
                removeWalls(current_cell,next_cell)
                current_cell.current = False
                current_cell = next_cell
            elif len(stack) > 0:
                current_cell.current = False
                current_cell = stack.pop()
            else:
                play = True
        pygame.display.flip()


main()
pygame.quit()

I would love if anyone could help or point me in the right direction.


    end_rect = pygame.draw.rect(screen, RED, (800-width, 600-width, width, width))
    if player.rect.colliderect(end_rect):
                    screen.fill(BLACK)
                    end = True

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Ensure that the Player object is positioned in the center of cell of the grid. e.g. calculate a random position for the player:

def load_player(background):
    pimg = pygame.Surface((10, 10))
    pimg.fill((200, 20, 20))

    px = random.randint(0, rows-1) * width + width//2
    py = random.randint(0, cols-1) * width + width//2
    return Player(pimg, (px, py), background)

To track the player, but highlight the player position, the current player position has to be tint in a different color, before the player is updated and is redrawn:

pygame.draw.rect(screen, (255, 164, 164), player.rect)
sprites.update(None, dt)
sprites.draw(screen)

For the collision test:

  • The current position of the player in the grid has to be identified.
  • The new possible new position of the player, dependent on the movement has to be identified.
  • If a wall is on the track from the current to the new position, then the movement has to be skipped
class Player(pygame.sprite.Sprite):
    def __init__(self, image, pos, background):
        super().__init__()
        self.image = image
        self.pos = pygame.Vector2(pos)
        self.rect = self.image.get_rect(center=self.pos)
        self.background = background

    def update(self, events, dt):
        pressed = pygame.key.get_pressed()
        move = pygame.Vector2((0, 0))

        # calculate maximum movement and current cell position  
        testdist = dt // 5 + 2
        cellx = self.rect.centerx // width
        celly = self.rect.centery // width
        minx = self.rect.left // width
        maxx = self.rect.right // width
        miny = self.rect.top // width
        maxy = self.rect.bottom // width

        # test move up
        if minx == maxx and pressed[pygame.K_w]:
            nexty = (self.rect.top-testdist) // width
            if celly == nexty or (nexty >= 0 and not grid[celly][cellx].walls[0]):
                move += (0, -1)

        # test move right
        elif miny == maxy and pressed[pygame.K_d]:
            nextx = (self.rect.right+testdist) // width
            if cellx == nextx or (nextx < cols and not grid[celly][cellx].walls[1]):
                move += (1, 0)

        # test move down
        elif minx == maxx and pressed[pygame.K_s]:
            nexty = (self.rect.bottom+testdist) // width
            if celly == nexty or (nexty < rows and not grid[celly][cellx].walls[2]):
                move += (0, 1)            

        # test move left
        elif miny == maxy and pressed[pygame.K_a]:
            nextx = (self.rect.left-testdist) // width
            if cellx == nextx or (nextx >= 0 and not grid[celly][cellx].walls[3]):
                move += (-1, 0)

        self.pos = self.pos + move*(dt/5)
        self.rect.center = self.pos

eudwk


If you want to restart the maze, the you’ve to get rid of the nested game loops. Use 1 game loop and a condition, which state if the game is in play state or initializing the maze.

To check if the player has reached the goal can be done by pygame.Rect.colliderect():

finished = pygame.Rect(0, 0, width, width).colliderect(player.rect)

To restart you’ve to reset the grid:

grid = []
for y in range(rows):
    grid.append([])
    for x in range(cols):
        grid[y].append(Cell(x,y))
current_cell = grid[0][0]

Set the player to a new random position:

px = random.randint(0, rows-1) * width + width//2
py = random.randint(0, cols-1) * width + width//2
player.pos = pygame.Vector2(px, py)
player.rect = player.image.get_rect(center=player.pos)

Clear the background and reset the state play:

screen.fill(0)
play = False

Full main code:

def main():
    global current_cell, grid

    player = None
    initialized = False
    current_maze = None
    dt = 0  
    screen_rect = screen.get_rect()
    clock = pygame.time.Clock()
    sprites = pygame.sprite.Group()

    if not initialized:
        #current_maze = 0
        background = load_background()
        background = None
        player = load_player(background)
        sprites.add(player)
        initialized = True

    play = False 
    while not done:
        # --- Main event loop
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return

        if play == True:

            pygame.draw.rect(screen, (255, 164, 164), player.rect)
            sprites.update(None, dt)
            sprites.draw(screen)

            dt = clock.tick(60)

            finished = pygame.Rect(0, 0, width, width).colliderect(player.rect)
            if finished:
                # init new grid
                grid = []
                for y in range(rows):
                    grid.append([])
                    for x in range(cols):
                        grid[y].append(Cell(x,y))
                current_cell = grid[0][0]
                # create new random player positon
                px = random.randint(0, rows-1) * width + width//2
                py = random.randint(0, cols-1) * width + width//2
                player.pos = pygame.Vector2(px, py)
                player.rect = player.image.get_rect(center=player.pos)
                # clear screen
                screen.fill(0)
                play = False

        else:
            current_cell.visited = True
            current_cell.current = True

            next_cell = current_cell.checkNeighbors()
            if next_cell != False:
                current_cell.neighbors = []
                stack.append(current_cell)
                removeWalls(current_cell,next_cell)
                current_cell.current = False
                current_cell = next_cell
            elif len(stack) > 0:
                current_cell.current = False
                current_cell = stack.pop()
            else:
                play = True

            for y in range(rows):
                for x in range(cols):
                    grid[y][x].draw()

        pygame.display.flip()


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x