Game Over Screen с использованием Pygame - PullRequest
0 голосов
/ 04 мая 2020

Я пытаюсь завершить sh версию понга, и я хочу, чтобы игра заканчивалась, когда игрок пропускает мяч, и он падает на стену за веслом. Я пытался создать экран Game Over для этого и не повезло. Я хочу, чтобы у пользователя была возможность перезапустить новую игру или выйти из экрана все вместе.

# Import the pygame library and initialise the game 
# the scoring system will be inside of the main game
# the paddle and ball classes are imported into the main game
# still trying to work out how to make the other paddle move without keyboard input
import pygame
from Paddle import Paddle
from Ball import Ball
#while running loop
     #rest of the code

pygame.init()
black = (0,0,0)
white = (255,255,255)


paddle2 = Paddle(white, 10, 100)
paddle2.rect.x = 670
paddle2.rect.y = 200

ball = Ball(white,8,8)
ball.rect.x = 345
ball.rect.y = 195

width = 700
height = 500

size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Pong")

user_lose = False

sprites_list = pygame.sprite.Group()

sprites_list.add(paddle2)
sprites_list.add(ball)

carryOn = True

clock = pygame.time.Clock()

#Set inital player scores:
scoreA = 0
scoreB = 0



# -------- Main Program Loop -----------
while carryOn:
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
              carryOn = False 
        elif event.type==pygame.KEYDOWN:
                if event.key==pygame.K_x: 
                     carryOn=False 


    keys = pygame.key.get_pressed()
    if keys[pygame.K_UP]:
        paddle2.up(5)
    if keys[pygame.K_DOWN]:
        paddle2.down(5)

    sprites_list.update()

    if ball.rect.x>=690:
        scoreA+=1
        ball.velocity[0] = -ball.velocity[0]
    if ball.rect.x<=0:
        scoreB+=1
        ball.velocity[0] = -ball.velocity[0]
    if ball.rect.y>490:
        ball.velocity[1] = -ball.velocity[1]
    if ball.rect.y<0:
        ball.velocity[1] = -ball.velocity[1]  

    if pygame.sprite.collide_mask(ball, paddle2):
        ball.bounce()

    screen.fill(black)

    sprites_list.draw(screen) 

    #Scores displayed:
    font = pygame.font.Font(None, 74)
    font2 = pygame.font.Font(None, 55)
    """
    text = font.render(str(scoreA), 1, white)
    screen.blit(text, (250,10))
    """
    text = font.render(str(scoreB), 1, white)
    screen.blit(text, (430,10))
    text = font.render(str("Score: "), 1 ,white)
    screen.blit(text, (250, 10))
    text = font2.render(str("Keep The Ball Bouncing"), 1, white)
    screen.blit(text, (155,60))

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

pygame.quit()

Ответы [ 2 ]

2 голосов
/ 04 мая 2020

Вы можете использовать переменную state = 'INTRO'/'GAME'/'GAMEOVER' или отдельные переменные is_intro = True/False, is_game = True/False, is_gameover = True/False, is_pause = True/False, чтобы управлять тем, какой код выполняется в основном l oop

Это также потребует функции reset_all_values, которые используют global для сброса внешних / глобальных значений.

Примерно так.

import pygame

def reset_all_values():
    global scoreA
    global scoreB

    scoreA = 0
    scoreB = 0

    # reset other values

# --- main ---

size = (700, 500)

pygame.init()
screen = pygame.display.set_mode(size)

clock = pygame.time.Clock()

font = pygame.font.Font(None, 50)

reset_all_values()

# -------- Main Program Loop -----------

state = 'INTRO'

carry_on = True

while carry_on:

    # --- events ---

    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            carryOn = False 
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_x: 
                carry_on = False

            if state == 'INTRO':
                if event.key == pygame.K_ESCAPE:                    
                    state = 'GAME'
                    reset_all_values() # 
                # other keys for intro
            elif state == 'GAME':
                if event.key == pygame.K_ESCAPE: 
                    state = 'GAMEOVER'
                # other keys for game
            elif state == 'GAMEOVER':
                if event.key == pygame.K_ESCAPE: 
                    state = 'INTRO'
                    #reset_all_values() # TODO
                # other keys for gameover


    # --- changes/moves/collisions ---

    if state == 'INTRO':
        pass
    elif state == 'GAME':
        scoreA += 1
        if scoreA >= 100:
            state = 'GAMEOVER'
    elif state == 'GAMEOVER':
        pass

    # --- draws ---

    screen.fill((0,0,0))

    if state == 'INTRO':
        text = font.render('INTRO - Press ESC', True, (255,255,255))
        rect = text.get_rect(center=screen.get_rect().center)
        screen.blit(text, rect)
    elif state == 'GAME':
        text = font.render('GAME - Wait for Score 100', True, (255,255,255))
        rect = text.get_rect(center=screen.get_rect().center)
        screen.blit(text, rect)
        text = font.render(f'SCORE {scoreA}' , True, (255,255,255))
        rect = text.get_rect()
        screen.blit(text, rect)
    elif state == 'GAMEOVER':
        text = font.render('GAMEOVER - Press ESC', True, (255,255,255))
        rect = text.get_rect(center=screen.get_rect().center)
        screen.blit(text, rect)
        text = font.render(f'SCORE {scoreA}' , True, (255,255,255))
        rect = text.get_rect()
        screen.blit(text, rect)

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

pygame.quit()

Вы также можете поместить код в такие функции, как intro_event_handle(), intro_change(), intro_draw() и др. 1039 *. чтобы сделать его более читабельным.

import pygame


def intro_handle_event(event):
    global state

    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_ESCAPE:                    
            state = 'GAME'
            reset_all_values() # 
        # other keys for intro

def game_handle_event(event):
    global state

    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_ESCAPE: 
            state = 'GAMEOVER'
        # other keys for game

def gameover_handle_event(event):
    global state

    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_ESCAPE: 
            state = 'INTRO'
        # other keys for gameover

def intro_change():
    pass

def game_change():    
    global state
    global scoreA

    scoreA += 1
    if scoreA >= 100:
        state = 'GAMEOVER'

def gameover_change():
    pass

def intro_draw(screen):
    text = font.render('INTRO - Press ESC', True, (255,255,255))
    rect = text.get_rect(center=screen.get_rect().center)
    screen.blit(text, rect)

def game_draw(screen):
    text = font.render('GAME - Wait for SCORE 100', True, (255,255,255))
    rect = text.get_rect(center=screen.get_rect().center)
    screen.blit(text, rect)
    text = font.render(f'SCORE {scoreA}' , True, (255,255,255))
    rect = text.get_rect()
    screen.blit(text, rect)

def gameover_draw(screen):
    text = font.render('GAMEOVER - Press ESC', True, (255,255,255))
    rect = text.get_rect(center=screen.get_rect().center)
    screen.blit(text, rect)
    text = font.render(f'SCORE {scoreA}' , True, (255,255,255))
    rect = text.get_rect()
    screen.blit(text, rect)

def reset_all_values():
    global scoreA
    global scoreB

    scoreA = 0
    scoreB = 0

    # reset other values

# --- main ---

size = (700, 500)

pygame.init()
screen = pygame.display.set_mode(size)

clock = pygame.time.Clock()

font = pygame.font.Font(None, 50)

reset_all_values()

# -------- Main Program Loop -----------

state = 'INTRO'

carry_on = True

while carry_on:

    # --- events ---

    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            carryOn = False 
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_x: 
                carry_on = False

        if state == 'INTRO':
            intro_handle_event(event)
        elif state == 'GAME':
            game_handle_event(event)
        elif state == 'GAMEOVER':
            gameover_handle_event(event)

    # --- changes/moves/collisions ---

    if state == 'INTRO':
        intro_change()
    elif state == 'GAME':
        game_change()
    elif state == 'GAMEOVER':
        gameover_change()

    # --- draws ---

    screen.fill((0,0,0))

    if state == 'INTRO':
        intro_draw(screen)
    elif state == 'GAME':
        game_draw(screen)
    elif state == 'GAMEOVER':
        gameover_draw(screen)

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

pygame.quit()

Вы можете хранить функции в словаре

handle_event = {
   'INTRO': intro_handle_event,
   'GAME': game_handle_event,
   'GAMEOVER': gameover_handle_event,
}

и использовать только state (вместо if/elif) для выполнения правильной функции.

handle_event[state](event) 

import pygame


def intro_handle_event(event):
    global state

    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_ESCAPE:                    
            state = 'GAME'
            reset_all_values() # 
        # other keys for intro

def game_handle_event(event):
    global state

    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_ESCAPE: 
            state = 'GAMEOVER'
        # other keys for game

def gameover_handle_event(event):
    global state

    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_ESCAPE: 
            state = 'INTRO'
        # other keys for gameover

def intro_change():
    pass

def game_change():    
    global state
    global scoreA

    scoreA += 1
    if scoreA >= 100:
        state = 'GAMEOVER'

def gameover_change():
    pass

def intro_draw(screen):
    text = font.render('INTRO - Press ESC', True, (255,255,255))
    rect = text.get_rect(center=screen.get_rect().center)
    screen.blit(text, rect)

def game_draw(screen):
    text = font.render('GAME - Wait for SCORE 100', True, (255,255,255))
    rect = text.get_rect(center=screen.get_rect().center)
    screen.blit(text, rect)
    text = font.render(f'SCORE {scoreA}' , True, (255,255,255))
    rect = text.get_rect()
    screen.blit(text, rect)

def gameover_draw(screen):
    text = font.render('GAMEOVER - Press ESC', True, (255,255,255))
    rect = text.get_rect(center=screen.get_rect().center)
    screen.blit(text, rect)
    text = font.render(f'SCORE {scoreA}' , True, (255,255,255))
    rect = text.get_rect()
    screen.blit(text, rect)

def reset_all_values():
    global scoreA
    global scoreB

    scoreA = 0
    scoreB = 0

    # reset other values

# --- main ---

size = (700, 500)

pygame.init()
screen = pygame.display.set_mode(size)

clock = pygame.time.Clock()

font = pygame.font.Font(None, 50)

reset_all_values()

handle_event = {
   'INTRO': intro_handle_event,
   'GAME': game_handle_event,
   'GAMEOVER': gameover_handle_event,
}

change = {
   'INTRO': intro_change,
   'GAME': game_change,
   'GAMEOVER': gameover_change,
}

draw = {
   'INTRO': intro_draw,
   'GAME': game_draw,
   'GAMEOVER': gameover_draw,
}

# -------- Main Program Loop -----------

state = 'INTRO'

carry_on = True

    while carry_on:

        # --- events ---

        for event in pygame.event.get(): 
            if event.type == pygame.QUIT: 
                carryOn = False 
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_x: 
                    carry_on = False

            handle_event[state](event)

        # --- changes/moves/collisions ---

        change[state]()

        # --- draws ---

        screen.fill((0,0,0))

        draw[state](screen)

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

    pygame.quit()

In similar way you can keep it in classes.

import pygame

class Intro():

    def __inti__(self):
        self.reset()

    def reset(self):
        pass

    def handle_event(self, event):
        global state

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:                    
                state = 'GAME'
                scene[state].reset() 
            # other keys for intro

    def change(self):
        pass

    def draw(self, screen):
        text = font.render('INTRO - Press ESC', True, (255,255,255))
        rect = text.get_rect(center=screen.get_rect().center)
        screen.blit(text, rect)

class Game():

    def __inti__(self):
        self.reset()

    def reset(self):
        global scoreA
        global scoreB

        scoreA = 0
        scoreB = 0

        # reset other values

    def handle_event(self, event):
        global state

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE: 
                state = 'GAMEOVER'
                scene[state].reset()
            # other keys for game

    def change(self):    
        global state
        global scoreA

        scoreA += 1
        if scoreA >= 100:
            state = 'GAMEOVER'
            scene[state].reset()

    def draw(self, screen):
        text = font.render('GAME - Wait for SCORE 100', True, (255,255,255))
        rect = text.get_rect(center=screen.get_rect().center)
        screen.blit(text, rect)
        text = font.render(f'SCORE {scoreA}' , True, (255,255,255))
        rect = text.get_rect()
        screen.blit(text, rect)


class GameOver():

    def __inti__(self):
        self.reset()

    def reset(self):
        pass

    def handle_event(self, event):
        global state

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE: 
                state = 'INTRO'
                scene[state].reset()
            # other keys for gameover

    def change(self):
        pass

    def draw(self, screen):
        text = font.render('GAMEOVER - Press ESC', True, (255,255,255))
        rect = text.get_rect(center=screen.get_rect().center)
        screen.blit(text, rect)
        text = font.render(f'SCORE {scoreA}' , True, (255,255,255))
        rect = text.get_rect()
        screen.blit(text, rect)

# --- main ---

size = (700, 500)

pygame.init()
screen = pygame.display.set_mode(size)

clock = pygame.time.Clock()

font = pygame.font.Font(None, 50)

scene = {
   'INTRO': Intro(),
   'GAME': Game(),
   'GAMEOVER': GameOver(),
}

# -------- Main Program Loop -----------

state = 'INTRO'

carry_on = True

while carry_on:

    # --- events ---

    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            carryOn = False 
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_x: 
                carry_on = False

        scene[state].handle_event(event)

    # --- changes/moves/collisions ---

    scene[state].change()

    # --- draws ---

    screen.fill((0,0,0))

    scene[state].draw(screen)

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

pygame.quit()

Таким образом, вы строите Finite State Machine


Другим методом может быть создание отдельных циклов для каждого состояния и помещение его во внешний l oop, который запустит выбранное l oop или выйдет из игры.

import pygame

def intro_loop(screen):

    print('start intro loop')

    carry_on = True
    next_state = None

    while carry_on and not next_state:

        # --- events ---

        for event in pygame.event.get(): 
            if event.type == pygame.QUIT: 
                carry_on = False 
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_x: 
                    carry_on = False

                if event.key == pygame.K_ESCAPE:                    
                    next_state = 'GAME'

        # --- changes/moves/collisions ---


        # --- draws ---

        screen.fill((0,0,0))

        text = font.render('INTRO - Press ESC', True, (255,255,255))
        rect = text.get_rect(center=screen.get_rect().center)
        screen.blit(text, rect)

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

    return carry_on, next_state 

def game_loop(screen):
    global scoreA
    global scoreB

    scoreA = 0
    scoreB = 0

    # reset other values

    print('start game loop')

    carry_on = True
    next_state = None

    while carry_on and not next_state:

        # --- events ---

        for event in pygame.event.get(): 
            if event.type == pygame.QUIT: 
                carry_on = False 
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_x: 
                    carry_on = False

                if event.key == pygame.K_ESCAPE: 
                    next_state = 'GAMEOVER'

        # --- changes/moves/collisions ---

        scoreA += 1
        if scoreA >= 100:
            next_state = 'GAMEOVER'

        # --- draws ---

        screen.fill((0,0,0))

        text = font.render('GAME - Wait for SCORE 100', True, (255,255,255))
        rect = text.get_rect(center=screen.get_rect().center)
        screen.blit(text, rect)
        text = font.render(f'SCORE {scoreA}' , True, (255,255,255))
        rect = text.get_rect()
        screen.blit(text, rect)

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

    return carry_on, next_state 

def gameover_loop(screen):

    print('start gameover loop')

    carry_on = True
    next_state = None

    while carry_on and not next_state:

        # --- events ---

        for event in pygame.event.get(): 
            if event.type == pygame.QUIT: 
                carry_on = False 
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_x: 
                    carry_on = False

                if event.key == pygame.K_ESCAPE:                    
                    next_state = 'INTRO'

        # --- changes/moves/collisions ---


        # --- draws ---

        screen.fill((0,0,0))

        text = font.render('GAMEOVER - Press ESC', True, (255,255,255))
        rect = text.get_rect(center=screen.get_rect().center)
        screen.blit(text, rect)
        text = font.render(f'SCORE {scoreA}' , True, (255,255,255))
        rect = text.get_rect()
        screen.blit(text, rect)

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

    return carry_on, next_state 

# --- main ---

size = (700, 500)

pygame.init()
screen = pygame.display.set_mode(size)

clock = pygame.time.Clock()

font = pygame.font.Font(None, 50)

# -------- Main Program Loop -----------

state = 'INTRO'
carry_on = True

while carry_on:

    if state == 'INTRO':
        carry_on, state = intro_loop(screen)
    elif state == 'GAME':
        carry_on, state = game_loop(screen)
    elif state == 'GAMEOVER':
        carry_on, state = gameover_loop(screen)

pygame.quit()
1 голос
/ 04 мая 2020

Исходя из того, как вы это сформулировали, я полагаю, что ваша проблема в перезапуске игры, а не в игре за экраном, которая задает вопрос. Предполагая, что это так ...

Я не согласен с подходом к попытке объединить разные состояния в одну игру l oop. Это, конечно, можно сделать, но в этом сценарии нет веской причины. Это усложняет выполнение кода без какой-либо выгоды от его структурирования. Есть ситуации, когда подход с использованием конечного автомата имеет смысл, но на самом деле это не один из них.

Добавление дополнительного l oop с вопросом о перезапуске игры может быть решено намного проще, чем это. Возьмите код от

carryOn = True

до

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

за исключением строки:

clock = pygame.time.Clock()

и переместите все это в метод, называемый чем-то вроде run_game()

Вам также необходимо переместить строки, которые инициализируют положения весла и мяча, и user_lose = False и переместить это в начало метода run_game().

Затем, когда вы хочу запустить игру, которую ты так называешь. После его выхода вы можете спросить, хотят ли они снова играть, и позвонить снова, если они это сделают, или выйти, если они решили не играть. Вам понадобится это в al oop, конечно, чтобы повторить это более одного раза.

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