Controlling Sprite Animation Speed?

183 views
Skip to first unread message

Solar Lune

unread,
Jan 5, 2017, 5:15:37 AM1/5/17
to pyglet-users
Hey, there. So, I'm doing work on creating a quick little Python module to auto-load tags and animations in from Aseprite into pyglet, but before I go further, I wanted to confirm: Is there no way to control how quickly a sprite is playing, or know where in the animation a sprite is (apart from when it hits the end of the animation)?

Benjamin Moran

unread,
Jan 5, 2017, 8:54:25 AM1/5/17
to pyglet-users
That sounds like an interesting project. What kind of format will your data be in?

The Sprite class does not currently have any public attributes that show the animation details, but it is possible to access this information. If you create a Sprite with an animation, it will have a private attribute with the current frame (this attribute will not exist if the sprite uses a static image):
>>> sprite = pyglet.sprite.Sprite(img=some_animation)
>>> sprite._frame_index
0

As for animation speed:
If you're creating an animation from a sequence of images, or a sprite sheet (ImageGrid), you can specify the animation speed on creation.
There is not currently a standard way of controlling animation speed after creation, but there are some ways you could to it. The trick is that each frame in an animation has it's own duration attribute. The Sprite class simply plays these frames in order. One way to do it would be to simple re-create the animation and update the sprites *image* attribue with the new animation. Another way would be to iterate through the animations frames, and modify their duration attribute. If you post a little more about what you're trying to accomplish, it would be easier to recommend something.

-Ben

Solar Lune

unread,
Jan 5, 2017, 12:13:02 PM1/5/17
to pyglet...@googlegroups.com
Aseprite allows you to export a standard sprite sheet, and export timing information and tags to a JSON file. I'm loading that file in to create the animations and tags from - the data class is currently a container that holds the loaded set of animations, tags, and a reference to the pyglet Sprite itself. 

In another engine, I also created functions that you could use to tell when you hit specific tags (for example, a "spawn" tag in a shooting animation) - that's what I'd like to add here, too, for simplicity and ease-of-use.

I'll see about exposing this frame index to the data class I have so that the user can tell what frame the animation's on - perhaps also a function that gives a percentage completed.

Being able to tweak the animation speed of a "currently running" animation is also important, so that's what I was looking into. Seems like it might be good to add a multiplication value to Animations so that it's easier to tweak speed, rather than having to loop through each frame and alter its duration (since that takes processor speed to do).

Thanks for the information!

--
You received this message because you are subscribed to a topic in the Google Groups "pyglet-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/pyglet-users/3Pp3VHtoAto/unsubscribe.
To unsubscribe from this group and all its topics, send an email to pyglet-users+unsubscribe@googlegroups.com.
To post to this group, send email to pyglet...@googlegroups.com.
Visit this group at https://groups.google.com/group/pyglet-users.
For more options, visit https://groups.google.com/d/optout.

Benjamin Moran

unread,
Jan 5, 2017, 8:57:40 PM1/5/17
to pyglet-users
I did some reading up on Aseprite. It's a nice program, and I think it might be nice to make a loader for the binary .aseprite/.ase format at some point as well. It's binary, but well defined and looks easy to parse.

In your case, it might be simplest to just subclass the Sprite module, and override the _animate method. Here is the original method:
    def _animate(self, dt):
       
self._frame_index += 1
       
if self._frame_index >= len(self._animation.frames):
           
self._frame_index = 0
           
self.dispatch_event('on_animation_end')
           
if self._vertex_list is None:
               
return  # Deleted in event handler.

        frame
= self._animation.frames[self._frame_index]
       
self._set_texture(frame.image.get_texture())

       
if frame.duration is not None:
            duration
= frame.duration - (self._next_dt - dt)
            duration
= min(max(0, duration), frame.duration)
            clock
.schedule_once(self._animate, duration)
           
self._next_dt = duration
       
else:
           
self.dispatch_event('on_animation_end')

As you can see, it uses the duration attribute of the frames themselves to advance. I would suggest that you add a Sprite.animation_speed property to your subclass of the Sprite class, and then modify the Sprite._animate method to use that value instead. This would be simple to change the speed.   If you go this route, you could also easily update any frame index properties as well from within the _animate method.
To unsubscribe from this group and all its topics, send an email to pyglet-users...@googlegroups.com.

Benjamin Moran

unread,
Mar 30, 2017, 11:30:43 AM3/30/17
to pyglet-users
If you're still following this, I've written a decoder for the Aaprite binary format (.ase). It allows you to load in Asprite animations directly, including frame time. Let me know if you're interested and I'll post it.
Reply all
Reply to author
Forward
0 new messages