Избавляемся от рекурсии в Pygame - PullRequest
0 голосов
/ 25 августа 2018

Я сделал игру в пигме, которая включает в себя главное меню, игровой цикл, экран победы и экран сбоя.Моя игра работает так, как я хочу, чтобы она работала, но я знаю, что каждый раз, когда меняю экран, я просто углубляюсь в цикл, и игра может вылететь, когда я достигну 1000 рекурсий (я так думаю?)).Я не знаю, как это исправить, поэтому, если вы могли бы, пожалуйста, помогите мне.

Вот код:

import pygame
import sys


pygame.init()
pygame.display.set_caption("My Game")
screen_width, screen_height = 1200, 600
screen = pygame.display.set_mode((screen_width, screen_height))
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)
font = pygame.font.Font(None, 25)
frame_rate = 60
last_seconds = None

class Walls(pygame.Rect):

    def __init__(self, x, y, w, h):
        super().__init__(x, y, w, h)


class LeftRedRect(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


class RightRedRect(pygame.Rect):

    def __init__(self, x, y, w, h, vel):
        super().__init__(x, y, w, h)
        self.vel = vel

    def update(self):
        self.x += self.vel
        if self.right > 1180 or self.left < 620:
            self.vel = -self.vel


class UpAndDownRedRect(pygame.Rect):

    def __init__(self, x, y, w, h, vel):
        super().__init__(x, y, w, h)
        self.vel = vel

    def update(self):
        self.y += self.vel
        if self.top < 20 or self.bottom > 535:
            self.vel = -self.vel


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

def message_display(text):
    largeText = pygame.font.Font(None, 115)
    screen.blit(largeText.render(text, True, BLUE), (370, 250))
    pygame.display.update()

    pygame.time.wait(1500)

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",35)
    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(WHITE)

        largeText = pygame.font.Font(None, 115)
        screen.blit(largeText.render("You lost", True, BLUE), (420, 50))

        button("Restart", 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 victory_screen():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit_game()

        screen.fill(WHITE)

        #TO DO: POSITION THE TEXT#
        largeText = pygame.font.Font(None, 115)
        screen.blit(largeText.render("Congratulations!", True, BLUE), (300, 50))
        largeText = pygame.font.Font(None, 60)
        screen.blit(largeText.render("You beat the game!", True, BLUE), (400, 150))

        button("Restart", 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(frame_rate)

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

        screen.fill(WHITE)

        largeText = pygame.font.Font(None, 115)
        screen.blit(largeText.render("My Game", True, BLUE), (430, 50))

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


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

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

    finish_line = pygame.Rect(620, 535, 560, 45)

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

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

    rightredrects = [
        RightRedRect(1140, 120, 30, 30, vel_left),
        RightRedRect(1140, 240, 30, 30, vel_left),
        RightRedRect(1140, 360, 30, 30, vel_left),
        RightRedRect(620, 180, 30, 30, vel_right),
        RightRedRect(620, 300, 30, 30, vel_right),
        RightRedRect(620, 420, 30, 30, vel_right),
    ]

    upanddownredrects = [
        UpAndDownRedRect(620, 20, 30, 30, vel_up),
        UpAndDownRedRect(752, 505, 30, 30, vel_up),
        UpAndDownRedRect(885, 20, 30, 30, vel_up),
        UpAndDownRedRect(1016, 505, 30, 30, vel_up),
        UpAndDownRedRect(1150, 20, 30, 30, vel_up)
    ]

    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

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

        for rect in rightredrects:
            rect.update()  # Movement and bounds checking
            if player.colliderect(rect):
                print("Game over")
               # message_display("Game Over")
               # restart()

        for rect in leftredrects:
            rect.update()
            if player.colliderect(rect):
                print("Game over")
               # message_display("Game Over")
                #restart()

        for rect in upanddownredrects:
            rect.update()
            if player.colliderect(rect):
                print("Game over")
                #message_display("Game Over")
                #restart()

        if player.colliderect(finish_line):
            print("You beat the game")
            victory_screen()

        # Drawing everything
        screen.fill(WHITE)

        pygame.draw.rect(screen, BRIGHT_YELLOW, finish_line)

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

        for rect in rightredrects:
            pygame.draw.rect(screen, RED, rect)

        for rect in leftredrects:
            pygame.draw.rect(screen, RED, rect)

        for rect in upanddownredrects:
            pygame.draw.rect(screen, RED, rect)


        pygame.draw.rect(screen, GREEN, player)

        pygame.display.update()

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


def main():
    scene = front_page  # Set the current scene.
    while scene is not None:
        # Execute the current scene function. When it's done
        # it returns either the next scene or None which we
        # assign to the scene variable.
        scene = scene()


main()
pygame.quit()

Ответы [ 2 ]

0 голосов
/ 26 августа 2018

Вы можете добавить переменную next_scene к вашей сцене и установить ее для следующей функции сцены, когда кнопка нажата.В цикле while вы должны проверить if next_scene is not None: и затем вернуть next_scene в функцию main, где она будет вызываться.Чтобы изменить переменную next_scene, необходимо определить вложенные функции обратного вызова.

def front_page():
    next_scene = None

    def start_game():
        nonlocal next_scene
        # Set the `next_scene` variable in the enclosing scope
        # to the `menu` function.
        next_scene = menu

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

        # Return the next scene to the `main` function if the variable is not None.
        if next_scene is not None:
            return next_scene

        screen.fill(WHITE)

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

        pygame.display.flip()  # Don't call both display.update and display.flip.
        clock.tick(60)

В функции menu вы можете просто вернуть функцию restart, когда игрок касается стены или движущегося объекта.прямоугольник:

for wall in walls:
    # Check if the player rectangle collides with a wall rectangle
    if player.colliderect(wall):
        print("Game over")
        return restart
0 голосов
/ 25 августа 2018

для каждого места, где вы печатаете («Игра окончена»), возвращает True, как я делал в этой части вашего кода:

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

, если вы не играете до сих порцикл while, и он будет печатать «игра окончена» до тех пор, пока вы не сможете приготовить яйца на своем компьютере или он не даст сбой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...