RaZiiiGG
RaZiiiGG

Reputation: 193

Switching menus in pygame

I changed the structure of my code, but I am still running into problems when I crash, and I want to restart the game. My idea is to build 3 "screens": main menu, game, restart. I am having no problem entering the main menu, when I run the program, and click the "Start" button or the "Quit" button. But, when I enter the game, I crash, and I click the "Restart" button, but there is an error.

Here is the code:

import pygame
import sys


pygame.init()
screen = pygame.display.set_mode((1200, 600))
clock = pygame.time.Clock()
BLUE = pygame.Color('dodgerblue3')
ORANGE = pygame.Color('sienna3')
BLACK = (0, 0, 0)
WHITE = (255,255,255)
RED = (255, 0, 0)
GREEN = (13, 255, 0)
YELLOW = (0, 255, 20)
BRIGHT_YELLOW = (255, 255, 20)
vel = 4
vel_left = 5
vel_right = -5

player = pygame.Rect(40, 45, 30, 30)

rotatingrects = [
    pygame.Rect(630, 300, 250, 20),
    pygame.Rect(920, 300, 250, 20)
    ]

walls = [
    pygame.Rect(0, 0, 1200, 20), pygame.Rect(0, 0, 20, 600),
    pygame.Rect(0, 580, 1200, 20), pygame.Rect(1180, 0, 20, 600),
    pygame.Rect(300, 0, 20, 530), pygame.Rect(20, 100, 230, 20),
    pygame.Rect(70, 200, 230, 20), pygame.Rect(20, 300, 230, 20),
    pygame.Rect(70, 400, 230, 20), pygame.Rect(600, 100, 20, 500)
    ]

class MovingRect(pygame.Rect):

    def __init__(self, x, y, w, h, vel):
        # Calling the __init__ method of the parent class
        super().__init__(x, y, w, h)
        self.vel = vel

    def update(self):
        self.x += self.vel  # Moving
        if self.right > 600 or self.left < 320:  # If it's not in this area
            self.vel = -self.vel  # Inverting the direction

movingrects = [
    MovingRect(320, 120, 30, 30, vel_left),
    MovingRect(320, 240, 30, 30, vel_left),
    MovingRect(320, 360, 30, 30, vel_left),
    MovingRect(570, 180, 30, 30, vel_right),
    MovingRect(570, 300, 30, 30, vel_right),
    MovingRect(570, 420, 30, 30, vel_right)
    ]

def quit_game():
    pygame.quit()
    sys.exit()

def text_objects(text, font):
    textSurface = font.render(text, True, BLACK)
    return textSurface, textSurface.get_rect()

def button(msg, x, y, w, h, ic, ac, action = None):
    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()


    if x + w > mouse[0] > x and y + h  > mouse[1] > y:
        pygame.draw.rect(screen, ac, (x, y, w, h))
        if click[0] == 1 and action is not None:
            action()
    else:
        pygame.draw.rect(screen, ic, (x, y, w, h))

    smallText = pygame.font.Font("freesansbold.ttf",50)
    textSurf, textRect = text_objects(msg, smallText)
    textRect.center = ((x+(w/2)), (y+(h/2)))
    screen.blit(textSurf, textRect)

def restart():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit_game()

        screen.fill(BLUE)

        button("Restart", 525, 250, 150, 60, BRIGHT_YELLOW, YELLOW, menu)

        pygame.display.update()
        pygame.display.flip()
        clock.tick(60)

def front_page():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit_game()

        screen.fill(WHITE)

        button("Start", 525, 250, 150, 60, BRIGHT_YELLOW, YELLOW, menu)
        button("Quit", 525, 350, 150, 60, BRIGHT_YELLOW, YELLOW, quit_game)

        pygame.display.update()
        pygame.display.flip()
        clock.tick(60)


def menu():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit_game()

        keys = pygame.key.get_pressed()

        # Player coordinates
        if keys[pygame.K_LEFT] and player.x > 0:
            player.x -= vel
        if keys[pygame.K_RIGHT] and player.x < 1200 - player.width:
            player.x += vel
        if keys[pygame.K_UP] and player.y > 0:
            player.y -= vel
        if keys[pygame.K_DOWN] and player.y < 600 - player.height:
            player.y += vel

        for wall in walls:
            # Check if the player rectangle collides with a wall rectangle
            if player.colliderect(wall):
                print("Game over")
                restart()

        for movingrect in movingrects:
            movingrect.update()  # Movement and bounds checking
            if player.colliderect(movingrect):
                print("Game over")

        # TO DO #
        for rotatingrect in rotatingrects:
            if player.colliderect(rotatingrect):
                print("Game over")

        # Drawing everything
        screen.fill(WHITE)
        pygame.draw.rect(screen, RED, player)
        # Drawing walls and moving objects
        for rotatingrect in rotatingrects:
            pygame.draw.rect(screen, BLACK, rotatingrect)

        for wall in walls:
            pygame.draw.rect(screen, BLACK, wall)

        for movingrect in movingrects:
            pygame.draw.rect(screen, GREEN, movingrect)

        pygame.draw.rect(screen, RED, player)
        pygame.display.update()

        pygame.display.flip()
        clock.tick(60)


def main():
    scene = front_page
    while scene is not None:
        scene = scene()


main()
pygame.quit()

Upvotes: 3

Views: 883

Answers (1)

skrx
skrx

Reputation: 20448

That happens because your player rect is a global variable and it's still at the position of the collision when you restart the game.

Move the game related variables to the menu function (the game function), so that they will be reset to their original values when you call menu again.

def menu():
    vel = 4
    vel_left = 5
    vel_right = -5

    player = pygame.Rect(40, 45, 30, 30)

    rotatingrects = [
        pygame.Rect(630, 300, 250, 20),
        pygame.Rect(920, 300, 250, 20)
    ]

    walls = [
        pygame.Rect(0, 0, 1200, 20), pygame.Rect(0, 0, 20, 600),
        pygame.Rect(0, 580, 1200, 20), pygame.Rect(1180, 0, 20, 600),
        pygame.Rect(300, 0, 20, 530), pygame.Rect(20, 100, 230, 20),
        pygame.Rect(70, 200, 230, 20), pygame.Rect(20, 300, 230, 20),
        pygame.Rect(70, 400, 230, 20), pygame.Rect(600, 100, 20, 500)
    ]
    movingrects = [
        MovingRect(320, 120, 30, 30, vel_left),
        MovingRect(320, 240, 30, 30, vel_left),
        MovingRect(320, 360, 30, 30, vel_left),
        MovingRect(570, 180, 30, 30, vel_right),
        MovingRect(570, 300, 30, 30, vel_right),
        MovingRect(570, 420, 30, 30, vel_right)
    ]

Upvotes: 2

Related Questions