[SOLVED] Tween Behaviour with events

Hi all,

We are looking at the PlayCanvas Tween functionality and its event behaviour and not able to make sense of it.

Here’s a sample project forked from the tween tutorial: PlayCanvas 3D HTML5 Game Engine
We modified the position tween to include events on ‘loop’,‘complete’,‘update’ to see the effect of these in the project.

Expectation:
When .repeat(n) is absent and .loop(true) is present, an event should appear for each loop, and complete should never appear. Update should appear at some rate equivalent to FPS.
When .repeat(n) is present, loop event may not appear, complete appears after n repeats occur and update should appear at some rate equivalent to FPS.

Reality:
When .repeat(n) is absent, one loop event, one complete event and one update event and nothing more.
When .repeat(8) is present, one loop event, one complete event and one update event and nothing more.
Please see screen grab of console.

Is something broken in the library or are we misunderstanding how the tween events are supposed to work? We originally started looking into the behaviour when we wanted an event to occur after 8 iterations of an animation and found that the ‘complete’ event was triggering prematurely and thus causing our event to occur prematurely too.

Relevant code replicated here:


TweenPosition.prototype.reset = function () {                  
    // if we are already tweening then stop first
    if (this.tween) {
        this.tween.stop();
    }

    // reset our position
    this.entity.setLocalPosition(-4, 0, 0);
    this.counter = 0; //added this to count loops/repeats

    // create a new tween using our script attributes
    this.tween = this.entity.tween(this.entity.getLocalPosition())
        .to(new pc.Vec3(4, 0, 0), this.duration, pc[this.easing])
        .delay(this.delay)
        .loop(this.loop)
        .yoyo(this.yoyo)
        .on('loop',function(thise){
            console.log("No repeat Loop",thise.counter);
            thise.counter++;
        }(this))
        .on('complete',function(thise){
            console.log("No repeat Complete",thise.counter);
        }(this))
        .on('update',function(thise){
            console.log("No repeat Update",thise.counter);
        }(this));

    // only set repeats if loop is false
    if (! this.loop){
        console.log("repeat!");
        this.tween.repeat(this.repeat)
        .on('loop',function(thise){
            console.log("Repeat Loop",thise.counter);
            thise.counter++;
        }(this))
        .on('complete',function(thise){
            console.log("Repeat Complete",thise.counter);
        }(this))
          .on('update',function(thise){
            console.log("Repeat Update",thise.counter);
        }(this));
    }

    // start the tween
    this.tween.start();
};

Hi, @sciseedlets and welcome!

I would recommend you to raise your concerns in a ticket on the github playcanvas-tween repo GitHub - playcanvas/playcanvas-tween: A tween library for PlayCanvas

Regarding the complete event firing after every iteration has its own use cases. For the time being you can count the number of tween iterations completed using the complete event and then call the completion function.

.on('complete', ()=>{

   tweenCompleted++;
  if(tweenCompleted === 8)
    this.complete();
})

Hmm, I’m not seeing this in my tests :thinking:

Loop only: https://playcanvas.com/editor/scene/1388258

TestLoop.prototype.initialize = function() {
    this.entity.tween(this.entity.getLocalPosition())
        .to({ x: 10, y: 0, z: 0 }, 1.0, pc.SineOut)
        //.repeat(8)
        .loop(true)
        .on('complete', function () {
            console.log('tween completed');
        }).on('update', function (dt) {
            console.log('tween update ' + dt.toString());
        })
        .start();
};

I can’t see ‘tween completed’ in the console log and update is called per update

Repeat only: https://playcanvas.com/editor/scene/1387260

    this.entity.tween(this.entity.getLocalPosition())
        .to({ x: 10, y: 0, z: 0 }, 1.0, pc.SineOut)
        .repeat(8)
        //.loop(true)
        .on('complete', function () {
            console.log('tween completed');
        }).on('update', function (dt) {
            console.log('tween update ' + dt.toString());
        })
        .start();

I see ‘tween completed’ once right at the end and ‘tween update’ is called every frame

I’ve forked your project: https://playcanvas.com/editor/scene/1388269

Looks like the issue was with your callbacks to the events loop, complete and update. I’ve changed it to an ES5 style bind and it now matches the expected behaviour

    this.tween = this.entity.tween(this.entity.getLocalPosition())
        .to(new pc.Vec3(4, 0, 0), this.duration, pc[this.easing])
        .delay(this.delay)
        .loop(this.loop)
        .yoyo(this.yoyo)
        .on('loop',function(){
            console.log("No repeat Loop",this.counter);
            this.counter++;
        }.bind(this)).on('complete',function(){
            console.log("No repeat Complete",this.counter);
        }.bind(this))
        .on('update',function(){
            console.log("No repeat Update",this.counter);
        }.bind(this));
2 Likes

Thanks @yaustar. I just arrived at the same conclusion that the bind method was causing the error.