Spine Plugin - Animation Complete Callback

Hi there,

Short: How can I trigger an event after a animation has finished playing using spine in PlayCanvas?

Long: In the old Version of Spine one could add a “onComplete” Callback, e.g. to play animation “Walk” after animation “Attack” has finished. This is from an old example:

this.entity.spine.state.setAnimationByName(0, "Attack", false);
                this.entity.spine.state.onComplete = function (track, count) {
                    if (this.tracks[0].animation.name === "Attack") {
                        this.setAnimationByName(track, "Walk", true);
                    }
                };

I am aware that the “setAnimationByName” was renamed to “setAnimation”.

But I think the “onComplete” function is gone. Is there an equivalent for the “onComplete” action? How can I trigger some events when a specific animation has ended? Most preferably by a proper callback, not by some hacks like checking the state every frame or something similar…

Thanks for your help,
Rene

I haven’t heard of this “Spine” API. Where did you find it? I’m curious as to what it does?

It’s a wrapper (click) to use animations created with a tool named “spine” (click) within PlayCanvas engine.

It’s a 2D animation system?

Yes. In their Pro Version they also feature pretty awesome “2.5D” mesh deformations, check it out here: http://esotericsoftware.com/spine-demos

Heya,

this proved a pain in the butt to figure out for me too - the Spine API docs are too long winded. Basically it’s something like a ‘delegate’ pattern now.

Here’s my animation control script, which adds hooks to get events, end and the like:

var AnimationController = function(ent)
{
    this.entity = ent;
    this.paused = false;
    this.playing = false;
    this.speed = 1;
    
    this.delegateObj = {
        start: this.onStart.bind(this),
        complete: this.onComplete.bind(this),
        event: this.onEvent.bind(this),
        interrupt: this.onInterrupt.bind(this),
    };
    this.entity.spine.state.addListener(this.delegateObj);
    
    pc.events.attach(this);
};

AnimationController.prototype.getMainTrack = function(){
    return this.entity.spine.state.tracks[0];
};

AnimationController.prototype.setPlaybackSpeed = function(speed){
    this.speed = speed;
    if( this.getMainTrack() ) this.getMainTrack().timeScale = this.speed;
};

AnimationController.prototype.play = function(name,speed,loop){
    this.playing = true;
    this.paused = false;
    
    this.entity.spine.state.setAnimation(0, name, typeof loop != 'undefined' ? loop : false);
    
    if( typeof speed != 'undefined' ) this.setPlaybackSpeed(speed);
};

AnimationController.prototype.stop = function(){
    this.playing = false;
    this.paused = false;
    this.entity.spine.state.setEmptyAnimation(0,0);
};

AnimationController.prototype.pause = function(){
    if( ! this.playing ) return;
    this.paused = true;
    this.getMainTrack().timeScale = 0;
};

AnimationController.prototype.resume = function(){
    if( ! this.playing ) return;
    this.paused = false;
    this.getMainTrack().timeScale = this.speed;
};

AnimationController.prototype.destroy = function(){
    
    this.entity = null;
    
    this.delegateObj = null;
};

AnimationController.prototype.onStart = function(track){
    console.log("START",track);
    this.fire('start',track);
};

AnimationController.prototype.onComplete = function(track){
    console.log("COMPLETE",track);
    this.fire('complete',track);
};

AnimationController.prototype.onEvent = function(track,event){
    console.log("EVENT",track,event);
    this.fire('event',track,event);
};

AnimationController.prototype.onInterrupt = function(track){
    console.log("INTERRUPT",track);
    this.fire('interrupt',track,event);
};

Note that this script is independent from the PlayCanvas script system - you create a new AnimationController, and pass it your Spine entity. Then you control the Spine anim via the API presented on the AnimationController here.

2 Likes

Thanks a lot @inductible - Those snippets helped me out :wink:

Have a nice day,
Rene

1 Like