Description
I've just checked through the issues and PRs for the project and it seems there have been numerous attempts to implement an animation system for sprite based actors, but none have worked out. I think this really would be a feature worth its weight in gold.
Is there any information not accessible via the issues and PRs on progress on this? If not, I might take another look at it. In case there has been partial progress, would the leadership of the program prefer continuing work on one of the previous in-progress solutions or a new approach.
Possible concept for a new approach
I wouldn't be able to start on this immediately, but my first thought would be to have a property animations for Actor objects. This property would be an instance of a new class AnimationSystem or similar and would expose all relevant functions and variables that have to do with animations.
Since changes should be non-breaking, changing the value of image should supercede any animations and lock the image in.
The Animation system itself would use a dictionary to store multiple individual animations (key = name of the animation, value = animation data). Each animation would be made up of frames which each have a duration in seconds associated.
The dictionary would not be exposed directly to the user, but rather be populated and changed via functions such as animations.add(name, frames, durations), animations.remove(name) and similar. Support for spritesheets could be added simply by having a special function like animations.load_spritesheet(sheet, anims) where anims would be a list of tuples that give names, starting locations and separations for the individual animations in the spritesheet. Maybe there's a more elegant way to handle spritesheets but I think for a first implementation, just having the option to of using images in the /images directory would be enough.
Animations could fundamentally be played in three different ways:
- Directly playing an animation (animations.play(name))
- Queuing animations to be played in sequence (animations.queue(name, name2, ...))
- Setting a base animation that plays when no other animation is active (animations.set_base(name))
Managing based on changes in the game state would occur in the update() function. Where the actual automatic updating of the animations takes place I am unsure as of yet. The most user-friendly thing would be for everything to happen in draw() automatically. Since I am somewhat new in this repo, I am unsure whether this could cause problems because of the timing-sensitive nature of the animations though. If this is the case, the best solution could be to also have a function animations.run(dt) or animations.update(dt) that would be called from update() to have the system progress an animation. This however could lead to more confusion and problems for the user (maybe the user makes changes to the animations after calling animations.update(dt) in update(), leading to a mismatch in game frame). Any comment on this would be appreciated.
To make this flexible and easy to use, the number of steps required to get basic animations working should be minimal. For this, animations.add() or any equivalent should provide multiple options for the provided arguments up to giving a full dictionary itself. At the same time, the functions should check thouroghly for validity of the added animations to prevent problems in the future and must have clear and descriptive errors if something was wrong.
Mockup use
alien = Actor("alien")
alien.animations.add("idle", ["idle_1", "idle_2", "idle_3"], [0.3, 0.3, 0.3])
alien.animations.set_base("idle")
alien.animations.add("move", ["move_1", "move_2"], [0.25, 0.4])
def draw():
screen.clear()
alien.draw()
def update(dt):
if keyboard.right:
alien.x += 5
alien.animations.play("move")
# Note: animations.play() does not restart the animation if called repeatedly while the animation is ongoing