Related
This question already has answers here:
How to get keyboard input in pygame?
(11 answers)
Closed last year.
I'm working on a program for school and am required to use a pygame window to display cumulative totals for my program (it's for ordering coffee). Here is what the code looks like for the part where the window opens:
if totalconf == 'y':
# if user wishes to view cumulative totals
pygame.init()
background_colour = (231,247,146)
(width, height) = (1500, 900)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Running Totals')
# initialise new window with yellow background and title
myFont = pygame.font.SysFont("arial", 40)
myFont2 = pygame.font.SysFont("arial", 20)
# initialise small and large fonts
text = myFont.render("In store totals:", True, (0, 0, 0))
text3 = myFont.render("Takeaway totals:", True, (0, 0, 0))
text4 = myFont.render("In store earnings:", True, (0, 0, 0))
text5 = myFont.render("Takeaway earnings:", True, (0, 0, 0))
text6 = myFont.render(f"Total discounts: ${total_discounts}", True, (0, 0, 0))
text7 = myFont.render(f"Total gst: ${total_gst}", True, (0, 0, 0))
text8 = myFont.render(f"Total surcharges: ${total_takeawaycharges}", True, (0, 0, 0))
# initialise headings and totals to display on screen
screen.fill(background_colour)
# fill screen with background color
pygame.display.flip()
# update screen
running = True
# run window
while running:
# while window is running
screen.blit(text, (20, 20))
screen.blit(text3, (300, 20))
screen.blit(text4, (600, 20))
screen.blit(text5, (900, 20))
screen.blit(text6, (20, 700))
screen.blit(text7, (20, 740))
screen.blit(text8, (20, 780))
# project all text onto screen
pygame.display.update()
# update screen
initial = 70
# set initial as 70 down
for item, values in totalsdict.items():
# for values stored in totals dict
text2 = myFont2.render(f'{item.title()}: {values[0]}', True, (0,0,0))
# print out item and equivalent total in small font
screen.blit(text2, (20, initial))
# display text on screen
pygame.display.update()
# update screen
initial += 40
# increase inital by 40 so values print vertically down
initial = 70
# set initial as 70 down
for item, values in totalsdict.items():
# for values stored in totals dict
text2 = myFont2.render(f'{item.title()}: {values[1]}', True, (0,0,0))
# print out item and equivalent total in small font
screen.blit(text2, (300, initial))
# display text on screen
pygame.display.update()
# update screen
initial += 40
# increase inital by 40 so values print vertically down
initial = 70
# set initial as 70 down
for item, values in totalsdict.items():
# for values stored in totals dict
text2 = myFont2.render(f'{item.title()}: {values[2]}', True, (0,0,0))
# print out item and equivalent total in small font
screen.blit(text2, (600, initial))
# display text on screen
pygame.display.update()
# update screen
initial += 40
# increase inital by 40 so values print vertically down
initial = 70
# set initial as 70 down
for item, values in totalsdict.items():
# for values stored in totals dict
text2 = myFont2.render(f'{item.title()}: {values[3]}', True, (0,0,0))
# print out item and equivalent total in small font
screen.blit(text2, (900, initial))
# display text on screen
pygame.display.update()
# update screen
initial += 40
# increase inital by 40 so values print vertically down
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if running == False:
pygame.quit()
# code to stop running if 'X' is pressed
If the user wants to see the cumulative totals, they input 'y' for totalconf. This bit of code sits in a continuous while loop which takes orders until a blank is entered. The first time the program runs this works great and opens and closes without stopping the program. However, the second time, if I wish to see the updated cumulative totals and open the pygame window, I get a message which says "Backend terminated or disconnected.Windows fatal exception: access violation". This is a really long program but I hope the information I have given is enough.
So in summary, I need to be able to open and close the window every time the loop runs without getting the message above.
Use the keyboard event:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_x:
running = False
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action.
This question already has answers here:
How can I create a text input box with Pygame?
(5 answers)
Why is my pygame display not responding while waiting for input?
(1 answer)
Closed 1 year ago.
I am new to python programming and am trying to create a game for class. Every time I run the program, before the user gets to put input in the surface screen goes non responsive. What am I doing wrong?
#import modules needed
import pygame, sys, time, random
from pygame.locals import *
def main():
#Assigns Colors
ORANGE = (255, 127, 80) #Background
BLACK = (0, 0, 0 ) #Mountains
WHITE = (255,255,255) #Snow & Trees
BROWN = (61, 16, 16) #moose & Mountains
GREEN = (0, 153, 0) #Trees
L_BROWN=(181, 101, 29) #Tree Trunks
YELLOW =(255, 255, 204) #Sky
BLUE = (67, 111, 181) #Lake
LIME = (57, 255, 20)
#initiate modules
pygame.init()
done=False
#assign screen values and display captions
screen = pygame.display.set_mode((1000,600))
pygame.display.set_caption("Welcome To Michelle Era's Final Project - Moose Scene")
#start clock
clock=pygame.time.Clock()
fps = (60)
#Assign Variables
drink = " "
name = " "
welcome = " "
water= " "
quit = " "
i = 0
Moose_img = pygame.image.load('moose.png')
Beer_img = pygame.image.load('beer.png')
mikey_img=pygame.image.load('Mikey.jpg')
Water_img = pygame.image.load('water.png')
font = pygame.font.SysFont('Calibri',25,False,False)
text=font.render("My text", True, YELLOW)
player_num = 0
moose_num = random.randrange(1,26)
while not done:
pygame.event.pump()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(ORANGE) #fills background orange
#Draw Scene
def draw_mountains(screen, x,y):
pygame.draw.rect(screen, BLACK,(1,200,1000,100)) # Base of mountain
x_offset=0
while x_offset<1000:
pygame.draw.polygon(screen, WHITE, [[100+x_offset,100], [0+x_offset ,225], [200+x_offset, 225]], 0) # snow caps on mountain
pygame.draw.polygon(screen, BROWN, [[100+x_offset,120], [0+x_offset ,225], [200+x_offset, 230]], 0)
x_offset=x_offset+120#tells how many pixels to move over until you reached 1000
def draw_trees(screen, x,y):
x_offset=0
while x_offset<1000:
pygame.draw.ellipse(screen, GREEN, [27+x_offset,158,40,50], 0) #draws leaves starting at x27 to x 1000 every 50 pixels
x_offset=x_offset +50 #tells how many pixels to move over until you reached 1000
pygame.draw.line(screen,L_BROWN,[x_offset,200],[x_offset +10,250],8) #draws trunk starting at x0 to x 1000 every 50 pixels
pygame.draw.line(screen,WHITE,[x_offset,207],[x_offset +10,250],1) #draws snow starting at x0 to x 1000 every 50 pixels
x_offset=x_offset +50
def draw_lake(screen, x,y):
pygame.draw.rect(screen,BLUE, [0,300,1000,200],0)# draws the lake
pygame.draw.rect(screen,L_BROWN,[0,500,1000,100],0) #draws grass
def gameover():
screen.fill(BLACK) #fills play surface
pygame.display.flip() #updates the display
gameOverFont=pygame.font.Font('freesansbold.ttf',17)
gameOversurf = gameOverFont.render("A Big thank you to my brother Michael Era who originally painted the mural that was the inspiration for this project",True, YELLOW)
gameOverRect = gameOversurf.get_rect()
gameOverRect.midtop = (500,40)
screen.blit(gameOversurf, gameOverRect)
screen.blit(mikey_img, (200,100))
pygame.display.flip()
time.sleep(30)
draw_mountains(screen, 0,0)
draw_trees(screen,0,0)
draw_lake(screen,300,400)
screen.blit(Moose_img, (600,400))
welcome = font.render("WELCOME TO MOOSEVILLE", True, YELLOW)
screen.blit(welcome, [300,50])
pygame.display.update()
#
#GET user input
name=(input('What is your Moose named ? '))
name=font.render("I like The Name " + str(name), True, YELLOW)
draw_mountains(screen, 0,0)
draw_trees(screen,0,0)
draw_lake(screen,300,400)
screen.blit(Moose_img, (600,400))
screen.blit(name, (550, 355))
pygame.display.update()
num_game=font.render("I am thinking of a number between 1 and 25, can you guess it? ", True, LIME)
screen.blit(num_game,(25,325))
player_num=(input(" What is your guess 1 to 10: "))
player_num = font.render('You Choose The Number: ' +str(player_num), True, LIME)
screen.blit(player_num,(25,350))
pygame.display.update()
moose_num = random.randrange(1,11)
moose_num=font.render('My number choice was : ' + str(moose_num), True, LIME)
screen.blit(moose_num,(25,376))
pygame.display.update()
if player_num == moose_num:
won=font.render('You Won!!!', True, YELLOW)
screen.blit(won,(25,400))
pygame.display.update()
else:
lose=font.render('You Lose!' , True, YELLOW)
screen.blit(lose,(25,400))
pygame.display.update()
quit = input('Do you want to try again? y or n ')
if quit == "n":
gameover()
else:
done=False
pygame.quit()
main()
Firstly, you don't need both event.pump() and event.get(), just use event.get in the loop as now. Also, you don't usually define functions inside a while loop. They would be outside the loop and called from inside it. You are also calling both event.pump and event.get and getting input via "input."
You also call pygame.quit() inside the while loop. Break this up into a bunch of functions.
main() - this calls all the others
get_input()
draw_screen()
etc
Also the numbers game says:
num_game=font.render("I am thinking of a number between 1 and 25, can you guess it? "
and then asks for:
player_num=(input(" What is your guess 1 to 10: "))
You cannot use input in the application loop. input waits for an input. While the system is waiting for input, the application loop will halt and the game will not respond. Use the KEYDOWN event instead of input:
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
# [...]
Either implement a textbox (see How to create a text input box with pygame?)
or get the input in a separate thread (see Why is my display not responding while waiting for input?).
I want to show a text on the screen when a variable changes to True. The Text "Game Over" is show for a very short period of time with this code but I disappears after less than one second.
import pygame
import random
import time
import math
# Initialize pygame
pygame.init()
# Create window (width, height)
screen1 = pygame.display.set_mode(((800, 600)))
ScreenHeight = screen1.get_height()
ScreenWidth = screen1.get_width()
#Game Over text
go_font = pygame.font.Font('freesansbold.ttf', 128)
go_text = "GAME OVER"
go_textX = 300
go_textY = 300
def show_gameover(go_textX, go_textY):
gameover_text = font.render(go_text, True, (105, 105, 105))
screen1.blit(gameover_text, (go_textY,go_textY))
# Variable to track gameover
gameover = False
while running:
if gameover:
show_gameover(go_textX, go_textY)
# Insert Background
screen1.blit(background, (0, 0))
i = 0
for obs in obstacle_list:
obs.spawn_obstacle()
obs.update_y()
outOfBounds = obs.out_of_bounds(playerX, playerY)
if outOfBounds:
obstacle_list.pop(i)
collision = obs.collision_detection(playerX, playerY)
if collision:
gameover = True
show_gameover(go_textX, go_textY) #Show Gameover-text
i += 1
# Update after each iteration of the while-loop
pygame.display.update()
You have to draw the text after the background. If you draw the text before drawing the background, it will be hidden from the background. Draw it just before updating the display. So it is drawn over all other objects in the scene.
while running:
# Insert Background
screen1.blit(background, (0, 0))
# [...]
if gameover:
show_gameover(go_textX, go_textY)
# Update after each iteration of the while-loop
pygame.display.update()
At the request of Furas, below are the segments of code in a Pygame Project that I'm currently working on. What I'm trying to get to happen is essentially like clearing everything visible on the previous window so I can start fresh with a new UI. When the code is run, and the "Start Game" button is pressed on the startup screen, the background colour updates, but everything that was previously rendered (the title and all of the buttons) remain on the screen. If anyone could offer any general pointers - or advice based off the code below - that would a great help!
The game_loop function:
This first part is where I need the screen to be cleared/updated. The game_loop contains more game logic, which is irrelevant to the current question, and what is pasted below is the only part of the function that interacts with the window.
new_surface = pygame.Surface((1,1))
def game_loop():
global clicked_game
global game_running
clicked_game = True
game_running = True
if clicked_game == True:
screen.fill( (0,0,0) )
screen.blit(new_surface, (0,0))
pygame.display.update()
User Interface Initialisation and Functions:
These are the rest of the functions which follow later on from the actual game logic in game_loop:
def quit_game():
pygame.quit()
quit()
def update_options():
global clicked_options
clicked_options = True
def button(window, msg, x_coord, y_coord, width, height, initial_colour, highlight_colour, button_action):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x_coord + width > mouse[0] > x_coord and y_coord + height > mouse[1] > y_coord:
pygame.draw.rect(window, highlight_colour, (x_coord, y_coord, width, height))
if click[0] == 1:
button_action()
else:
pygame.draw.rect(window, initial_colour, (x_coord, y_coord, width, height))
button_Text = pygame.font.Font("freesansbold.ttf",20)
text_Surf, text_Rect = text_objects(msg, button_Text)
text_Rect.center = ((x_coord + (width / 2)), (y_coord + (height / 2)))
window.blit(text_Surf, text_Rect)
while play:
for event in pygame.event.get():
if event.type == pygame.QUIT:
play = False
button(screen, "Start Game", 231, 236, 250, 50, e_m_light, e_m_lighter, game_loop)
button(screen, "Options", 231, 336, 250, 50, e_m_light, e_m_lighter, update_options)
button(screen, "Exit", 231, 436, 250, 50, e_m_light, e_m_lighter, quit_game)
if clicked_options == True:
#update title colour for testing purposes
text_Surface = Font1.render('BlackJack Blast!', True, e_m_lighter)
else:
text_Surface = Font1.render('BlackJack Blast!', True, white)
screen.blit(textSurface,(106,100))
pygame.display.update()
Screenshots of the UI before and after pressing "Start Game":
User Interface - Before
User Interface - After
I'm still a bit of a pygame novice, so if you're unsure of how to fix this specific problem, but recognise something else that could do with improving, or if you need any more information to develop a solution, please let me know!
You blit all buttons all the times - in every loop - so why the shoud disaper ?
You can use variables like display_menu = True, display_game = True, display_options = False to control what elements display - silimiar to clicked_options.
But cleaner is to create separated while True loop for every scene - Menu, Game, Option.
You can use functions like in example: https://stackoverflow.com/a/47460947/1832058
It uses front_page(), menu() to run different while True loops for two different scenes.
Or you can create classes for differnt scenes/stages: stage-example
You can see this on image:
I'm new to pygame and currently I'm working on creating a memory game where the computer displays boxes at random positions for like a second and then the user has to click on where he/she thinks those boxes are. It's kind of like this game:
However I'm not really sure how to make the computer display the boxes with like a letter or symbol e.g. 'T' or '%'. (I've already made the grid).
Could anyone please help? It would be really appreciated.
import pygame
size=[500,500]
pygame.init()
screen=pygame.display.set_mode(size)
# Colours
LIME = (0,255,0)
RED = (255, 0, 0)
BLACK = (0,0,0)
PINK = (255,102,178)
SALMON = (255,192,203)
WHITE = (255,255,255)
LIGHT_PINK = (255, 181, 197)
SKY_BLUE = (176, 226, 255)
screen.fill(BLACK)
# Width and Height of game box
width=50
height=50
# Margin between each cell
margin = 5
# Create a 2 dimensional array. A two dimesional
# array is simply a list of lists.
grid=[]
for row in range(20):
# Add an empty array that will hold each cell
# in this row
grid.append([])
for column in range(20):
grid[row].append(0) # Append a cell
# Set row 1, cell 5 to one. (Remember rows and
# column numbers start at zero.)
grid[1][5] = 1
# Set title of screen
pygame.display.set_caption("Spatial Recall")
#Loop until the user clicks the close button.
done=False
# Used to manage how fast the screen updates
clock=pygame.time.Clock()
# -------- Main Program Loop -----------
while done==False:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done=True # Flag that we are done so we exit this loop
if event.type == pygame.MOUSEBUTTONDOWN:
# User clicks the mouse. Get the position
pos = pygame.mouse.get_pos()
# Change the x/y screen coordinates to grid coordinates
column=pos[0] // (width+margin)
row=pos[1] // (height+margin)
# Sete t hat location to zero
grid[row][column]=1
print("Click ",pos,"Grid coordinates: ",row,column)
# Draw the grid
for row in range(10):
for column in range(10):
color = LIGHT_PINK
if grid[row][column] == 1:
color = RED
pygame.draw.rect(screen,color,[(margin+width)*column+margin,(margin+height)*row+margin,width,height])
# Limit to 20 frames per second
clock.tick(20)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
pygame.quit ()
In order to display text, you have to go through a series of steps. First you will want to get a font by using the command `pygame.font.Font(font name, size). For example:
arialfont=pygame.font.Font('arial', 12)
All available fonts can be gotten from the command pygame.font.get_fonts(). Remember to initialize pygame (pygame.init()) before any of this.
Next, you will have to use the Font.render(text, antialias, color, background=None). For example:
text=arialfont.render('Hello World!', True, (0, 0, 0))
This will return a surface. You can use it just like you would any other surface. Use text.get_rect() to get its rect, then reposition the rect to put it where you want it to be, and blit it to the window. If you don't know anything about surface objects, just ask me.
Here is a working code.
import pygame, sys
pygame.init()#never forget this line
window=pygame.display.set_mode((100, 100))
font=pygame.font.SysFont('arial', 40)
text=font.render('#', True, (0, 0, 0))
rect=text.get_rect()
window.fill((255, 255, 255))
window.blit(text, rect)
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
sys.exit()