I have a project in Pygame 1.9.2 where I reinitialize the display multiple times, and draw text to the display surface. It works fine until I close the Pygame display and re-initialize it again.
It follows a structure like this:
from pygame import *
init() # this is pygame.init()
running = True
while running:
display.set_mode((800,600))
visible = True
textFont = font.SysFont("Comic Sans MS", 12)
while visible:
for evt in event.get():
if evt.type == QUIT:
visible = False
if evt.type == KEYDOWN:
if evt.key == K_ESCAPE:
visible = running = False
textPic = textFont.render("Hello world!", True, (255,255,255))
display.get_surface().blit(textPic, (0,0))
display.flip()
quit()
This program works until the display is closed for the first time and then reinitialized, after which I receive the following error when trying to use textFont.render:
pygame.error: Text has zero width
I'm tearing my hair out trying to figure out what's wrong... I know that "Hello world!" has a width greater than zero. How do I fix this problem?
The problem is that pygame.quit() was called before the program was finished. This causes every Pygame module (e.g. pygame.font) to be uninitialized.
Instead of relying on pygame.quit to close the Pygame display, use pygame.display.quit at the end of every while running loop. Then put pygame.quit at the very end of the script to unload the rest of the modules after they're done being used.
(Calling pygame.init() again before rendering text won't fix this issue either, because it causes the Pygame display to stop responding. (This might be a bug with Pygame 1.9.2)
I found a solution that worked for me: just delete the font element before calling pygame.display.quit(), ie just del font every time you're done using it.
The font element is the one you created using the command:
font.SysFont("Comic Sans MS", 12)
but that I personally create using pygame.font.Font(None, font_size)
Related
I'm using jupyter notebook to make a py-game. I've noticed that EVERY TIME I render some text in the game, the notebook will collapse. It works when I run the game and the text is shown as expected. However, when I close the game's window and try to run the code for a second time it will collapse. Some times it will work for a couple of tries, but it'll collapse at some point. Other times, the notebook just collapses as soon as I close the game's window.
The relevant part of the code would be:
import pygame
pygame.init()
run=True
#screensize
screensize = (width,height)=(600,600)
screen = pygame.display.set_mode(screensize)
#font used for the text
myfont = pygame.font.SysFont('Comic Sans MS', 30)
#the text that will be rendered. It is usually some variable value, but the problem remains even if it is constant:
vel=3.001
while run:
pygame.time.delay(20)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run=False
screen.fill((0,0,0))
########rendering the text############
textsurface = myfont.render(str(int(vel)), False, (0, 100, 100))
screen.blit(textsurface,(200,400))
######################################
pygame.display.update()
pygame.quit()
Lets say I run the code and the I close the window. If I try to run the code again, the message is:
Le noyau semble planté. Il va redémarrer automatiquement.
(the kernel appears to have died. it will restart automatically)
I've been advised not to use pygame with jupyter notebook, but I jus't can't code outside that environment.
As suggested by user 'furas' above, activating pygame once and replacing pygame.init() for pygame.display.init(); and pygame.quit() by pygame.display.quit() solved this problem for me. Not sure if it implies more resources being used, but so far it has shown no problems in my rather basic laptop.
import pygame
pygame.init()
In a different cell:
pygame.display.init()
run=True
#screensize
screensize = (width,height)=(600,600)
screen = pygame.display.set_mode(screensize)
#font used for the text
myfont = pygame.font.SysFont('Comic Sans MS', 30)
#the text that will be rendered. It is usually some variable value, but the problem remains even if it is constant:
vel=3.001
while run:
pygame.time.delay(20)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run=False
screen.fill((0,0,0))
########rendering the text############
textsurface = myfont.render(str(int(vel)), False, (0, 100, 100))
screen.blit(textsurface,(200,400))
######################################
pygame.display.update()
pygame.display.quit()
I am not able to run anything using pygame as whenever I run anything, even a very simple program displaying a circle, the program yields a black screen which does nothing.
The black screen I am talking about is this black screen
What is this exactly? and is there a way to fix it?
Edit:
I forgot to mention that the program appears to be running well and I get no errors.
Edit #2: This is my very simple program:
import pygame
pygame.init()
screen = pygame.display.set_mode([500, 500])
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((255, 255, 255))
SCREEN_TITLE = 'Chess Game'
pygame.display.set_caption(SCREEN_TITLE)
pygame.draw.circle(screen, (0, 0, 255), (250, 250), 75)
pygame.display.flip()
pygame.quit()
Edit #3: a picture of what is showing on the python console
after I press the exit button
before I press the exit button
You may experience two separated issues:
Issue 1: Pygame installation on MacOS
There are some documented problems when running PyGame with MacOS. Please check that you have correctly installed and setup pygame in your machine. This post might be useful.
Issue 2: Code incorrections
Apart from that, your code has several issues. Your running loop does not display anything since it is stuck processing events and nothing more. Therefore, you see a black screen. Notice that you are printing the screen and the circle when the execution is over.
When using pygame I suggest to differentiate between:
Initialisation: Setup pygame and screen. Render any static content.
Running loop: Process events and render any dynamic content.
End: Display any end animation/object and finalise pygame.
I suggest the following modifications:
Render first the screen
In the running loop just process the events and render the circle
I have added debug messages. You can enable and disable them by running python mygame.py and python -O mygame.py. Be aware that the print statements inside the running loop will print a lot of messages.
Here is the code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# For better print formatting
from __future__ import print_function
# Imports
import pygame
#
# MAIN FUNCTION
#
def main():
# Setup display and static content
if __debug__:
print("Initialising pygame")
pygame.init()
SCREEN_TITLE = 'Chess Game'
pygame.display.set_caption(SCREEN_TITLE)
screen = pygame.display.set_mode([500, 500])
screen.fill((255, 255, 255))
pygame.display.flip()
# Running loop
running = True
while running:
if __debug__:
print("New iteration")
# Process events
if __debug__:
print("- Processing events...")
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Display any dynamic content
if __debug__:
print("- Rendering dynamic content...")
pygame.draw.circle(screen, (0, 0, 255), (250, 250), 75)
# Update display
if __debug__:
print("- Updating display...")
pygame.display.flip()
# End
if __debug__:
print("End")
pygame.quit()
#
# ENTRY POINT
#
if __name__ == "__main__":
main()
Debug output:
$ python mygame.py
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
Initialising pygame
New iteration
- Processing events...
- Rendering dynamic content...
- Updating display...
.
.
.
New iteration
- Processing events...
- Rendering dynamic content...
- Updating display...
End
Display:
I'm using pygame and updating to the screen every loop of the main loop. What I don't understand is nothing will update until I add a for loop looking for events, then suddenly all the updating does occur. Why is this?
def run(self):
two_pm = get_stand_up_timestamp()
pygame.init()
font = pygame.font.Font(None, 72)
screen = pygame.display.set_mode(self._dimensions)
before_two = True
while before_two:
# Blit the time to the window.
# Update Screen.
current_time = datetime.datetime.now()
text = font.render(f'{current_time.hour} : {current_time.minute} : {current_time.second}', True, (0, 0, 0))
blit_center = (
self._dimensions[0] // 2 - (text.get_width() // 2),
self._dimensions[1] // 2 - (text.get_height() // 2)
)
screen.fill((255, 255, 255))
screen.blit(text, blit_center)
pygame.display.flip()
# Get events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
sys.exit()
When you call pygame.event.get() (or pump()), pygame processes all events that your window manager send to the window managed by pygame.
You don't see these events as they are not returned by get(), but pygame handles them internally. These events could be WM_PAINT on Windows or Expose on Linux (IIRC pygame uses Xlib), or other events (I guess you could look them up in pygame's source code).
E.g. if you run pygame on Windows, Pygame has to call Windows' GetMessage function, otherwise:
If a top-level window stops responding to messages for more than several seconds, the system considers the window to be not responding and replaces it with a ghost window that has the same z-order, location, size, and visual attributes. This allows the user to move it, resize it, or even close the application. However, these are the only actions available because the application is actually not responding.
So the typical behaviour if you don't let pygame process the events is that it will basically run, but the mouse cursor will change to the busy cursor and you can't move the window before it will eventually freeze.
If you run pygame on other systems, e.g. Linux, you only see a black screen. I don't know the internals of the message loop when pygame runs on Linux, but it's similiar to the Windows message loop: you have to process the events in the queue to have pygame call Xlib's XNextEvent function (IIRC) to give the window manager a chance to draw the window.
See e.g. Message loop in Microsoft Windows and/or Xlib for more information on that topic.
No idea why it doesn't work on your end, however when I run
def run():
width = 500
height = 500
pygame.init()
font = pygame.font.Font(None, 72)
screen = pygame.display.set_mode((width, height))
before_two = True
while before_two:
# Blit the time to the window.
# Update Screen.
current_time = datetime.datetime.now()
text = font.render(f'{current_time.hour} : {current_time.minute} : {current_time.second}', True, (0, 0, 0))
blit_center = (
width // 2 - (text.get_width() // 2),
height // 2 - (text.get_height() // 2)
)
screen.fill((255, 255, 255))
screen.blit(text, blit_center)
pygame.display.flip()
run()
Everything works fine update wise. The clock ticks every second so it may be something with your version of python or pygame. Try updating them both. Alternately it could be a problem with how you get pass pygame the dimensions of the window with the run(self) and self._dimensions. Trying using static dimensions like I did above and see if that works on your end. Sadly without more code to see how you call run() its difficult to fully debug whats wrong.
I'm slowly trying to get to know pygame and write my first game in it and honestly, I didn't expect problems so early. So far I've only set a display, that is supposed to be there indefinitely (I just wanted to try it out):
import pygame
pygame.init()
(width, height) = (1000, 700)
screen = pygame.display.set_mode((width, height))
while True:
pygame.display.flip()
But when the window appears it says it's "not responding". I tried deleting the loop so that display would just blink once and vanish, because programm would die immiedately after it's created, but I get the same "not responding" window. I'm using pygame 1.9.2 and python 3.5. I wonder if the trouble may be because of anaconda - the window is opened as subcart for anaconda by default.
Edit: So far I discovered that when I open it not from spyder, but just click on a file it works just fine. Is there any way to make it work by simple run and compile while in spyder or it's just how it's supposed to work?
Add this to your loop. For me the only time it isnt responding is when I click the X and this could be to do with the fact that pygame doesn't know what to do when that happens.
import sys
for evt in pygame.event.get():
if evt.type == pygame.QUIT:
pygame.quit()
sys.exit()
#Try This
import pygame
(width, height) = (1000, 700)
screen=pygame.display.set_mode((width, height))
pygame.display.update()
while True:
for event in pygame.event.get():``
if event.type == pygame.QUIT:
pygame.quit()
quit()
I´m a newbie on pygame, and i have this code for trying to do kind of a startscreen for a football game, this start screen has a static background image that is"img_start_screen" and the logo of the game that I want it to have a little animation that stops when it reaches the certain point on the screen, that logo is the variable "logo"
import pygame,sys
from pygame.locals import *
pygame.init()
screen=pygame.display.set_mode((1280,720))
pygame.display.set_caption("CEFoot 3.0")
FPS=60
fpsClock=pygame.time.Clock()
img_start_screen=pygame.image.load("start_screen.gif")
logo=pygame.image.load("logo8bit.png")
logox=390
logoy=0
direction="down"
while True:
window.blit(img_start_screen,(0,0))
if direction == "down":
logoy+=5
if logoy==300:
direction="center"
if direction == "center":
pass
screen.blit(logo,(logox,logoy))
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
pygame.display.update
fpsClock.tick(FPS)
The problem is that when I run the code it starts as a black screen and not until I move the window "out" of the Windows screen it refreshes, the images aren´t the problem as I ran the code without them and it showed the same black screen. I´m beginning to think that it isn´t code problem but compability as I´m running Python 3.2 and Pygame 1.9(I think) the last version that is really old , all this on Windows 10, so this might be the problem.Thanks in advance.
As you know pygame.display.update is a function
as seen if you print it:
>>> print pygame.display.update
<built-in function update>
so when you call pygame.display.update without parenthesis () you are merely stating a reference to a function. Whereas if you use parenthesis you call the function:
>>> print pygame.display.update()
None
this calls the function and returns None