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 
Have a nice day,
Rene
1 Like