Claudio,
My problem is only related to long calculations on the same thread as
Pyglet, not garbage collection. The calculations are out of my
control, since it is user created AI game logic. The game is a non-
trivial graph problem, which cannot be solved in real-time and the
solution space is too large for computer memory. You can see an
example of a similar game here: http://paulsolt.com/projects/labyrinth/
Animation stuttering may not be the correct description. The blocking
calculation causes animation frames to be skipped in the beginning of
an animation sequence. This means that users do not see the full
animations if the time delta in the _step function is very large. My
current workaround is to skip updates if the time delta is above a
certain threshold.
Here's a sample output from the _step() function with the time deltas
before and after a long calculation.
dt: 0.0287780761719
dt: 0.0165908336639
Mouse Pressed: 323.0 , 265.0
Long Calc
Total Calc Time 1.05840206146
dt: 1.4731771946
dt: 0.00134301185608
dt: 0.0100548267365
By adding code to skip updates after a certain time delta (dt)
threshold, I can maintain smooth/full animations after the long
calculation is complete.
cocosnode.py Line 758
def _step(self, dt):
# HACK to prevent animation hiccups after a long calculation,
the first frame back will be a large
# time delta, which can cause animations to think they're
done, before the user has seen them.
print "dt:", dt
if dt > .05:
return
# Normal _step(self,dt): code
for x in self.to_remove:
if x in self.actions:
self.actions.remove( x )
self.to_remove = []
if self.skip_frame:
self.skip_frame = False
return
if len( self.actions ) == 0:
self.scheduled = False
pyglet.clock.unschedule( self._step )
for action in self.actions:
if not action.scheduled_to_remove:
action.step(dt)
if action.done():
self.remove_action( action )
Regards,
Paul Solt
[email protected]
http://www.paulsolt.com/
On Nov 29, 1:14 am, claudio canepa <[email protected]> wrote:
> On Mon, Nov 29, 2010 at 12:24 AM, Paul Solt <[email protected]> wrote:
> > Is there an easy way to use a background worker thread for the complex
> > calculations in cocos2d/pyglet? I would ideally like to do work off
>
> the GUI thread, but I am not sure on how to do it.
>
> > I have an issue with frames missing in animations if I perform complex
> > calculations before triggering an animation. I'm currently running
> > this code on Mac OS X 10.6.5. Here's the basic structure of the
> > offending code.
>
> > 1. Do complex calculation (~1 second to run)
> > 2. Animate result
>
> > I'm expecting the calculation to finish before invoking the animation,
> > but that's not the case.
>
> I'm sure the calculation finish before the animation starts, python is not a
> parallel language.
>
> > It appears that the animation starts soon
> > after the complex calculation starts.
>
> I think you see stuttering when the animation begins, and then you deduce
> the complex calculation has not ended
>
> > After performing a complex
>
> calculation the animation that follows will be missing frames of
>
> animation. It may skip or stutter before resuming normal animation
>
> speed.
>
>
>
> The stuttering can be produced by some aftereffects of the heavy
> calculations.
> I can think of two ways:
>
> 1. The complex calculation don't let pyglet get control for a long time.
> Pyglet tries to schedule itself to satisfy the desired framerate and
> schedule_interval requests, and tries to reduce the differences between
> desired calling times and real calling times. Probably the adaptive parts in
> pyglet.clock and pyglet.app get confused by the long time it was blocked and
> multiple messages waiting in the application queue, needing some frames
> after the calculation ends to stabilize.
> The basic solution would be to not block pyglet so much time.
>
> 2. Garbage collection. Less likely, but possible. If your complex
> calculation allocates lot of memory or a big number of objects, which are
> unreferenced after the calc terminates, a slow garbage collection can kick
> in.
>
>
>
>
>
> > Here's an example:
> > Key press = animation
> > Mouse press = calculation + animation
>
> > import sys
> > import os
> > sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
> > from time import time
> > import cocos
>
> > class HelloWorld(cocos.layer.Layer):
> > is_event_handler = True
>
> > def on_key_press (self, key, modifiers):
> > """This function is called when a key is pressed.
> > 'key' is a constant indicating which key was pressed.
> > 'modifiers' is a bitwise or of several constants indicating
> > which
> > modifiers are active at the time of the press (ctrl,
> > shift, capslock, etc.)
> > """
> > print "Key pressed:", key
>
> > #animate
> > self.label.do(cocos.actions.FadeIn(1) +
> > cocos.actions.RotateBy(360,1) +
> > cocos.actions.ScaleBy(2, 2) +
> > cocos.actions.ScaleBy(1/2.0, 1))
>
> > def calc(self):
> > print "Long Calc"
> > start = time()
> > for i in range(4000000):
> > j = i * 13743
> > end = time()
> > print "Total Calc Time", (end - start)
>
> > def on_mouse_press (self, x, y, buttons, modifiers):
> > """This function is called when any mouse button is pressed
>
> > (x, y) are the physical coordinates of the mouse
> > 'buttons' is a bitwise or of pyglet.window.mouse constants
> > LEFT, MIDDLE, RIGHT
> > 'modifiers' is a bitwise or of pyglet.window.key modifier
> > constants
> > (values like 'SHIFT', 'OPTION', 'ALT')
> > """
> > posX, posY = cocos.director.director.get_virtual_coordinates
> > (x, y)
> > print "Mouse Pressed: ", posX, ",", posY
>
> > # Do complex calculation that takes ~1 second to complete
> > self.calc()
>
> > #animate
> > self.label.do(cocos.actions.FadeIn(1) +
> > cocos.actions.RotateBy(360,1) +
> > cocos.actions.ScaleBy(2, 2) +
> > cocos.actions.ScaleBy(1/2.0, 1))
>
> > def __init__(self):
> > super( HelloWorld, self ).__init__()
>
> > # a cocos.text.Label is a wrapper of pyglet.text.Label
> > # with the benefit of being a cocosnode
> > self.label = cocos.text.Label('Hello, World!',
> > font_name='Times New Roman',
> > font_size=32,
> > anchor_x='center', anchor_y='center')
>
> > self.label.position = 320,240
> > self.add( self.label )
>
> > if __name__ == "__main__":
> > # director init takes the same arguments as pyglet.window
> > cocos.director.director.init()
> > hello_layer = HelloWorld ()
> > main_scene = cocos.scene.Scene (hello_layer)
> > cocos.director.director.run (main_scene)
>
> Clicking the mouse I see
> 1. a time without changes
> 2. followed by a smooth animation.
> windows xp here, running cocos trunk r1065, pyglet 1.1.4
>
> I remember some older pyglet having problems with time.
>
> --
> claudio
--
You received this message because you are subscribed to the Google Groups
"cocos2d discuss" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/cocos-discuss?hl=en.