Pygame window is not responding after interaction with it - python-3.x

I need to generate circles in random place every second. Now I have this code.
import pygame as pg
from threading import Thread
import random
pg.init()
WIDTH = 600
HEIGH = 600
sc = pg.display.set_mode((WIDTH, HEIGH))
pg.display.set_caption("Bacteria")
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
sc.fill(BLACK)
pg.display.flip()
clock = pg.time.Clock()
FPS = 24
class FoodGen(Thread):
def run(self):
while 1:
clock.tick(1)
pg.draw.circle(sc, WHITE, (random.randint(10, WIDTH-10), random.randint(10, WIDTH-10)), 10)
class Main(Thread):
def run(self):
running = 1
while running:
clock.tick(FPS)
for event in pg.event.get():
if event.type == pg.QUIT:
running = 0
break
pg.display.flip()
pg.quit()
t1 = FoodGen()
t1.start()
t2 = Main()
t2.start()
When is move mouse on the window it turns to waiting mode. The window is running until I try to move or close it. I've already red many information about this problem, but still can't fix it.

See How to run multiple while loops at a time in Python. If you want to control something over time in Pygame you have two options:
Use pygame.time.get_ticks() to measure time and and implement logic that controls the object depending on the time.
Use the timer event. Use pygame.time.set_timer() to repeatedly create a USEREVENT in the event queue. Change object states when the event occurs.
e.g.:
import pygame as pg
import random
WIDTH, HEIGH = 600, 600
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
FPS = 24
pg.init()
sc = pg.display.set_mode((WIDTH, HEIGH))
pg.display.set_caption("Bacteria")
clock = pg.time.Clock()
timer_interval = 100 # 0.1 seconds
timer_event_id = pg.USEREVENT + 1
pg.time.set_timer(timer_event_id, timer_interval)
circles = []
running = 1
while running:
clock.tick(FPS)
for event in pg.event.get():
if event.type == pg.QUIT:
running = 0
if event.type == timer_event_id:
circles.append((random.randint(10, WIDTH-10), random.randint(10, WIDTH-10)))
sc.fill(BLACK)
for center in circles:
pg.draw.circle(sc, WHITE, center, 10)
pg.display.flip()
pg.quit()

Related

Pygame, A Bit Racey tutorial: Calling the same function to draw the same object multiple times [duplicate]

I'm a beginner programmer who is starting with python and I'm starting out by making a game in pygame.
The game basically spawns circles at random positions and when clicked, it gives you points.
Recently I've hit a roadblock when I want to spawn multiple instances of the same object (in this case circles) at the same time.
I've tried stuff like sleep() and some other code related to counters, but it always results in the next circle spawned overriding the previous one (i.e the program spawns circle 1, but when circle 2 comes in, circle 1 disappears).
Does anyone know a solution to this? I would really appreciate your help!
import pygame
import random
import time
pygame.init()
window = pygame.display.set_mode((800,600))
class circle():
def __init__(self, color, x, y, radius, width,):
self.color = color
self.x = x
self.y = y
self.radius = radius
self.width = width
def draw(self, win, outline=None):
pygame.draw.circle(win, self.color, (self.x, self.y, self.radius, self.width), 0)
run=True
while run:
window.fill((0, 0, 0))
pygame.draw.circle(window, (255, 255, 255), (random.randint(0, 800),random.randint(0, 600)), 20, 20)
time.sleep(1)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run=False
pygame.quit()
quit()
It does not work that way. time.sleep, pygame.time.wait() or pygame.time.delay is not the right way to control time and gameplay within an application loop. The game does not respond while you wait. The application loop runs continuously. You have to measure the time in the loop and spawn the objects according to the elapsed time.
pygame.Surface.fill clears the entire screen. Add the newly created objects to a list. Redraw all of the objects and the entire scene in each frame.
See also Time, timer event and clock
You have 2 options. Use pygame.time.get_ticks() to measure the time. Define a time interval after which a new object should appear. Create an object when the point in time is reached and calculate the point in time for the next object:
object_list = []
time_interval = 500 # 500 milliseconds == 0.1 seconds
next_object_time = 0
while run:
# [...]
current_time = pygame.time.get_ticks()
if current_time > next_object_time:
next_object_time += time_interval
object_list.append(Object())
Minimal example:
repl.it/#Rabbid76/PyGame-TimerSpawnObjects
import pygame, random
pygame.init()
window = pygame.display.set_mode((300, 300))
class Object:
def __init__(self):
self.radius = 50
self.x = random.randrange(self.radius, window.get_width()-self.radius)
self.y = random.randrange(self.radius, window.get_height()-self.radius)
self.color = pygame.Color(0)
self.color.hsla = (random.randrange(0, 360), 100, 50, 100)
object_list = []
time_interval = 200 # 200 milliseconds == 0.2 seconds
next_object_time = 0
run = True
clock = pygame.time.Clock()
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
current_time = pygame.time.get_ticks()
if current_time > next_object_time:
next_object_time += time_interval
object_list.append(Object())
window.fill(0)
for object in object_list[:]:
pygame.draw.circle(window, object.color, (object.x, object.y), round(object.radius))
object.radius -= 0.2
if object.radius < 1:
object_list.remove(object)
pygame.display.flip()
pygame.quit()
exit()
The other option is to use the pygame.event module. Use pygame.time.set_timer() to repeatedly create a USEREVENT in the event queue. The time has to be set in milliseconds. e.g.:
object_list = []
time_interval = 500 # 500 milliseconds == 0.1 seconds
timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, time_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.
Receive the event in the event loop:
while run:
for event in pygame.event.get():
if event.type == timer_event:
object_list.append(Object())
The timer event can be stopped by passing 0 to the time argument of pygame.time.set_timer.
Minimal example:
repl.it/#Rabbid76/PyGame-TimerEventSpawn
import pygame, random
pygame.init()
window = pygame.display.set_mode((300, 300))
class Object:
def __init__(self):
self.radius = 50
self.x = random.randrange(self.radius, window.get_width()-self.radius)
self.y = random.randrange(self.radius, window.get_height()-self.radius)
self.color = pygame.Color(0)
self.color.hsla = (random.randrange(0, 360), 100, 50, 100)
object_list = []
time_interval = 200 # 200 milliseconds == 0.2 seconds
timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, time_interval)
run = True
clock = pygame.time.Clock()
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == timer_event:
object_list.append(Object())
window.fill(0)
for object in object_list[:]:
pygame.draw.circle(window, object.color, (object.x, object.y), round(object.radius))
object.radius -= 0.2
if object.radius < 1:
object_list.remove(object)
pygame.display.flip()
pygame.quit()
exit()

Pygame fade to black function

I'm coding a game in python 3 using pygame latest version. I have a function that is intended to slowly fade the screen until it is totally black. It should do so by blitting a low-alpha black surface many times on the screen.
But when I test it, it only blocks the game until the loop is finished. I suspect a problem with the alpha of black_surface.
I've seen some questions on forums about fade in pygame, but none of them concerned fade directly in functions.
Here is the code:
def fade_to_black(screen):
black_surface = Surface((screen.get_width(), screen.get_height()), flags= SRCALPHA)
color = (255, 255, 255, 1)
black_surface.fill(color)
alpha_key = 1
while alpha_key <= 255:
screen.blit(black_surface, screen.get_rect())
display.flip()
alpha_key = alpha_key + 1
time.wait(1)
I have looked in documentation and forums but can't find any solution. Hope it isn't an obvious issue I would have missed... Thanks for the help!
You create a surface called black_surface, but you fill it with white. Fill it with black (eg. (0, 0, 0, 1)) and may work, but there's another problem:
When you call display.flip() inside a loop where you change the screen surface, the display may not actually update if you don't let pygame handle events (e.g. by calling pygame.event.get()), depending on your OS. Also, while your loop runs, you can't handle events manually, e.g. the QUIT event. So while your screen fades to black, you can't quit your game.
Generally, you should only have one main loop and not call blocking functions like pygame.time.sleep, but there are exceptions, of course).
Here's simple Sprite-based example:
import pygame
class Fade(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.rect = pygame.display.get_surface().get_rect()
self.image = pygame.Surface(self.rect.size, flags=pygame.SRCALPHA)
self.alpha = 0
self.direction = 1
def update(self, events):
self.image.fill((0, 0, 0, self.alpha))
self.alpha += self.direction
if self.alpha > 255 or self.alpha < 0:
self.direction *= -1
self.alpha += self.direction
def main():
pygame.init()
screen = pygame.display.set_mode((500, 500))
sprites = pygame.sprite.Group(Fade())
clock = pygame.time.Clock()
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
sprites.update(events)
screen.fill((30, 30, 30))
pygame.draw.rect(screen, pygame.Color('dodgerblue'), (100, 100, 100, 100))
sprites.draw(screen)
pygame.display.update()
clock.tick(60)
if __name__ == '__main__':
main()

How to do a PyGame countdown without overlaps? [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 is not displaying a grid or fps counter

I am trying to make a rpg but i always get the issue when pygame dose not display I am using a youtube video to help my make this rpg but Its just not working the creator made a color module to help but it just dose not work I know there are better ways of making a fps counter feel free to improve it
import pygame, sys, time
from Scripts.UltraColor import *
pygame.init()
cSec = 0
cFrame = 0
FPS = 0
tile_size = 32
fps_font = pygame.font.Font("C:\\Windows\\Fonts\\Verdana.ttf", 20)
def show_fps():
fps_overlay = fps_font.render(str(FPS), True, Color.Goldenrod)
window.blit(fps_overlay, (0,0))
def create_window():
global window, window_height, window_width, window_title
window_width, window_hight = 800, 600
window_title = "RPG"
pygame.display.set_caption(window_title)
window = pygame.display.set_mode((window_width, window_hight), pygame.HWSURFACE|pygame.DOUBLEBUF)
def count_fps():
global cSec, cFrame, FPS
if cSec == time.strftime("%S"):
cFrame += 1
else:
FPS = cFrame
cFrame = 0
cSec = time.strftime("%S")
create_window()
isRunning = True
while isRunning:
for event in pygame.event.get():
if event.type == pygame.QUIT:
isRunning = False
# LOGIC
count_fps()
# Render Graphics
window.fill(Color.Black)
# - Render Sinple Terrain Grid
for x in range(0, 640, tile_size):
for y in range(0, 480, tile_size):
pygame.draw.rect(window, Color.White, (x, y, tile_size + 1, tile_size + 1), 1)
show_fps()
pygame.display.update
pygame.quit()
sys.exit()
You need to add parentheses behind pygame.display.update to call this function and update the display: pygame.display.update()
I also recommend to use a pygame.time.Clock to limit the frame rate and get the fps. Calling clock.tick(FPS) makes sure that the game doesn't run faster than this frame rate. In the show_fps function you can just call clock.get_fps() to get the current frame rate.
import pygame
def show_fps(window, clock):
fps_overlay = FPS_FONT.render(str(clock.get_fps()), True, GOLDENROD)
window.blit(fps_overlay, (0, 0))
pygame.init()
FPS_FONT = pygame.font.SysFont("Verdana", 20)
GOLDENROD = pygame.Color("goldenrod")
tile_size = 32
window = pygame.display.set_mode((800, 600), pygame.HWSURFACE|pygame.DOUBLEBUF)
clock = pygame.time.Clock()
FPS = 60
isRunning = True
while isRunning:
for event in pygame.event.get():
if event.type == pygame.QUIT:
isRunning = False
# Render Graphics
window.fill((50, 50, 50))
# Render Simple Terrain Grid
for x in range(0, 640, tile_size):
for y in range(0, 480, tile_size):
pygame.draw.rect(
window, (255, 255, 255),
(x, y, tile_size+1, tile_size+1), 1)
show_fps(window, clock)
clock.tick(FPS)
pygame.display.update()
pygame.quit()

Python /Pygame blitting multiple image to list coordinates

So i'm making a space game where you have a open world to explore (A black Screen)
and i wanna create planets(Blit images to screen) around the universe(from a list).
This is my code currently
star = pygame.image.load("star.png")
planets = random.randrange(100,500) #<------#####NOT IMPORTANT#######
positions = [(300,50),(400,27),(900,55)] #<------
position = ()
positions has coorinates where images should be blitted
but when i blit them
for position in positions:
ikkuna.blit(star, position)
it blits the first one or nothing and does not crash
why?
################################################-
Here is the full code if it helps (there is bits of the finish language in there hope it does not bother)
"ikkuna = screen (leveys,korkeus) = (width,hight) toiminnassa = in action"
import pygame
import random
import time
import sys
import math
pygame.init()
White = (255,255,255)
red = (255,0,0)
kello = pygame.time.Clock()
star = pygame.image.load("star.png")
planets = random.randrange(100,500)
positions = [(300,50)]
position = ()
tausta_vari = (255,255,255)
(leveys, korkeus) = (1000, 1000)
ikkuna = pygame.display.set_mode((leveys, korkeus))
pygame.display.set_caption("SpaceGenerationTest")
######################################################################
toiminnassa = True
while toiminnassa:
for event in pygame.event.get():
if event.type == pygame.QUIT:
toiminnassa = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_g:
print("Generating World....")
print(planets)
for position in positions:
ikkuna.blit(star, position)
print("hello")
There's some problems with your code:
Your not updating the display, which means that all your changes won't be visible. Use pygame.display.update() or pygame.display.flip() at the end of the game loop to update the screen.
When you're mixing English and Finnish it becomes very inconsistent and hard to follow, especially for people who don't speak Finnish. Try to use English, even when you're just practicing.
Your full example only contain one position in the list, thus it's only creating one star at one position.
Pressing the 'g'-key won't generate any planets. You might want to introduce a boolean variable like in the example below.
I changed your code to english and made some adjustment so it's more consistent.
import pygame
import random
pygame.init()
WHITE = (255, 255, 255)
RED = (255, 0, 0)
# I changed the background color to black, because I understood it as that is what you want.
BACKGROUND_COLOR = (0, 0, 0) # tausta_vari
clock = pygame.time.Clock() # kello
star = pygame.Surface((32, 32))
star.fill((255, 255, 255))
planets = random.randrange(100, 500)
positions = [(300, 50), (400, 27), (900, 55)]
WIDTH, HEIGHT = (1000, 1000) # (leveys, korkeus)
screen = pygame.display.set_mode((WIDTH, HEIGHT)) # ikkuna
pygame.display.set_caption("SpaceGenerationTest")
display_stars = False
running = True # toiminnassa
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_g:
print("Generating World....")
print(planets)
display_stars = True
screen.fill(BACKGROUND_COLOR)
if display_stars:
for position in positions:
# This will create 3 stars because there're 3 elements in the list positions.
# To create more stars you'll need to add more in the list positions.
screen.blit(star, position)
pygame.display.update()
Your blitting all your images to the exact same position: positions = [(300, 50)], so the last image covers all the other images up. Also, you may not know this, but to display anything in pygame you have to either call pygame.display.flip() or pygame.display.update() after you finish drawing. I made a few revisions to your code, so the stars should show-up:
import pygame
import random
import time
import sys
import math
def main():
pygame.init()
White = (255,255,255)
red = (255,0,0)
kello = pygame.time.Clock()
star = pygame.image.load("star.png")
planets = random.randrange(100,500)
positions = [(300,50), (310, 60), (320, 80), (607, 451), (345, 231)]
tausta_vari = (255,255,255)
(leveys, korkeus) = (1000, 1000)
ikkuna = pygame.display.set_mode((leveys, korkeus))
pygame.display.set_caption("SpaceGenerationTest")
######################################################################
toiminnassa = True
while toiminnassa:
for event in pygame.event.get():
if event.type == pygame.QUIT:
toiminnassa = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_g:
print("Generating World....")
print(planets)
ikkuna.fill((0, 0, 0)) # fill the screen with black
for position in positions:
ikkuna.blit(star, position)
print("Hello")
pygame.display.flip() # updating the screen
if __name__ == '__main__': # are we running this .py file as the main program?
try:
main()
finally:
pg.quit()
quit()
~Mr.Python

Resources