3

Im attempting intergrate this a code which auto generates a maze with my sprite code, but when I try and add my sprite code snippet the program keeps erroring.

Iv tried to remove and redefine variables and also aline the programs variables with my own snippet

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()

        new_pos = self.pos + move*(dt/5)
        new_rect = self.rect.copy()
        new_rect.center = new_pos
        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):
    background = (pygame.image.load("background.jpg"))
    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():
    while not done:
        # --- Main event loop
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return

        global current_cell
        play = False
        current_cell.visited = True
        current_cell.current = True

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

        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()
            play = True 

        """    
        elif len(stack) == 0:
            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
        """
        if play == True:
            pygame.init()
            screen_rect = screen.get_rect()

            clock = pygame.time.Clock()
            sprites = pygame.sprite.Group()

            player = None
            initialized = False
            current_maze = None
            dt = 0

            while True:
                events = pygame.event.get()

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

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

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

                if player_x >= 780 and 275 < player_y < 375:
                    current_maze += 1

                    # reset to first maze if all mazes were done
                    if current_maze >= mazes_len:
                        current_maze = 0

                    background = load_background(mazes[current_maze])
                    sprites.empty()
                    player = load_player(background)
                    sprites.add(player)

                sprites.update(events, dt)

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

                sprites.draw(screen)
                pygame.display.flip()
                dt = clock.tick(60)

        pygame.display.flip()


main()
pygame.quit()

It would be awesome if someone could help me find out what the actual issue is here as when i have scanned through the code I dont see any issues with the current variables listed as my code snippet doesnt share anything with the auto generating maze program.

Pthyon
  • 152
  • 10

1 Answers1

2

The issue is the assignment of the function objectload_backgroundtobackground` in the main loop:

background = load_background

You have to call the function load_background and to assign the return value to background:

background = load_background()

I recommend to add a default argument value to the parameter of the function load_background:

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

If you want to discard the background optionally, then set

background = None

And check for if the background is present before it is draw or accessed:

if background:
    screen.fill(pygame.Color('grey'))
    screen.blit(background, (0, 0)) 
class Player(pygame.sprite.Sprite):

    # [...]

    def update(self, events, dt):

        # [...]

        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

Avoid additional loops inside the main loop. The application should run in a single loop. In side the main loop there should be a single event loop.

the variable play is state, which indicates if the maze is set up or the game is in running state:

# initilization
# [...]

while not done:

    # event loop
    for event in pygame.event.get():

        # [...]

    if play:

        # play 
        # [...]

    else:

        # create maze
        # [...]

The state play has to be set when stack is empty:

        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

The main function may look as follows:

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:

            # [...]

            sprites.update(None, dt)

            # [...]

            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()

Finally the player won't move, because self.pos is never changed and self.rect is never set.
Set self.rect in Player.update:

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)

    self.pos = self.pos + move*(dt/5)
    self.rect.center = self.pos 
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • How would I just remove the whole picture background function all together because when ran the background appears over the actual maze which is generated – Pthyon Apr 12 '19 at 12:33
  • Last question. When adding the sprite how would I check the position of the red block so that the program knows to run the sprite function after the whole maze has been generated – Pthyon Apr 12 '19 at 13:14
  • How would colision work here atm the sprite just goes straight through walls – Pthyon Apr 24 '19 at 18:30
  • @KallumHancox Yes I know, but for this issue you've posted a new question: [Adding collision to maze walls](https://stackoverflow.com/questions/55833941/adding-collision-to-maze-walls). I'm working on an answer to the new question. Please be patient. – Rabbid76 Apr 24 '19 at 19:15
  • Yes I know, but for that issue you've posted a new question,( [Adding collision to maze walls](https://stackoverflow.com/questions/55833941/adding-collision-to-maze-walls)), which I've answered right now. – Rabbid76 Apr 24 '19 at 20:08