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
Related
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 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)
I'm making a game with pygame and I encountered a problem with the following code :
while not self.end: # main game loop
keys = pygame.key.get_pressed()
if keys[K_LEFT]:
adddirection(LEFT)
elif keys[K_RIGHT]:
adddirection(RIGHT)
elif keys[K_UP]:
adddirection(UP)
elif keys[K_DOWN]:
adddirection(DOWN)
When I hold TOP arrow or DOWN arrow, if I press any right or left key, nothing will happen, the elif does not resolves. Why ? Should I do this another way ?
If I replace all the 'elif' by 'if' the opposite happens. If I hold left or right, top and down will never resolves.
I would like to understand that weird mechanic.
The code would be like
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if (event.key == K_LEFT):
//
elif (event.key == K_RIGHT):
//
elif (event.key == K_UP):
//
elif (event.key == K_DOWN):
//
keys_pressed = key.get_pressed()
if keys_pressed[K_LEFT]:
//
if keys_pressed[K_RIGHT]:
if keys_pressed[K_UP]:
//
if keys_pressed[K_DOWN]:
//
Replace // with your condtions
So, as per the nature of elif stacks, if one resolves as true, it wont test the others and simply skip, loop up how if elif else works online somewhere.
so you need to either use "if" for each, or split it in to a for loop.
However since you say when you use if for all of them, you still don't get your expected behaviour. I suspect this could be caused by "adddirection()", could you post that too if you cannot solve this issue?
As is mentioned in another answer, you can also use pygame events to deal with keypresses
The problem may be unsolvable. The way keyboards work is every key sends a signal on a copper wire through the USB cable. Mechanical (gaming) keyboards have a copper wire for each key, however to reduce the cost of cheap keyboards, many keys share a wire, and as a result only one of the keys which share a wire can be pressed at once. The arrow keys are on the same wire which may be contributing to your issue. The reason WASD is generally used for movement in games is because the 4 keys run along different wires.
TLDR: You may have better luck using WASD instead of your arrow keys
Im looking for some comparison between ENTER_FRAME and TIMER methods when using them for an update method. I have looked around the internet for some answers but I'm still finding it hard to understand.
Would anyone be able to help with simplifying the different between them?
Timer events can dispatch independent of the framerate of the swf (to a point). They can happen more often or less often than an ENTER_FRAME event, and should be used if you care about the precision of calculations as they happen between the span of time covered by ENTER_FRAME. The most common use case for this is a physics engine, where you may want to be as precise as possible and therefore wish to perform your simulation at a rate faster than Flash's fps.
Also, timers can be useful if you want a specific action to occur after a given delay. For example, a Timer lets you perform an action after 10 seconds easily. You simply pass 10000 milliseconds into your Timer's constructor and then the Timer event will be dispatched 10 seconds later. If you were to use ENTER_FRAME you would need to manually track the time elapsed on every frame update if you wanted to know when 10 seconds had passed.
ENTER_FRAME events are tied to the rendering cycle of the timeline and more or less match the framerate you've specified. For instance, if you have a framerate of 30fps then you'll receive approximately 30 ENTER_FRAME events per second. You may receive fewer if you have a particularly complex display list, or if your logic takes a particularly long time to execute.
"enterFrame" is dispatched on every frame.
Suppose your SWF is 24fps: "enterFrame" will be dispatched up to 24 times every second.
"timer" is dispatched at a set interval.
Suppose you start a Timer with a delay of 50 milliseconds: "timer" will be dispatched up to 20 times every second.
The actual frequency of these events will depend on the host environment as well as what's going on inside your application. For example, if you have a for loop inside your "timer" handler where you're iterating over a 1,000-element array and performing some string manipulation on each element, then you'll likely get fewer "timer" events than if your array contained only 10 elements. Likewise, if the user's system is low on free memory, then Flash Player may have trouble executing your SWF and it might slow down the rate at which these events are dispatched.
"enterFrame" depends directly on the frame rate. "timer" depends somewhat indirectly on the frame rate.
Because you (or someone else) will invariably ask what I mean by "somewhat indirectly," here's a small AS3 app that tests both events:
package
{
import flash.display.*;
import flash.events.*;
import flash.utils.*;
public class Test extends Sprite
{
private var timer:Timer = null;
private var timerEventCount:int = 0;
private var enterFrameEventCount:int = 0;
private var startTime:Number = 0;
public function Test()
{
timer = new Timer(20, 0);
timer.addEventListener("timer", timerHandler);
timer.start();
addEventListener("enterFrame", enterFrameHandler);
startTime = new Date().time;
}
private function timerHandler(event:Event):void
{
timerEventCount++;
var timeElapsed:Number = new Date().time - startTime;
//for (var i:int = 0; i < 4000; i++)
// trace("i", i);
if (timeElapsed >= 1000) {
// Stop timer after 1 second.
timer.stop();
removeEventListener("enterFrame", enterFrameHandler);
trace(timerEventCount + " timer events and "
+ enterFrameEventCount + " enterFrame events in "
+ timeElapsed + " milliseconds.");
}
}
private function enterFrameHandler(event:Event):void
{
enterFrameEventCount++;
}
}
}
Compile at 12fps:
mxmlc Test.as -default-frame-rate=12
Output:
45 timer events and 12 enterFrame events in 1001 milliseconds.
Compile at 60fps:
mxmlc Test.as -default-frame-rate=60
Output:
29 timer events and 58 enterFrame events in 1010 milliseconds.
As you can see, a higher frame rate actually slows down the timer. I'm running this in Flash Player Debugger 10.3.181.34 (10.3); your mileage may vary.
Finally, if you uncomment the for loop and run it again with 60fps, you'll see what I'm talking about.
Output:
3 timer events and 3 enterFrame events in 1145 milliseconds.
ENTER_FRAME is an event that is triggered every time the render loop of the virtual machine runs and this is relative to the framerate of the movie. For example, in the Flash CS IDE if you set the framerate to 30, then from the root display object or stage, 30 ENTER_FRAME events will be fired every second.
A timer on the other hand is just that, a timer. It runs solely based on the system clock time. For example, if you set a timer with a delay of 1 millisecond, then that timer will fire one millisecond after being started, and will continue to fire once every single millisecond if you enable it. What I think camus was trying to say in his answer is that this process runs independent of the framerate. It's based solely on checking the system clock and triggering events for timers that have had the requested delay satisfied. This is verified internally by storing the system time at which the timer was started and then checking the current system time repeatedly until it is greater than or equal to the saved time PLUS the timers delay. Example:
timer.start() //Lets say current system time is 1000
Timer duration is 1000, so we need to trigger this timer when the system time is greater than or equal to 2000.
checkTimers() //Loops, gets the current system
//If system time is greater than or equal to 2000, trigger timer with an event
dispatchEvent(Timer.TIME, etc, etc);
Note that the above "code" is just pseudo code to demonstrate the basic principles of the system.
ENTER_FRAME is relative to the movie's frame rate . TIMER events should be absolute.