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 我想您的家庭作业并不严格允许使用它。您已经使用 done
和 finished
变量开始了这条道路。
我已经把 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 我想您的家庭作业并不严格允许使用它。您已经使用 done
和 finished
变量开始了这条道路。