I'm currently learning pygame and writing a simple 2d game. I've come to the point when I need to introduce a start menu. The problem is though the startSCreen function doesn't render the "press space to start" label when the program is started but it does after the character dies for the first time (as can you see below, the function runs in an infinite loop, startScreen is recalled again after the player loses). The way the game works is displayed below:
pygame.init()
win = pygame.display.set_mode((600, 900))
pygame.display.set_caption('The Game')
start_font = pygame.font.SysFont('Arial', 25, bold = True)
def startScreen():
start = True
while start:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
mainGame()
start = False
win.fill((0,0,0))
start_text = start_font.render('PRESS SPACE TO START', 1, (255, 255, 255))
win.blit(start_text, (50, 300))
pygame.display.update()
def mainGame():
main game code
while True:
startScreen()
I didn't paste the mainGame function code as I doubt it affects the issue. Hope somebody can spot the mistake :).
The problem with your code is that until you run mainGame(), start=True and only when you've run the game does start become False. However, the "press space to start text"'s placed after the loop therefore it will only run once the loop has been exited (which means you have played the game at least once.
To solve this problem simply place the display code before the loop as shown below:
def startScreen():
# Display Start Text
win.fill((0,0,0))
start_text = start_font.render('PRESS SPACE TO START', 1, (255, 255, 255))
win.blit(start_text, (50, 300))
pygame.display.update()
# Loop until exited or game is played
start = True
while start:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
mainGame()
start = False
Related
I tried to use python to display image:
import pygame
win = pygame.display.set_mode((500, 500))
DisplayImage("Prologue.jpg", win)
And when it runs, nothing happened. It also happened for
DisplayImage("Streets.jpg", win)
However, when I tried the exact same thing later on in the code, it ran perfectly.
I checked, the picture was in the same folder as the .py file, and I didn't type the name wrong.
The function is:
def DisplayImage(imageName, screen):
screen.fill((0, 0, 0))
Image = pygame.image.load(imageName).convert()
screen_rect = screen.get_rect()
Image_rect = Image.get_rect().fit(screen_rect)
Image = pygame.transform.scale(Image, Image_rect.size)
screen.blit(Image, [0, 0])
pygame.display.update()
Update:
I commented out all of the lines and copy and pasted that line out so it's the only line that runs. It runs perfectly.
Update 2:
Found the issue. The reason it doesn't work was that the pygame window was "not responding". I don't know what caused it to not respond, but in one of the test runs I didn't make it show "not responding", and the images were loaded fine. The "not responding" always shows up when I type in my player name, and the function looks like this:
def createName():
playerName = input("Enter the player name\n")
desiredName = input("Is "+playerName+" the desired name?[1]Yes/[2]No\n")
if desiredName == "1":
return playerName
elif desiredName == "2":
playerName = createName()
Sometimes when I type the player name nothing happens, and the letters only show up after a while. If this happens, the pygame window is bound to not respond.
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:
run = True
while run:
event_list = pygame.event.get()
for event in event_list:
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if pygame.key == pygame.K_1:
# [...]
if pygame.key == pygame.K_2:
# [...]
Another option is to get the input in a separate thread.
Minimal example:
import pygame
import threading
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
color = "red"
def get_input():
global color
color = input('enter color (e.g. blue): ')
input_thread = threading.Thread(target=get_input)
input_thread.start()
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window_center = window.get_rect().center
window.fill(0)
pygame.draw.circle(window, color, window_center, 100)
pygame.display.flip()
pygame.quit()
exit()
This is my first game so excuse the messy code. I am making a space invaders game and everything i implemented is working fine (sprites, function of the game, music, pause screen, etc). I wanted to implement a really simple menu screen where, if you press C, the game starts. However, the problem with this is that no matter where i call the menu function, there is always a problem, here is the code (im just going to post the menu function and main loop since everything else i believe is not needed).
import pygame
import random
import math
from pygame import mixer
# Start pygame
pygame.init()
# Create Screen
screen = pygame.display.set_mode((1000, 710))
# Background Image
background = pygame.image.load('background.png').convert_alpha()
# Menu Variables
menu_font = pygame.font.Font('freesansbold.ttf', 65)
menuX = 380
menuY = 250
# Menu Function
def game_intro(x, y):
menu = True
while menu:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
menu = False
if event.key == pygame.K_q:
pygame.quit()
quit()
# Menu Text
menu_text = menu_font.render("Space Invaders", True, (255, 255, 255))
screen.blit(menu_text, (x, y))
pygame.display.update()
# Game Loop
running = True
while running:
# RGB - Red, Green, Blue
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
----game_intro(menuX,menuY)---IF I PUT IT HERE, THE ACTUAL GAME APPEARS FOR ONE SECOND AND IT GOES BACK TO MAIN MENU-----------
# Making the screen stay still
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
--------game_intro(menuX,menuY)--- IF I PUT IT HERE, THE GAME APPEARS ONLY WHEN 'c' IS BEING HELD DOWN-----------------
*more code*
# Updating
pygame.display.update()
if i put it above pygame.display.update(), then the same thing happens: the game appears for one second and then it goes back to the menu screen. I have tried to search everywhere but the videos either are from 2014, and the websites with some similar problem don't explain how to fix it. Please help.
First of all you should throw the while loop out of your function.
def game_intro(x, y):
# Menu Text
menu_text = menu_font.render("Space Invaders", True, (255, 255, 255))
screen.blit(menu_text, (x, y))
the missing code gets put in the mainloop like this
...
# Making the screen stay still
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
menu = False
if event.key == pygame.K_q:
pygame.quit()
...
now in your mainloop you need to decide whether to draw the menu or the game
if menu:
game_intro(x, y)
else:
#CODE THAT DRAWS THE GAME
all together:
import pygame
import random
import math
from pygame import mixer
# Start pygame
pygame.init()
# Create Screen
screen = pygame.display.set_mode((1000, 710))
# Background Image
background = pygame.image.load('background.png').convert_alpha()
# Menu Variables
menu_font = pygame.font.Font('freesansbold.ttf', 65)
menuX = 380
menuY = 250
# Menu Function
def game_intro(x, y):
# Menu Text
menu_text = menu_font.render("Space Invaders", True, (255, 255, 255))
screen.blit(menu_text, (x, y))
# Game Loop
running = True
while running:
# RGB - Red, Green, Blue
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
# Making the screen stay still
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
menu = False
if event.key == pygame.K_q:
pygame.quit()
if menu:
game_intro(x, y)
else:
# CODE THAT DRAWS THE GAME
# Updating
pygame.display.update()
this should work
note that you need to set menu to True somewhere to get into the menu
import pygame,sys
pygame.init()
screen = pygame.display.set_mode((800,600))
game_over = False
while not game_over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
pygame.draw.rect(screen, (255,0,0),(400,300,50,50))
pygame.display.flip()
As #Furas writes, the screen update code is not being called from within the loop. Python uses indentation to designate code blocks, so if the function call (or other code section) is not indented to the correct column, it is literally a completely different set of operations.
Since a piece of sample code is worth a thousand words:
import pygame,sys
pygame.init()
screen = pygame.display.set_mode((800,600))
game_over = False
while not game_over:
# Handle user-events
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
# Re-draw the screen
pygame.draw.rect(screen, (255,0,0), (400,300,50,50))
pygame.display.flip()
pygame.quit()
sys.exit()
I'm having a hard time with pygame blitting text onto the screen. Right now before quitting I just want to have a message show up for 2 seconds, then have the game quit. To do this I use time.sleep(2). However, and I believe most other people don't have this issue from questions I've looked up on Stackoverflow, the text just doesn't show up until what seems to be the last moment before the window closes. Rather, the screen remains white after pressing the close button. My code is below. Please note that this is not a duplicate of this question.
import pygame
import time
pygame.init()
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
clock = pygame.time.Clock()
FPS = 30
font = pygame.font.SysFont(None, 25)
x = False
while not x:
for event in pygame.event.get():
if event.type == pygame.QUIT:
x = True
gameDisplay.fill(white)
pygame.display.update()
clock.tick(FPS)
screen_text = font.render('Test', True, red)
gameDisplay.blit(screen_text, (0, 0))
pygame.display.update()
time.sleep(2)
pygame.quit()
I ended up using the pygame.time.set_timer workaround #CodeSurgeon mentioned.
This worked for me - replacing time.sleep(2), with:
pygame.time.set_timer(pygame.USEREVENT, 2000)
should_quit = False
while not should_quit:
for event in pygame.event.get():
if event.type == pygame.USEREVENT:
should_quit = True
I actually have the exact same problem and found that if I moved time.sleep(2) directly after pygame.quit() it worked as intended. I'm new to pygame and not sure why this works
screen_text = font.render('Test', True, red)
gameDisplay.blit(screen_text, (0, 0))
pygame.display.update()
pygame.quit()
time.sleep(2)
You could try replacing time.sleep(2) with
for i in range(0, 200, 1):
time.sleep(0.01)
This can be useful in other situations with long sleeps if you want to be able to use CTRL-C to stop the program. It also might be more convenient to use a function:
def MySleep(duration, resolution=10):
"""Sleep, without freezing the program. All values in ms"""
for i in range(0, int(duration), int(resolution)):
time.sleep(resolution / 1000)
for some reason, stdlib time.sleep() does not work in pygame.
However, pygame does have its own time function.
Here is the code I wrote to print out a message, character by character.
message = ""
font = pygame.font.Font("freesansbold.ttf", 32)
message_text_x = 0
message_text_y = 550
message_text_speed = 35
inF = open("chapter_1.txt")
lines = inF.readlines()
def write_message(char, x, y):
# first render the value as text so it can be drawn on the screen using screen.blit
message_text = font.render(char, True, (0, 0, 0))
screen.blit(message_text, (x, y))
running = True
while running:
for line in lines:
for char in line:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
running = False
if event.key == pygame.K_SPACE:
message_text_speed = 10
message += char
write_message(message, message_text_x, message_text_y)
pygame.event.pump()
pygame.time.delay(message_text_speed)
pygame.display.update()
clock.tick(60)
When spacebar is clicked the speed of the text becomes faster
I have the following code in Python 3 (and pygame), but the white surface fails to display and I don't understand why. Has it got something to do with where it has been placed? I tried de-indenting, but that didn't work either? The code is as below:
import pygame
from pygame.locals import*
pygame.init()
screen=pygame.display.set_mode((800,600))
# Variable to keep our main loop running
running = True
# Our main loop!
while running:
# for loop through the event queue
for event in pygame.event.get():
# Check for KEYDOWN event; KEYDOWN is a constant defined in pygame.locals, which we imported earlier
if event.type == KEYDOWN:
# If the Esc key has been pressed set running to false to exit the main loop
if event.key == K_ESCAPE:
running = False
# Check for QUIT event; if QUIT, set running to false
elif event.type == QUIT:
running = False
# Create the surface and pass in a tuple with its length and width
surf = pygame.Surface((50, 50))
# Give the surface a color to differentiate it from the background
surf.fill((255, 255, 255))
rect = surf.get_rect()
screen.blit(surf, (400, 300))
pygame.display.flip()
So it does appear that your indentation is wrong.
You need to define the surface and update the screen etc. outside of the event loop.
At the very least you must move the screen.blit(surf, (400, 300)) and pygame.display.flip() outside of the event loop.
This is it fixed:
# Our main loop!
while running:
# for loop through the event queue
for event in pygame.event.get():
# Check for KEYDOWN event; KEYDOWN is a constant defined in pygame.locals, which we imported earlier
if event.type == KEYDOWN:
# If the Esc key has been pressed set running to false to exit the main loop
if event.key == K_ESCAPE:
running = False
# Check for QUIT event; if QUIT, set running to false
elif event.type == QUIT:
running = False
# Create the surface and pass in a tuple with its length and width
surf = pygame.Surface((50, 50))
# Give the surface a color to differentiate it from the background
surf.fill((255, 255, 255))
rect = surf.get_rect()
screen.blit(surf, (400, 300))
pygame.display.flip()