Pygame Text Blit and time.sleep not working - python

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

Related

Why does pygame window animationonly work when i am moving my cursor

I am making flappy bird following this guide https://www.youtube.com/watch?v=UZg49z76cLw&t=1309s
but the screen only updates when i move my cursor does anyone know how to fix this
import pygame, sys
def draw_floor():
screen.blit(floor_surface, (floor_animation, 400))
screen.blit(floor_surface, (floor_animation + 275,400))
pygame.init()
screen = pygame.display.set_mode((275,512))
clock = pygame.time.Clock()
bg_surface = pygame.image.load('C:/Users/cuerv/Downloads/flappy-bird-assets-master/flappy-bird-assets-master/sprites/background-day.png').convert()
floor_surface = pygame.image.load('C:/Users/cuerv/Downloads/flappy-bird-assets-master/flappy-bird-assets-master/sprites/base.png').convert()
floor_animation = 0
bird_surface = pygame.image.load('C:/Users/cuerv/Downloads/flappy-bird-assets-master/flappy-bird-assets-master/sprites/bluebird-midflap.png').convert()
bird_rect = bird_surface.get_rect(center = (100,256))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.blit(bg_surface, (0, 0))
screen.blit(bird_surface, (bird_rect))
floor_animation -= 1
draw_floor()
if floor_animation <= -275:
floor_animation = 0
screen.blit(floor_surface, (floor_animation, 400))
pygame.display.update()
clock.tick(120)
enter code here
Its a matter of Indentation. Draw the scene in the application loop rather than the event loop:
# application loop
while True:
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
#<--| INDENTATION
screen.blit(bg_surface, (0, 0))
screen.blit(bird_surface, (bird_rect))
floor_animation -= 1
draw_floor()
if floor_animation <= -275:
floor_animation = 0
screen.blit(floor_surface, (floor_animation, 400))
pygame.display.update()
Note, the event loop is only executed when an event occurs, but the application loop is executed continuously.
I guess in your function action is happening just when the mouse is hovering over the image or when position of mouse at time t1 != position at t2. Also provide the code so we can check what may be the problem :)
https://www.pygame.org/docs/ref/mouse.html

How to fix pygame menu (space invaders)?

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

pygame start menu not rendering when the program starts

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

Unable to start thread that plays sound [duplicate]

I started using pygame and I want to do simple game. One of the elements which I need is countdown timer.
How can I do the countdown time (eg 10 seconds) in PyGame?
Another easy way is to simply use pygame's event system.
Here's a simple example:
import pygame
pygame.init()
screen = pygame.display.set_mode((128, 128))
clock = pygame.time.Clock()
counter, text = 10, '10'.rjust(3)
pygame.time.set_timer(pygame.USEREVENT, 1000)
font = pygame.font.SysFont('Consolas', 30)
run = True
while run:
for e in pygame.event.get():
if e.type == pygame.USEREVENT:
counter -= 1
text = str(counter).rjust(3) if counter > 0 else 'boom!'
if e.type == pygame.QUIT:
run = False
screen.fill((255, 255, 255))
screen.blit(font.render(text, True, (0, 0, 0)), (32, 48))
pygame.display.flip()
clock.tick(60)
On this page you will find what you are looking for http://www.pygame.org/docs/ref/time.html#pygame.time.get_ticks
You download ticks once before beginning the countdown (which can be a trigger in the game - the key event, whatever).
For example:
start_ticks=pygame.time.get_ticks() #starter tick
while mainloop: # mainloop
seconds=(pygame.time.get_ticks()-start_ticks)/1000 #calculate how many seconds
if seconds>10: # if more than 10 seconds close the game
break
print (seconds) #print how many seconds
In pygame exists a timer event. Use pygame.time.set_timer() to repeatedly create an USEREVENT. e.g.:
timer_interval = 500 # 0.5 seconds
timer_event = pygame.USEREVENT + 1
pygame.time.set_timer(timer_event , timer_interval)
Note, in pygame customer events can be defined. Each event needs a unique id. The ids for the user events have to be between pygame.USEREVENT (24) and pygame.NUMEVENTS (32). In this case pygame.USEREVENT+1 is the event id for the timer event.
To disable the timer for an event, set the milliseconds argument to 0.
Receive the event in the event loop:
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == timer_event:
# [...]
The timer event can be stopped by passing 0 to the time parameter.
See the example:
import pygame
pygame.init()
window = pygame.display.set_mode((200, 200))
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 100)
counter = 10
text = font.render(str(counter), True, (0, 128, 0))
timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, 1000)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == timer_event:
counter -= 1
text = font.render(str(counter), True, (0, 128, 0))
if counter == 0:
pygame.time.set_timer(timer_event, 0)
window.fill((255, 255, 255))
text_rect = text.get_rect(center = window.get_rect().center)
window.blit(text, text_rect)
pygame.display.flip()
pygame.time.Clock.tick returns the time in milliseconds since the last clock.tick call (delta time, dt), so you can use it to increase or decrease a timer variable.
import pygame as pg
def main():
pg.init()
screen = pg.display.set_mode((640, 480))
font = pg.font.Font(None, 40)
gray = pg.Color('gray19')
blue = pg.Color('dodgerblue')
# The clock is used to limit the frame rate
# and returns the time since last tick.
clock = pg.time.Clock()
timer = 10 # Decrease this to count down.
dt = 0 # Delta time (time since last tick).
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
timer -= dt
if timer <= 0:
timer = 10 # Reset it to 10 or do something else.
screen.fill(gray)
txt = font.render(str(round(timer, 2)), True, blue)
screen.blit(txt, (70, 70))
pg.display.flip()
dt = clock.tick(30) / 1000 # / 1000 to convert to seconds.
if __name__ == '__main__':
main()
pg.quit()
There are several ways you can do this- here's one. Python doesn't have a mechanism for interrupts as far as I know.
import time, datetime
timer_stop = datetime.datetime.utcnow() +datetime.timedelta(seconds=10)
while True:
if datetime.datetime.utcnow() > timer_stop:
print "timer complete"
break
There are many ways to do this and it is one of them
import pygame,time, sys
from pygame.locals import*
pygame.init()
screen_size = (400,400)
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption("timer")
time_left = 90 #duration of the timer in seconds
crashed = False
font = pygame.font.SysFont("Somic Sans MS", 30)
color = (255, 255, 255)
while not crashed:
for event in pygame.event.get():
if event.type == QUIT:
crashed = True
total_mins = time_left//60 # minutes left
total_sec = time_left-(60*(total_mins)) #seconds left
time_left -= 1
if time_left > -1:
text = font.render(("Time left: "+str(total_mins)+":"+str(total_sec)), True, color)
screen.blit(text, (200, 200))
pygame.display.flip()
screen.fill((20,20,20))
time.sleep(1)#making the time interval of the loop 1sec
else:
text = font.render("Time Over!!", True, color)
screen.blit(text, (200, 200))
pygame.display.flip()
screen.fill((20,20,20))
pygame.quit()
sys.exit()
This is actually quite simple. Thank Pygame for creating a simple library!
import pygame
x=0
while x < 10:
x+=1
pygame.time.delay(1000)
That's all there is to it! Have fun with pygame!
Another way to do it is to set up a new USEREVENT for a tick, set the time interval for it, then put the event into your game loop
'''
import pygame
from pygame.locals import *
import sys
pygame.init()
#just making a window to be easy to kill the program here
display = pygame.display.set_mode((300, 300))
pygame.display.set_caption("tick tock")
#set tick timer
tick = pygame.USEREVENT
pygame.time.set_timer(tick,1000)
while 1:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.USEREVENT:
if event.type == tick:
## do whatever you want when the tick happens
print('My tick happened')

Pygame crashes every time i click in the window

Here is the code:
import pygame, time
pygame.init()
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,155,0)
blue = (0,0,255)
def button(x,y,w,h,action=None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x+w > mouse[0] > x and y+h > mouse[1] > y:
if click [0] == 1 and action != None:
if action == "exit":
pygame.quit()
quit()
gameDisplay = pygame.display.set_mode((800,600))
pygame.display.set_caption("Game")
clock = pygame.time.Clock()
gameExit = False
menu1 = True
menu2 = True
gameloop = True
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
while menu1:
logo1 = pygame.image.load('logo.jpg')
gameDisplay.blit(logo1, (1, 1))
time.sleep(2)
pygame.display.update()
while menu2:
logo2 = pygame.image.load("logo2.jpg")
gameDisplay.blit(logo2, (0, 0))
time.sleep(2)
pygame.display.update()
time.sleep(2)
while gameloop:
gameDisplay.fill(white)
button(0, 0, 10,10,"exit")
pygame.draw.rect(gameDisplay, red, (0, 0, 10, 10))
pygame.display.update()
clock.tick(15)
pygame.quit()
quit()
Im assuming its all the while loops, i wanted to create a slide show of 2 logos that plays for 2 seconds each (which works) but as soon as I get past the slideshow, I click close, and it crashes. I tried adding a quick button (red square at the top right) and it crashes aswell. I am completely stumped and have looked through everything and made a ton of changes but it crashes... Please help, thanks in advance.
Your while loops are causing your problems, because you are never breaking out of them.
Personally, I think you should use the current pygame.time.get_ticks() in order to time your events. Here's an example:
# Code above here is unchanged
gameExit = False
logo1 = pygame.image.load('logo.png') # Don't load these in a loop!
logo2 = pygame.image.load('logo2.png') # Only need to load them once.
# Make sure you record start_time here! Because the timer actually
# started several seconds before the display is ready.
start_time = pygame.time.get_ticks() / 1000
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
time = pygame.time.get_ticks() / 1000
elapsed = time - start_time
gameDisplay.fill(black)
if elapsed > 4:
gameDisplay.fill(white)
button(0, 0, 10, 10, 'exit')
pygame.draw.rect(gameDisplay, red, (0, 0, 10, 10))
elif elapsed > 2:
gameDisplay.blit(logo2, (0, 0))
elif elapsed > 0:
gameDisplay.blit(logo1, (1, 1))
pygame.display.update()
clock.tick(15)
pygame.quit()
quit()
What I did was check to see if the elapsed time was greater than 4 seconds. If so, show the red square. If not, we go to the next one. Is time after 2 seconds? If so, show logo2. Finally, if the time is > 0, which it is right in the beginning, we show logo1. They are setup in the opposite order, because of the way if / elif works: it only catches the first one that is True. So as time goes on, the higher and higher options become True.
Does that make sense?

Categories