简体   繁体   English

使用 Pygame 的游戏结束屏幕

[英]Game Over Screen using Pygame

I am trying to finish up a version of pong and I want the game to end when the player misses the ball and it hits the wall behind the paddle.我正在尝试完成一个版本的乒乓球,我希望当球员错过球并击中球拍后面的墙壁时比赛结束。 I have been trying to build a Game Over screen for this and have had no luck.我一直在尝试为此构建一个 Game Over 屏幕,但没有运气。 I want the user to have an option to restart a new game or quit the screen all together.我希望用户可以选择重新开始新游戏或一起退出屏幕。

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

You can use variable state = 'INTRO'/'GAME'/'GAMEOVER' or separated variables is_intro = True/False , is_game = True/False , is_gameover = True/False , is_pause = True/False to control what code execute in main loop您可以使用变量state = 'INTRO'/'GAME'/'GAMEOVER'或分隔变量is_intro = True/False , is_game = True/False , is_gameover = True/False , is_pause = True/False来控制在 main 中执行的代码环形

It would need also function reset_all_values which use global to reset external/global values.它还需要使用global来重置外部/全局值的 function reset_all_values

Something like this.像这样的东西。

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

You can also put code in functions like intro_event_handle() , intro_change() , intro_draw() , etc. to make it more readable.您还可以将代码放入intro_event_handle()intro_change()intro_draw()等函数中,以使其更具可读性。

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

You may keep functions in dictionary您可以将函数保存在字典中

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

and use only state (instead of if/elif ) to execute correct function.并仅使用state (而不是if/elif )来执行正确的 function。

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

This way you build Finite State Machine这样您就可以构建有限的 State 机器


Other method can be create separated loops for every states and put it in external loop which will run selected loop or it will exit game.其他方法可以为每个状态创建单独的循环并将其放入将运行选定循环或退出游戏的外部循环。

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

I assume from the way you have phrased this that your problem is the rerunning of the game, not the game over screen that asks the question.我假设从您的表述方式来看,您的问题是游戏的重新运行,而不是提出问题的游戏结束屏幕。 Assuming that is the case...假设是这种情况...

I disagree with the approach of trying to combine different states into a single game loop.我不同意尝试将不同状态组合成一个游戏循环的方法。 It can certainly be done, but there is no real good reason to do it in this type of scenario.当然可以,但在这种情况下没有真正好的理由这样做。 It makes the code harder to follow without any benefit gained from structuring it that way.它使代码更难遵循,而不会从这种结构中获得任何好处。 There are situations where a state machine approach makes sense, but this really is not one of them.在某些情况下,state 机器方法是有意义的,但这确实不是其中之一。

Adding a an extra loop with a question about restarting the game can be handled much simpler than that.添加一个包含有关重新启动游戏的问题的额外循环可以比这简单得多。 Take the code from

carryOn = True

to

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

except for the line:除了这一行:

clock = pygame.time.Clock()

and move all of it into a method called something like run_game()并将所有这些移到一个名为run_game()的方法中

You would also need to move the lines that initialize the paddle and ball positions, and the user_lose = False and move that to the beginning of the run_game() method.您还需要移动初始化桨和球位置的线,以及user_lose = False并将其移动到run_game()方法的开头。

Then when you want to run the game you call that.然后,当您想运行游戏时,您可以调用它。 After it exits you can ask if they want to play again and call it again if they do, or exit if they chose not to.退出后,您可以询问他们是否要再次播放,如果他们愿意,请再次调用它,如果他们选择不这样做,则退出。 You would need that in a loop of course to repeat this more than once.当然,您需要在一个循环中多次重复此操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM