I'm working with pygame on a graphical application, involving some video computation, and mouse events listening. I'm using a raspberry 3, raspbian jessie and python2.7.
As the title said : i'm loosing some mouse events, especially when the CPU load is high. I managed to reproduce this behavior in this small exemple :
import pygame
import time
pygame.init()
pygame.display.set_caption('Crash!')
window = pygame.display.set_mode((300, 300))
running = True
Rectplace = pygame.draw.rect(window, (255, 0, 0),(100, 100, 100, 100))
pygame.display.update()
while running:
time.sleep(0.1)
for event in pygame.event.get():
print(`event`)
if event.type == pygame.QUIT:
running = False
When running this script, most of the mouse wheel events (buttons 4&5) are discarded on fast roll. Removing the time.sleep(0.1),that simulate CPU load, make the event listener perfectly reliable.
As i can't remove the slow computation part, nor optimize it more, what should i do to get back these events ?
Thank you for sharing your brains !
My guess is that pygame use a limited size circular event queue. When full, each new event replaces the oldest event. If you get more events than you can ever handle, then let them go, as you will have to discard them anyway.
If you have sporadic slow computations, so that catching up may be feasible, then you must break up the computation into pieces short enough in time that you can get events before the default queue is full. When you get them, either process immediately or put into a larger catch_up queue. The best way to do that depends on the details of the code.
Or investigate the suggested thread solution.
Related
I am writing a game using Pygame. When the game window opens, I currently only have the program call pygame.display.update after the game has changed something that shows on the screen. That works fine for limiting screen refreshes to only when necessary. I have discovered a side effect of moving the game window that causes the screen to get corrupted, which requires the program to force a refresh even if the program itself doesn't require one.
My question is if there is a pygame event (I didn't see one) or something else, that I can use to force the game to refresh the screen after a window move.
Okay, I happened across a code snippet that reports events to the console here:
http://www.poketcode.com/en/pygame/events/index.html
Running this was useful because I noticed that every time I moved the window partially off-screen, pygame triggered a VideoExpose event when the window area moved back on screen.
So, I added the following bit of code to my event loop and it worked great!:
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.VIDEOEXPOSE:
game.update_panels(force=True)
game.update_panels(force=False)
I'm writing a real-time interactive graphics application using SDL2 and OpenGL in Python (pysdl2, PyOpenGL). The application continuously produces frames, which may change in response to keyboard / mouse input or based on time.
My main event loop, copied from some obscure source on the web that I can't find again, looks (simplified) like this:
event = sdl2.SDL_Event()
running = True
while running:
# process events
while sdl2.SDL_PollEvent(ctypes.byref(event)) != 0:
if event.type == sdl2.SDL_QUIT:
running = False
# render frame
<some OpenGL commands>
sdl2.SDL_GL_SwapWindow(window)
sdl2.SDL_Delay(10)
From what I understand, the delay of 10 ms is intended to give the CPU some breathing room, and indeed, when I remove it the CPU usage doubles.
What I don't understand is why it is necessary. The graphics display is double buffered and buffer swaps are synchronized with the vertical retrace (60 Hz = 16 ms). Naively one would expect that if <some OpenGL commands> take less than 16 ms, then SDL_GL_SwapWindow will introduce a delay anyway, so SDL_Delay is not necessary. And if they use more than that, then the program is struggling to keep up with the display framerate, and introducing a delay would hurt.
Now from what I've been told in response to another question, the buffer swap and therefore the retrace synchronization doesn't happen when the SDL_GL_SwapWindow is executed, but this only puts a "sync & swap" instruction into an OpenGL queue, and this instruction gets executed when everything before has finished. The same holds for <some OpenGL commands>. But this instruction queue is finite, and therefore at some point my program, instead of waiting for the retrace, will wait for there to be space in the instruction queue. The end effect should be the same: If one execution of my event loop needs on average less than 16 ms, then the program will on average delay long enough to make it 16 ms per loop execution. So again, why is the explicit delay necessary?
As a second question: Considering the delay might hurt the framerate, is there a better way to let the CPU rest?
You don't need use sdl2.SDL_Delay(10) because SDL_Delay is timer for SDL2 framework if you use event-loop then it doesn't need with SDL_Delay.
My code for Python 3.10 looks example with KeyPress and Close window by mouse click
event = sdl2.SDL_Event()
running = True
while running:
while sdl2.SDL_PollEvent(ctypes.byref(event)) != 0:
if event.type == sdl2.SDL_QUIT:
running = False
if event.type == sdl2.SDL_KEYDOWN:
if event.key.keysym.sym == sdl2.SDLK_ESCAPE:
running = False
... GL Functions ...
sdl2.SDL_GL_SwapWindow(window)
Remember that event-loop should like other in C/C++,. Java, C# or other programming langauges.
Without event-loop means
you should use SDL_Delay() then game window will close automacally.
I hope you understand - I found Python examples but they look like weird and wrong - they write like "Latin".
I would like to improve who understands better like other programming languages.
PS: I will work hard my github with clear examples :)
I've been using pygame inside a conda environment. The installation went well, but whenever I call flip, it doesn't open any window from the terminal.
Here's the code that's supposed to open the window:
screen.blit(background_image, (0, 0))
pygame.display.flip()
pygame.display.update()
After pygame starts, it shows this message:
WARNING: 140: This application, or a library it uses, is using the
deprecated Carbon Component Manager for hosting Audio Units. Support
for this will be removed in a future release. Also, this makes the
host incompatible with version 3 audio units. Please transition to the
API's in AudioComponent.h.
Here's the entire code.
It's a sudoku game that should display a board with Sudoku being solved.
(This answer is not directed to the original question but to anyone who might have the same problem)
In the game loop you have to process/check events so that pygame knows your game hasn't crashed:
screen = pygame.display.set_mode((1000, 500))
while True:
for event in pygame.event.get():
# process events
# Update your sprites
pygame.display.update()
I'm trying to make a day/night feature for my game where every 10 minutes the background changes, but when I run it it just crashes on startup. Here's the buggy code.
bg = pygame.image.load("bg.png")
bgg = pygame.image.load("bbg.png")
def bg1():
screen.blit(bg, (0, 0))
def bbg1():
screen.blit(bbg, (0, 0))
def fbg():
bg1()
pygame.time.wait(10000)
bbg1()
screen.fill((0,0,0))
fbg()
I have the screen.fill((0,0,0)) because there is a rect there as well which moves around.
Your problem is that the pygame.time.wait call just stops the execution of the current thread for 10,000 milliseconds. You need to have another thread that actually runs the game.
The documentation states that:
pygame.time.wait()
Will pause for a given number of milliseconds. This function sleeps the process to share the processor with other programs. A program that waits for even a few milliseconds will consume very little processor time. It is slightly less accurate than the pygame.time.delay() function.
I recently startet getting into pyglet and rabbyt from pygame, but I have hit something of a brick wall.
I created a basic example where one Sprite (of the type found in pyglet.sprite.Sprite) is displayed at 60 frames per second. The problem is that this simple program is using up 50% of the CPU time somehow. I repeated the experiment with the sprite type found in the rabbyt library with the same result.
I decided to render 1000, then 10 000 sprites at 60 frames per second, and to my surprise the CPU usage stays at 50%. The only thing is that moving or animating a sprite results in slight stuttering.
Lastly, I tried running at 360 frames per second. Same result, 50% usage.
Here is the sample code:
import pyglet
import rabbyt
def on_draw(dt):
window.clear()
spr.render()
global window
window = pyglet.window.Window(800, 600)
spr = rabbyt.Sprite('ship.png')
spr.x = 100
spr.y = 100
pyglet.clock.schedule_interval(on_draw, 1.0/60.0)
if __name__ == '__main__':
pyglet.app.run()
I am using a Core 2 Duo with an ATI HD 3500 card.
Any advice/ideas are appreciated.
Be aware that the default pyglet event handler will fire an 'on_draw' event every time it clears the event queue.
http://www.pyglet.org/doc/programming_guide/the_application_event_loop.html
The pyglet application event loop dispatches window events (such as for mouse and keyboard input) as they occur and dispatches the on_draw event to each window after every iteration through the loop.
This means that any event can trigger a redraw.
So if you're moving the mouse about or doing anything that fires events, you will get massive slow down as it begins to trigger render calls.
This also caused problems because I was doing my own render calls, so I would get the two buffers fighting which created a 'ghost' effect on the screen. Took me a while to realise this was the cause.
I monkey patched the event loop to not do this.
https://github.com/adamlwgriffiths/PyGLy/blob/master/pygly/monkey_patch.py
Be aware that this patched event loop will no longer render on it's own, you must manually flip the buffers or trigger an 'on_draw' event.
It might be the case that, although you've hooked in at 60fps, but the internal render loop is ticking at the maximum possible rate.
I dislike code that takes away control, hence my patch lets me decide when render events occur.
Hmm.. You might want to know the fps at which the game runs, if it helps:
cldis = pyglet.clock.ClockDisplay()
Then add this to your on_draw function:
cldis.draw()
it draws the current fps at the bottomleft corner of the screen in a semi-transparent color.
I know that in Pygame there is the built-in called "Clock". You can put a limit on how many times the game loops per second using the tick method. In my example I have put a limit of 30 FPS. This prevents your CPU being on constant demand.
clock = pygame.time.Clock()
While 1:
clock.tick(30) # Puts a limit of 30 frames per second on the loop
In pyglet there appears to be something similar:
pyglet.clock.schedule_interval(on_draw, 1.0/60.0)
clock.set_fps_limit(60)
Hope that helps!
edit: documentation on fps limit: http://pyglet.org/doc/api/pyglet.clock-module.html#set_fps_limit