Pygame 不允许我在 .update() 之后更改显示

Pygame not letting me change display after .update()

我已经把 pygame.display.update() 放在多个不同的地方,但出于某种原因,它绝对不允许我按下 H 键,所以它得到了帮助,其他一切正常。 这是为了我比以前更难的学校作业。我技术上已经完成了,我只是想制作一个主菜单,一切都很顺利,然后帮助屏幕就再也不想画了

import pygame 
import time
import random
import sys
import os

# ! Use print(event) for coordinate reading

# TODO: Add highscore file read and overwrite ✔️
# TODO: Add Game over message ✔️
# TODO: Show highscore and points of that run ✔️
# TODO: Fix Snake not being on same x,y as apple (Most likely wrong movement increments) ✔️
# TODO: Add GRID ✔️


# ? Find a better spawning logic ✔️
# ? Add menu instead of a simple string - NOE AV DET JÆVLIGSTE JEG HAR STARTET PÅ
# ? Fine tune resolution and size 
# ? Add a unique powerup with 3% spawn chance giving 5 points and 1 body length



# ! Pygame Initiatior 
pygame.init() # * Initiates pygame

# ! Screen resolution and title
sc_width = 400
sc_height = 400
screen = pygame.display.set_mode((sc_width, sc_height)) # * Sets pygame window 
pygame.display.set_caption('Snake') # * Sets window title to Snake

# ! Color Variables
bgcolor = (25, 51, 102) # * Dark blue for background color
yellow = (255, 255, 0) # * Yellow color for snake 
red = (255, 0, 0) # * Red color for points & game over
white = (255, 255, 255) # * White color for score

# ! FPS variable
clock = pygame.time.Clock() # * Used to set the FPS of the game using clock.tick(xyz)

# ! Font 
font = pygame.font.SysFont(None, 30) # * None = Default pygame font. 40 = size of font

# ! Game Over Draw function
def GameOver(msg, color): # * Function takes in a string and color and draws it on screen
    text = font.render(msg, True, color) # * Draws msg with font with True for anti aliasing (Smooth edges) with specified color when func is called
    screen.blit(text, [50, 100]) # * Draws text at 100x100

# ! Snake
snake_block = 10 

def Snake(snake_block, snakelist):
    for x in snakelist:
        pygame.draw.rect(screen, yellow, [x[0], x[1], snake_block, snake_block])


# ! Grid 
black = (0, 0, 0)
def Grid():
    size = 10 # * Sets grid size to 10 (same as snake)
    for x2 in range(0, sc_width, size): # * Gaps 10 in width
        for y2 in range(0, sc_height, size): # * Gaps height with 10
            drawGrid = pygame.Rect(x2, y2, size, size) # * Makes a grid
            pygame.draw.rect(screen, black, drawGrid, 1) # * Draws it onto the screen

# ! Draw Score
def drawScore(score):
    points = font.render('Score: ' + str(score), True, white) 
    screen.blit(points, [0, 0]) # * Draws it top left

# ! Make highscore txt
try:
    f = open("highscore.txt", 'x') # * Creates file if it doesnt exist
    f.write('0')  # * No highscore set
    f.close()  # * Closes file to let other codes down the line rewrite the file
except FileExistsError: # * If exist continue to rest of code using it as the "highscore" file
    pass



# ! Draw Highscore
f = open('highscore.txt', 'r') # * Opens as read 
highscore = int(f.readline())
f.close()
def drawHighscore(highscore):
    hc = font.render('Score: ' + str(highscore), True, white) 
    screen.blit(hc, [310, 0]) # * Draws it top right


# # ! Draw PRE GAME Screen
# def drawMenu(menu, color):
#     pregame = font.render(menu, True, white) 
#     screen.blit(pregame, [50, 100])




# ! Multiline draw function (Whosebug) / PRE GAME
def drawMenu(menu, x, y, fsize):
    lines = menu.splitlines()
    for i, l in enumerate(lines):
        screen.blit(font.render(l, 0, white), (x, y + fsize*i))



# ! Draw Help screen
def drawHelp(x, y, fsize):
    help = "Controls: [W][A][S][D]\nInstructions: \nUse WASD to control the snake.\nGrab as many apples as you can;\nand dont crash into yourself :)\n\n [ (B) A C K ]"
    hlp = help.splitlines()
    for i, l in enumerate(hlp):
        screen.blit(font.render(l, 0, white), (x, y + fsize*i)) 



def mainMenu():
    menu = "[ (S) T A R T ]\n [ (H) E L P ]\n [ (Q) U I T ]\n jeg er best"
    screen.fill(bgcolor)
    drawMenu(menu, 140, 120, 80)
    for event in pygame.event.get(): # * Gathers inputs
        if event.type == pygame.KEYDOWN: # * Checks key presses
            if event.key == pygame.K_q: # * If Q is pressed
                pygame.quit()
                sys.exit()
            elif event.key == pygame.K_s: # * Calls game loop again
                game()
            elif event.key == pygame.K_h:
                screen.fill(bgcolor)
                drawHelp(25, 70, 40)




# ! Game Loop
def game():
    finished = False
    done = False

    # ! Spawn location of snake
    x = sc_width / 2 # * Spawns snake at screen width / 2
    x_move = 0 # * To update x coordinates as the snake moves
    y = sc_height / 2 # * Spawns snake at screen height / 2
    y_move = 0 # * To update y coordinates as the snake moves
    score = 0


    f = open('highscore.txt', 'r') # * Opens as read 
    highscore = int(f.readline())
    f.close()

    
    snakelist = []
    snake_len = 1

    # ! Randomizing apple spawn locations
    apple_x = round(random.randrange(0, sc_width - 10) / 10.0) * 10.0
    apple_y = round(random.randrange(0, sc_height - 10) / 10.0) * 10.0


    while not finished:
        while done == True:
            screen.fill(bgcolor)
            drawScore(snake_len - 1)
            drawHighscore(highscore)
            mainMenu()


        # ! Movement input logic
        for event in pygame.event.get(): # * Gathers inputs
            if event.type == pygame.QUIT: # * If pygame.quit gets called (clicking X on window) it will set finished to True which will end game loop
                finished = True # * Ends game loop
                sys.exit()
            if event.type == pygame.KEYDOWN: # * Checks if a key is pressed down
                if event.key == pygame.K_d: # * If key 'D' is pressed increase x by 10 making it move right
                    x_move = 10 # * Speed it moves
                    y_move = 0 # * No vertical movement
                elif event.key == pygame.K_a: # * If key 'A' is pressed decrease x by -10 making it move left
                    x_move = -10 # * Speed it moves
                    y_move = 0 # * No vertical movement
                elif event.key == pygame.K_w: # * If key 'W' is pressed decrease y by -10 making it move up
                    x_move = 0 # * No horizontal movement
                    y_move = -10 # * Speed it moves
                elif event.key == pygame.K_s: # * If key 'S' is pressed increase y by 10 making it move down
                    x_move = 0 # * No horizontal movement
                    y_move = 10 # * Speed it moves

        # ! Out of bounds logic
        # * If snake is at a value higher than screen res or lower than 0; it means its outside the screen box, then the Game loop var will be True and game ends
        if x >= sc_width or x < 0 or y >= sc_height or y < 0: 
            done = True

        # ! Update movement
        x += x_move 
        y += y_move
        
        screen.fill(bgcolor)

        # ! Draw grid 
        Grid() # * Draws grid

        # ! Draw snake and apples
        pygame.draw.rect(screen, red, [apple_x, apple_y, 10, 10]) # * Draws apples on screen with red color and puts it at apple_x,y with size of 10
        pygame.draw.rect(screen, yellow, [x, y, 10, 10]) # * Draws snake on screen with yellow color and puts it at var x,y with a size of 10

        snakeH = [] 
        snakeH.append(x) # * Appends snake head x position
        snakeH.append(y) # * Appends snake head y position 
        snakelist.append(snakeH) # * Adds snake head to THE snake list
        if len(snakelist) > snake_len: # * If snake list is bigger than snake length
            del snakelist[0] # * Kills head

        for x1 in snakelist[:-1]:
            # ? Tried to understand this by using prints and seeing values: 
            # ? I'm guessing since it checks each block (prints show list with values with 10 seperating (size of block))
            # ? DOES NOT PRINT HEAD
            # ? If head hits one of the other boxes, it will overlap in list and head wont be skipped and it dies
            # ! print(snakelist[:-1]) (Bugtesting / code understanding)
            if x1 == snakeH:
                # ! print(snakelist[:-1]) (Bugtesting / code understanding)
                done = True

        Snake(snake_block, snakelist) # * Updates func with new values
        drawScore(snake_len - 1) # * - 1 because dont want to count head as a point
        drawHighscore(highscore)


        # ! Snake eating apple and growing
        if x == apple_x and y == apple_y: # * Checks if snake is at apple pos
            apple_x = round(random.randrange(0, sc_width - 10) / 10.0) * 10.0 # * Spawns new apple inside play area
            apple_y = round(random.randrange(0, sc_height - 10) / 10.0) * 10.0 # * Spawns new apple inside play area
            snake_len += 1 # * Increases snake length by 1
            score += 1 # * Increases score by 1
        
        # ! Saving highscore
        f = open("highscore.txt", 'r+') # * Opens Highscore
        highscore = int(f.readline()) # * Reads Highscore
        if highscore > score: # * If Highscore > score(that run)
            f.close() # * Close file
        else: # * But if score > highscore
            f.close # * Close it so it doesnt add to existing number ex: highscore: 5 score that run 6 = highscore: 56
            f = open("highscore.txt", 'w') # * Open as write so it writes a new number
            f.write(f'{score}') # * Write current score
            f.close() # * Close

        f = open('highscore.txt', 'r') # * Opens as read 
        highscore = int(f.readline())
        f.close() # * Close file


        # ! Setting FPS 
        clock.tick(30) # * Sets FPS to 30
         
        pygame.display.update()
    pygame.quit() # * Uninitializes pygame
    quit() # * Quits


while True:
    mainMenu()

我修改了你的drawHelp函数如下:

def drawHelp(x, y, fsize):
    help = "Controls: [W][A][S][D]\nInstructions: \nUse WASD to control the snake.\nGrab as many apples as you can;\nand dont crash into yourself :)\n\n [ (B) A C K ]"
    hlp = help.splitlines()
    for i, l in enumerate(hlp):
        screen.blit(font.render(l, 0, white), (x, y + fsize*i)) 
    pygame.display.update()
    # to stay in this function until the B key is pressed.
    b_pressed = False
    while not b_pressed:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_b: 
                    b_pressed = True

请注意,我还必须将 pygame.display.update() 添加到 drawMenu() 的末尾才能显示主菜单。

就是说,有几个问题使您更难扩展和调试您的代码。通常 pygame.display.update() 只应调用一次,理想情况下,事件也应在一个地方处理。事件处理程序最好修改游戏状态,例如将状态从 主菜单 更改为 帮助 。您的事件处理程序调用接管事件处理、绘图和更新的函数。为了在不重构代码的情况下实现您的结果,我遵循了类似的做法。

它可能会帮助您阅读有关状态机的内容,这是一个 answer that may help you, or a pygame example 我想您的家庭作业并不严格允许使用它。您已经使用 donefinished 变量开始了这条道路。