Pyglet application framerate appears to speed up each time it is restarted - python

I am working on a basic simulation in pyglet, which I need to re-run and visualise multiple times. The simulation adjusts the focus "f" of a lens until it reaches the desired location (see gif here https://imgur.com/Ui06B1c). I have put an instance of the simulation inside a for loop along with a pyglet.app.run() loop running inside it also, so that it can be reset and run for 10 episodes.
num_episodes=10
for i in range(num_episodes):
update_rate=1/59
simulation=PivotPointSimulation()
pyglet.clock.schedule_interval(update, update_rate)
pyglet.app.run()
I need to make an instance of the "simulation" so that the draw and update methods can be called by pyglet.app.run(). By making a new instance each loop, I can also reset the variables when the simulation starts again. I terminate the simulation when the focus "f" of the lens reaches the desired position with pyglet.app.exit().
The problem is each time the for loop iterates, the framerate of my pyglet application speeds up (see gif for example https://imgur.com/Ui06B1c). I have checked if the update_rate is changing and it is staying the same. Peculiarly enough, when I use spyders stop button to stop the code, and run the simulation again with "play" the framerate of the simulation also gets faster and faster each time I hit stop and play.
I am wondering if there is a way to properly terminate an app, so that each time it runs again it is reset fully? I am unsure if pyglet.app.exit() is resetting everything properly. But I am not sure how the app is speeding up, since pyglet.clock.schedule_interval(update, update_rate) should update at a constant update rate.
I have tried playing around with Vsync settings (setting from false to true) and it hasn't helped. I have also tried using pyglet.clock.set_fps_limit(60) to no avail. So I am not sure what is going on here.
Has anyone encountered this problem before?

Every time you call pyglet.clock.schedule_interval(update, update_rate), it adds the callback to be called at the rate.
So at the end of your loop of 10, you have the same callback scheduled ten times.
One way to prevent this is to unschedule the function before so that it isn't scheduled a second time:
num_episodes=10
for i in range(num_episodes):
update_rate=1/59
simulation=PivotPointSimulation()
pyglet.clock.unschedule(update)
pyglet.clock.schedule_interval(update, update_rate)
pyglet.app.run()

Related

Turtle graphics - screen updates with tracer not working as expected

I'm trying to put in scheduled refreshes for a pong game, so the screen updates after a time interval so the paddles (which I have segmented) move in sync on the screen. What is the functional difference between these two blocks of code? I was trying to get the first one to work but wasn't able to get it to do what I wanted but after some experimenting I landed at the second one which does:
pongscreen.tracer(0)
def balltiming():
pongscreen.update()
time.sleep(0.5)
balltiming()
balltiming()
pongscreen.listen()
pongscreen.mainloop()
This second one works, but functionally they seem pretty much the same in what they're doing. Why doesn't the first one work but this does?
pongscreen.tracer(0)
def balltiming():
pongscreen.update()
pongscreen.ontimer(balltiming, 300)
balltiming()
pongscreen.listen()
pongscreen.mainloop()
The first block is genuinely recursive, so it'll blow the call stack after ~1000 frames on a typical CPython implementation.
The second block isn't recursive; the initial balltiming function is completely cleared from the call stack after it sets an ontimer event. Turtle internally calls the next iteration of balltiming that has been registered as a callback to ontimer without unbounded stack growth.
If you want to use sleep manually, use a while loop rather than recursion. However, sleep blocks the thread and is less amenable to precise framerate control, so generally ontimer is used.
A consequence of the blocking recursive calls and sleep is that in the first code block, pongscreen.listen() and pongscreen.mainloop() won't be reached, while in the second version, both will be reached and the main thread will block at pongscreen.mainloop(); the typical flow for a turtle program.

Ignore keyboard event on waitKey() in OpenCV

I'm learning OpenCV and I decided to make a snake game using it. It's almost done but there is a slight problem that seems simple but I couldn't find a solution.
while True:
move()
cv2.imshow('Snake Game', frame)
cv2.waitKey(250)
It's supposed to wait 250 miliseconds before the next frame but key presses break the waiting so game speeds up when I hold down a key. How can I make it ignore the keyboard events and only use time?
I would be very surprised if waitKey didn't stop the waiting after key presses. In fact the name itself suggest that. So basically it's like calling a function called max and then expect the minimum.
From your code and what you've described, you're using waitKey for two reasons:
waiting for some fixed time. That means you're using it to synchronize your game loop.
using it (maybe) to handle key presses for user interaction with the game.
In my opinion, first thing to do is to stop waiting and just keep showing frames continuously as soon as it is ready. And for synchronization you just need to save time for each frame printing. And using that time you update after user interaction or deciding how to process frame or ... One place to help you in that is to look at how game loops are implemented.Take a look here : https://gamedev.stackexchange.com/questions/651/how-should-i-write-a-main-game-loop

wxPython -- drawing a line, relatively slowly

I want to draw a line, but not instantaneously as it usually appears with DrawLine(). I want it to be fast, but just slow enough that you can tell it's being drawn.
I've tried testing a for loop that draws a line a pixel at a time with a sleep of .05 seconds, but it doesn't seem to draw any of it until the for loop ends at which point it draws it all, instantly. I figured this had to do with it not getting drawing actions through the mainloop, so I used CallAfter on the drawline, that didn't work, either.
It seems like there should be a way to simply tell drawline to draw it over the course of x seconds or send it through an animation object in which you can specify # of frames, etc. Not really sure where to look. Any suggestions?
The issue is that time.sleep(...) will also block GUI as the for loop itself. wx.Yield should normally signal "GUI, I have halted the time-consuming process, do whatever you nned to do NOW". But by experience, this basically never works (I have not found out yet why).
So instead of using sleep you could use wx.CallLater (Link to wxPython Phoenix docs) which is like wx.CallAfter, but a delay can be specified. By calling it at the end of the inner for loop drawing the line part draw events should not pile up.
You will probably want to draw a series of lines. That would likely be the easiest. I would probably use a wx.Timer. It runs in it's own main loop. You can set up the timer to fire every so often, say every 0.5 second. When it fires, it can call your draw method, which will draw the next line. You can read more about timers here:
http://wiki.wxpython.org/Timer
http://www.blog.pythonlibrary.org/2009/08/25/wxpython-using-wx-timers/
http://www.wxpython.org/docs/api/wx.Timer-class.html

Pyglet uses too much cpu

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

How do I close a loading screen right when the other thread is finished in Python using Tk?

I have a Python GUI that uses Tkinter. I have to SSH into another place to get data. I start a new thread to do this so that the GUI doesn't hang. During this time, I want to pop up a screen that lets the user know it is loading. Once the program is finished getting the data, I want to close the loading screen. What must I do to have my main loop recognize that the thread is done? I've tried to use that thread to close the loading screen that exists in the main loop, but then I discovered that doesn't work.
I have seen some producer consumer models that don't use GUIs, and they have while loops. This doesn't help me though. I also don't want to download and install other packages, but imports are ok. Thank you for your help!
Have your thread set a flag when it is done. Have the GUI periodically check for that flag and dismiss the window when it is set.
You can check for the flag by creating a function that checks for the flag, and if it's not set it uses after to have itself run again a few hundred ms later. The window won't go away immediately after the thread exits, but as long as the lag isn't more than a couple hundred ms the user will never notice.

Categories