jeremyckahn / shifty

The fastest TypeScript animation engine on the web
https://jeremyckahn.github.io/shifty/doc/
MIT License
1.54k stars 88 forks source link

Add a way to create a Tweenable() instance and set tween() params without starting tween #37

Closed unstoppablecarl closed 10 years ago

unstoppablecarl commented 10 years ago

I am queuing multiple tweens it would be nice to be able to completely create and configure a tweenable object without starting the tween.

For example I think you should be able to do this (or similar) easily:

var queue = [];

// second param accepts same params as tween()
var tween1 = new Tweenable(obj, {
    from: { x: 0,  y: 50  },
    to:   { x: 10, y: -30 },
    duration: 1500,
});
queue.push(tween1);

// second param accepts same params as tween()
var tween2 = new Tweenable(obj, {
    from: { x: 10,  y: 0  },
    to:   { x: 110, y: -10 },
    duration: 1000,
});
queue.push(tween2);

// later when ready
for (var i = 0; i < queue.length; i++) {
    var tween = queue[i];
    tween.resume();
}
jeremyckahn commented 10 years ago

Hi @unstoppablecarl, thanks for your suggestion. Shifty used to have queuing functionality, but I removed it as Rekapi matured. Rekapi is a keyframe library that provides the sequencing functionality that it seems you want out of Shifty. Rekapi actually uses Shifty internally to compute the keyframes, so you can use the two side-by-side. I suggest using Rekapi if you want to sequence a multi-step animation.

I'm closing this for now, feel free to reopen if necessary.

unstoppablecarl commented 10 years ago

Thanks for the recommendation this looks like it could be exactly what I am looking for.

I was not expecting or requesting that shifty have queuing functionality. I like that it is lightweight and does not try to handle things like that.

The issue is: you cannot create an object instance that has the tween params set without starting the tween. The method that starts the tween Tweenable.prototype.tween(); appears to be the only place to set the tween config info.

jeremyckahn commented 10 years ago

What is the use case for starting a tween sometime later than when it was defined? Is there a scenario where calling tweenable.tween({ /* config */ }) is not as desirable as defining the tween and starting it at a later point?

unstoppablecarl commented 10 years ago

I think for most (if not all) object oriented apis the separation of setting config data, and execution using that config data should be accessible separately. The convenience of one method that does both makes sense given it will be the majority use case, but I don't think should be the only option.

Use cases

Most of these could be accomplished with some sort of wrapper that keeps the instance and the config separate, but It is usually more desirable to extend the base object rather than wrap it in another layer.

Here is what I came accross


var Laser = Director.extend({

    startTime: null,
    duration: null,

    tween: null,
    tweenSettings: null,

    // settings
    startTile: null,
    endTile: null,
    color: null,

    constructor: function(settings){
        setttings = settings || {};
        _.extend(this, settings);

        var sprite = new LaserSprite({
            color: this.color
        });

        this.tween = new Tweenable(sprite);
        this.tweenSettings = {
            from: {
                x: Math.floor(this.startTile.x * this.tileSize) + (this.tileSize / 2 - sprite.size.x / 2),
                y: Math.floor(this.startTile.y * this.tileSize) + (this.tileSize / 2 - sprite.size.y / 2)
            },
            to: {
                x: Math.floor(this.endTile.x * this.tileSize) + (this.tileSize / 2 - sprite.size.x / 2),
                y: Math.floor(this.endTile.y * this.tileSize) + (this.tileSize / 2 - sprite.size.y / 2)
            },
            duration: this.duration
        };
    },
    start: function(){
        this.game.addSprite(sprite);
        // remember this.tween isn't ready to go add the config to it now
        // when debugging I have to discover that the data explicitly related to this tween isn't part of it until it starts and it is harder to observe because it is changing constantly
        this.tween.tween(this.tweenSettings);
    }
});

I think the change is worth the effort given how minimal it is.

jeremyckahn commented 10 years ago

You raise some good points. I'd like to avoid necessitating a .start() call or anything like that for people already using Shifty. In other words, the current usage patterns should not be broken due to the addition of this feature. Perhaps a preventStart config variable for tween()? I'm open to ideas and Pull Requests.

unstoppablecarl commented 10 years ago

This can be closed now.