I am unable to close out the game window after insertion of pygame.time.wait(1000) in my main game loop, for example:
while True:
ev = pygame.event.wait()
if ev.type == pygame.QUIT:
break
...
pygame.display.update()
pygame.time.wait(1000)
what is the issue here and is there any work around?
Problem is because 1000ms is 1s and it is long time for program. At this time program doesn't check pygame.event so it can't break mainloop (while True) and you can't quit - better use smaller value - 100ms (0.1s) or smaller.
If you use 40ms it gives you 1000ms/40ms = 25 FPS (Frames Per Seconds)
You can use Clock() to set FPS more precisely
clock = pygame.time.Clock()
# mainloop
clock.tick(25)
Related
I am practicing on pygame and I was wondering how can we do so that the framerate does not affect the speed of execution of the game
I would like FPS to not be locked and the game to always run at the same speed.
Until now I used the pygame.time.Clock.tick function but the speed of the character was changing depending on the number of FPS, which I don't want.
You have to calculate the movement per frame depending on the frame rate.
pygame.time.Clock.tick returns the number of milliseconds since the last call. When you call it in the application loop, this is the number of milliseconds that have passed since the last frame. Multiply the objects speed by the elapsed time per frame to get constant movement regardless of FPS.
For instance define the distance in number of pixel, which the player should move per second (move_per_second). Then compute the distance per frame in the application loop:
move_per_second = 500
FPS = 60
run = True
clock = pygame.time.Clock()
while run:
ms_frame = clock .tick(FPS)
move_per_frame = move_per_second * ms_frame / 1000
# [...]
This simple piece of code crashes (the window is not responding) after a few seconds (around 5).
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 24)
#clock = pygame.time.Clock()
#font = pygame.font.Font(None, 32)
cycles = 0
while True:
screen.fill(0)
# text = font.render('Cycles : %d' % cycles, True, (255, 255, 255))
# screen.blit(text, (100, 100))
cycles += 1
pygame.display.update()
If I uncomment the commented lines, I can clearly see the program going out of control when displaying values between 47 and 50.
I use python 2.7 and pygame 1.9.2, Windows 8 (64 bits) and Eclipse + PyDev.
Call pygame.event.get() at the beginning of the while loop.
You need to regularly make a call to one of four functions in the pygame.event module in order for pygame to internally interact with your OS. Otherwise the OS will think your game has crashed. So make sure you call one of these:
pygame.event.get() returns a list of all events currently in the event queue.
pygame.event.poll() returns a single event from the event queue or pygame.NOEVENT if the queue is empty.
pygame.event.wait() returns a single event from the event queue or waits until an event can be returned.
pygame.event.pump() allows pygame to handle internal actions. Useful when you don't want to handle events from the event queue.
The window does not respond (freeze), because you do not handle the events. You have to handle the events by either pygame.event.pump() or pygame.event.get(), to keep the window responding.
See the documentation of pygame.event.pump():
For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.
Add an event loop, for instance:
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# [...]
Alternatively just pump the events:
while True:
pygame.event.pump()
# [...]
Minimal example: repl.it/#Rabbid76/PyGame-MinimalApplicationLoop
I have a simple Pygame program:
#!/usr/bin/env python
import pygame
from pygame.locals import *
pygame.init()
win = pygame.display.set_mode((400,400))
pygame.display.set_caption("My first game")
But every time I try to run it, I get this:
pygame 2.0.0 (SDL 2.0.12, python 3.8.3)
Hello from the pygame community. https://www.pygame.org/contribute.html
And then nothing happens.
Why I can't run this program?
Your application works well. However, you haven't implemented an application loop:
import pygame
from pygame.locals import *
pygame.init()
win = pygame.display.set_mode((400,400))
pygame.display.set_caption("My first game")
clock = pygame.time.Clock()
run = True
while run:
# handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# update game objects
# [...]
# clear display
win.fill((0, 0, 0))
# draw game objects
# [...]
# update display
pygame.display.flip()
# limit frames per second
clock.tick(60)
pygame.quit()
The typical PyGame application loop has to:
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
limit frames per second to limit CPU usage with pygame.time.Clock.tick
repl.it/#Rabbid76/PyGame-MinimalApplicationLoop See also Event and application loop
This is interesting. Computer read your program line by line[python]. When all the line are interpreted, the program closed. To solve this problem you need to add a while loop to make sure the program will continue until you close the program.
import pygame,sys
from pygame.locals import *
pygame.init()
pygame.display.set_caption("My first game")
win = pygame.display.set_mode((400,400))
#game loop keeps the game running until you exit the game.
game_running=True
while game_running:
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
win.fill((0, 250, 154)) #Fill the pygame window with specific color. You can use hex or rgb color
pygame.display.update() #Refresh the pygame window
You can check more pygame Examples.
https://github.com/01one/Pygame-Examples
I think this will be helpful.
in the experiment I am preparing sounds are played from a csv file and timing is measured in frames. Given the fact that each sound lasts 300ms this equals to 18 frames.
from psychopy import data
from psychopy import core, visual, gui, data, event
from psychopy.tools.filetools import fromFile, toFile
import numpy, random, csv, time
from psychopy import logging, prefs
prefs.general['audioLib'] = ['pyo'] # Set the Audio Library [pyo (highest performer, check it), sounddevice (looks promessing, check it) or pygame (not good with timing)]
prefs.general['audioDriver']=['coreaudio']
from psychopy import sound
win = visual.Window([400,300], monitor="testMonitor", units="cm", fullscr=False)
stimuli = []
datafile = open("audioStim.csv", "rb")
reader = csv.reader(datafile, delimiter=";")
for row in reader:
stimuli.append(row[0])
#print (stimuli)
datafile.close()
clock = core.Clock()
for stimulus in stimuli:
#print (stimuli)
for frameN in range(18):
#print clock.getTime()
sound_stimulus = sound.Sound(stimulus)
sound_stimulus.play()
win.callOnFlip(clock.reset)
win.flip()
## Closing Section
win.close()
core.quit()
When running the experiment the sounds seem to blend with each other. They do not sound discrete.
The result is a bit problematic, is this an issue with Psychopy (not good quality when sounds are so short?) or with the code?
Thank you for your time!
Any other recommendations or suggestions for improvement of the code are very welcome.
Your code starts playing a sound on each frame, i.e., 60 times a second. Do this:
for stimulus in stimuli:
#print (stimuli)
for frameN in range(18):
#print clock.getTime()
win.flip()
if frameN == 0:
sound_stimulus = sound.Sound(stimulus)
sound_stimulus.play()
clock.reset() # Time zero is stimulus onset
I did two things here. First, I only start the sound_stimulus.play() and clock.reset() at flip onset only - not at subsequent updatings. Second, I started the sound AFTER win.flip so that it is timed to the flip. If you play before the flip, the sound can start can be anywhere in the 16.7 ms interval (but probably only will be for the very first trial).
BTW, since you don't really use the variable sound_stimulus, you could simplify the code even further:
if frameN == 0:
sound.Sound(stimulus).play()
I'm having trouble achieving frame rate independent motion in AS3 at 60fps. Every frame I measure the time since the previous frame, add it to an accumulator, and if the accumulator is greater than my target time, which is 16.666ms (60fps), a frame is simulated.
The problem is that the AS3 getTimer() only returns a time in milliseconds.
The delta times I get are often 16ms for the first frame, 16ms for the second, then 18ms for the third, and this pattern repeats. This averages out to 16.666. But in the first frame it is lower than the target time (16 < 16.666), so no frame is simulated. In the second frame the accumulator is higher than the target time, but slightly less than double it, so one frame is simulated. For the third frame 18ms pushes the accumulator over double the target time, so two frames are simulated.
So I'm getting this very jerky motion where no frames are rendered, then one, then two, then none, then one, then two, and this continues.
How would I get around this?
Wow... I thought I was only one who found that out.
Yes, the timer class in AS3 is not accurate. It will only trigger every ~16ms which causes MAJOR issues at times.
If want to see 2048 actions in 1000ms: FlashText Markup Language
(To test this, you'll need a method which takes 1ms to execute - just for even stats)
Notice the difference:
CORRECT: 1000ms | timer=0 == 1000 actions
AS3: 1000ms | timer=0 == 62.5 actions
I was able to write a class that works like this:
CORRECT: 1000ms | timer=0 == 1000 actions
RESHAPE TIMER: 1000ms | timer=0 == 1024 actions
NOTE:
it DOES NOT fire an action every ms
it DOES catch up to actions between the 16ms interval
an ACTION (the way I use it) is a method call, each method call can have its own body
The methodology I used to create this was catch-up... basically the first timer event will fire at 16ms... we know we have a full 16ms worth of code time to fire our own actions before the timer class fires again - thats where you inject sub-actions...
The highest I was able to produce was 2048 actions in 1000ms... more than 2 actions per ms.
Now... back to your problem
There is NO WAY to trigger a 0ms timer event. Based on my solution, if you want to by-pass the first 16ms of lag before the timer fires... you can dispatch an event which will fire within 2ms depending on the current system processes.
Possible Solution
If you take my approach for throwing your own actions within the 16ms, then you can build your own timer class. Use events for times under 16ms, when fired... fire 15 more - lol. Basically, you can create your own deltas between the 16ms.