I'm working through a python book. So far, all of the programs have worked, but now I'm stuck. I typed in the program, and I'm getting this error when I run it. I checked all of the lines several times, and I think everything's right. It is supposed to open a text window and 10 seconds later show a game character. At first, I had an indent error, but I fixed that. Now I'm getting this new error. it starts up and runs for about 0.5 seconds, but it immediately closes and gives this error. I'm using Python 3.8.10 On Windows 10 Pro 64-bit and this is the error: pygame.error: video system not initialized and here is the code:
import pygame
import time
import subprocess
pygame.init()
screen = pygame.display.set_mode((800, 250))
clock = pygame.time.Clock()
font = pygame.font.Font(None, 25)
pygame.time.set_timer(pygame.USEREVENT, 200)
def text_generator(text):
tmp = ""
for letter in text:
tmp += letter
if letter != " ":
yield tmp
class DynamicText(object):
def __init__(self, font, text, pos, autoreset=False):
self.done = False
self.font = font
self.text = text
self._gen = text_generator(self.text)
self.pos = pos
self.autoreset = autoreset
self.update()
def reset(self):
self._gen = text_generator(self.text)
self.done = False
self.update()
def update(self):
if not self.done:
try: self.rendered = self.font.render(next(self._gen), True, (0, 128, 0))
except StopIteration:
self.done = True
time.sleep(10)
subprocess.Popen("python C:\\Users\\david\\Documents\\pythonbook\\pygame1.py 1", shell=True)
def draw(self, screen):
screen.blit(self.rendered, self.pos)
text=("Steve has gone on a quest to defeat the Ender Dragon. Will he make it?")
message = DynamicText(font, text, (65, 120), autoreset=True)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT: break
if event.type == pygame.USEREVENT: message.update()
else:
screen.fill(pygame.color.Color('black'))
message.draw(screen)
pygame.display.flip()
clock.tick(60)
continue
break
pygame.quit()
How can I figure out what the error message means? Or does anyone know?
You quit the game in every frame with pygame.quit(). quit the game after the application loop instead of in the application loop. Also why do you update the game just in the else case? The break statement in case of event.type == pygame.QUIT only breaks the event loop, but not the application loop. Change the control flow of your code:
# application loop
run = True
while run:
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT: run = False
if event.type == pygame.USEREVENT: message.update()
# redraw in every frame
screen.fill(pygame.color.Color('black'))
message.draw(screen)
pygame.display.flip()
clock.tick(60)
# quit after the application loop
pygame.quit()
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()
I'm working on custom basic functions to simplify coding for me, like wait(seconds) or msg(...), and now I'm working on the window setup and updating, it works, but when I put it in a thread, it just won't do anything. I don't get any errors, so I'm confused and frustrated. I dont need you to debug it or anything, I just need help to know where the problem is and why it's a problem.
Here's my script so far (the script is at the bottom):
# Imports
if True:
import pygame, math, random, time, sys, threading
from pygame.locals import *
pygame.init()
# Setup
if True:
win_n = "New Project"
win_w = 800
win_h = 600
win_c = (0, 0, 0)
# Code
if True:
def wait(seconds):
time.sleep(seconds)
def wait_until(bool):
while not bool:
wait(0.001)
# Execute
if True:
def e_ws():
mainClock = pygame.time.Clock()
pygame.display.set_caption(win_n)
monitor_size = [pygame.display.Info().current_w, pygame.display.Info().current_h]
screen = pygame.display.set_mode((win_w, win_h), pygame.RESIZABLE)
fullscreen = False
while True:
screen.fill(win_c)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == VIDEORESIZE:
if not fullscreen:
screen = pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE)
if event.type == KEYDOWN:
if fullscreen:
screen = pygame.display.set_mode(monitor_size, pygame.FULLSCREEN)
else:
screen = pygame.display.set_mode((screen.get_width(), screen.get_height()),
pygame.RESIZABLE)
pygame.display.update()
mainClock.tick(60)
t_ws = threading.Thread(target=e_ws)
t_ws.start()
print("done")
Run a script with python yourscriptname.py from the command line.
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
This question already has answers here:
Why is my PyGame application not running at all?
(2 answers)
Why is nothing drawn in PyGame at all?
(2 answers)
Closed 2 years ago.
import pygame as pg
import sys
pg.init()
buttonFont = pg.font.SysFont("garamond", 25)
screenGray = pg.Color('gray80')
buttonGray2 = pg.Color('gray50')
textColour = pg.Color('navy')
screen = pg.display.set_mode((800, 600))
clock = pg.time.Clock()
class Button(pg.sprite.Sprite):
def __init__(self, text, x, y, width, height, colour):
super().__init__()
self.image = pg.Surface((width, height))
self.image.fill(colour)
self.rect = self.image.get_rect()
txt = buttonFont.render(text, True, textColour)
txtRect = txt.get_rect(center = self.rect.center)
self.image.blit(txt, txtRect)
self.rect.topleft = x, y
def isPressed(self, event):
if event.type == pg.MOUSEBUTTONDOWN:
if self.rect.collidepoint(event.pos):
return True
return False
def FrontPage():
screen.fill(screenGray)
Continue = Button('Continue', 105, 455, 120, 50, buttonGray2)
buttonsGroup1 = pg.sprite.Group(Continue)
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
elif Continue.isPressed(event):
Menu()
buttonsGroup1.draw(screen)
pg.display.flip()
clock.tick(60)
def Menu():
screen.fill(screenGray)
Scytale = Button('Scytale', 105,105,140,65, buttonGray2)
Caesar = Button('Caesar', 330,105,140,65, buttonGray2)
Vigenere = Button('Vigenere', 555,105,140,65, buttonGray2)
Enigma = Button('Enigma', 105,430,140,65,buttonGray2)
PublicKey = Button('Public Key', 330,430,140,65, buttonGray2)
Rijndael = Button('Rijndael', 555,430,140,65, buttonGray2)
buttonsGroup2 = pg.sprite.Group(Scytale,Caesar,Vigenere,Enigma,PublicKey,Rijndael)
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
buttonsGroup2.draw(screen)
clock.tick(60)
FrontPage()
Above is the stripped back code of my FrontPage, that has a button on it that, when clicked, should take the user to the menu screen where 6 more buttons are displayed to move onto the users chosen encryption method.
However, when I press the Continue button, nothing happens.
Is it because there is something wrong with the Button Class?
Or is there something else that makes the button stop working?
Thanks in advance
You have to call pg.display.flip() in the Menu function.
I also have a little recommendation about the code structure. I'd use another function or class (main in this case) to manage the different scenes. So I first assign the current scene function to a variable and call it in the main while loop. When the scene is done, I return the next scene and assign it to the scene variable to swap the scenes. That will avoid potential recursion errors which you get if you just call the next function directly from within another scene (although it's unlikely that you'll exceed the recursion limit of 1000 in a simple game or app).
import pygame as pg
pg.init()
screen = pg.display.set_mode((600, 400))
clock = pg.time.Clock()
BLUE = pg.Color('dodgerblue3')
ORANGE = pg.Color('sienna3')
def front_page():
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
return None
# Press a key to return the next scene.
elif event.type == pg.KEYDOWN:
return menu
screen.fill(BLUE)
pg.display.flip()
clock.tick(60)
def menu():
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
return None
# Press a key to return the next scene.
elif event.type == pg.KEYDOWN:
return front_page
screen.fill(ORANGE)
pg.display.flip()
clock.tick(60)
def main():
scene = front_page # Set the current scene.
while scene is not None:
# Execute the current scene function. When it's done
# it returns either the next scene or None which we
# assign to the scene variable.
scene = scene()
main()
pg.quit()
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