Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added TweenChain #723

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open

added TweenChain #723

wants to merge 1 commit into from

Conversation

mucaho
Copy link
Contributor

@mucaho mucaho commented Feb 6, 2014

TweenChain component:

  • sequentially arranges tweens (one tween plays after another)
  • optionally loops
  • can be called with relative offsets (think {x: -2*TILE_WIDTH} instead of {x: ent.x - 2*TILE_WIDTH}
  • does not interfere with already present Tweens or future Tweens
  • downside?: only one TweenChain at a time; possible to implement for more if needed

Example JSFiddle showing 1 TweenChain and 2 other Tweens animating at same time

This feature is listed in the Idea pool - Path Movement and should replace #515

Tests coming after I get the O.K. on the code

@mucaho mucaho added the Needs QA label Feb 6, 2014
@starwed
Copy link
Member

starwed commented Feb 6, 2014

Hmm, why a separate component, and not an additional capability of "Tween"?

It might be worth thinking about whether there's an easy way to abstract the notion of chainable actions out such that you could tie together Animations, Tweens, and any custom-made user events. On the other hand, maybe it's better to just have something that works right now, and abstract that bridge later.

@mucaho
Copy link
Contributor Author

mucaho commented Feb 9, 2014

The way it is implemented right now:

  • decouples the "aggregated tweens" logic from the implementation of the Tween component itself
  • it's clear which tweens belong to which tween chain, see example1
  • lacks the ability to define sequential tweens seperately, see example2

So you would want something like this

var ent = Crafty.e("Tween");

// One execution context
ent.tween({x: 100}, 100ms, isSequential = false)
   .tween([x: 40, alpha: 0}, 100ms, isSequential = true) // ends after 200ms total
   .tween(loopLast = 2) // loop the last two specified tweens

// Another execution context
ent.tween({y: 100}, 100ms, isSequential = true/false?) // pass true or false here? do I know if I'm specifying the first tween in a chain?
// In another scope in the same execution context, ~2ms later
ent.tween([y: 40}, 100ms, isSequential = true) // this will start once the last specified tween finishes

rather than something like this

var ent = Crafty.e("TweenChain");

// One execution context
ent.tweenChain(relativeValues = false, looping = true, [ 
      [{x: 100}, 100], 
      [{y: 40, alpha: 0}, 100],
    ])

// Another execution context
// can't do the same as above  - tweens in a chain can not be declared separately

right?

@mucaho
Copy link
Contributor Author

mucaho commented Feb 25, 2014

So I have been investigating how the user could reference mulitple chains (e.g. for cancelling them later):

  • Take the Tween approach: map every property (x,y,...) to the corresponding chain it was defined in. The user can then call cancelTweenChain('x') and it will cancel the chain where x is tweaked at least once. I do not like this approach, as any other chains that also tweek the same property will cause conflicts.
  • Return an automatically generated unique identifier when the user defines a tween chain. The user can then save the identifier and cancel the tween chain using this identifier. This approach is not coherent with the library's intention to allow method chaining.
  • Let the user specify an unique identifier each time he defines a tween chain. This clutters the API a bit, but the user can use a "natural language" identifier to cancel tween chains.
  • Use a combination of both: If user does not care about cancelling the tween chain, generate a identifier for him. If users cares about cancelling the tween chain, let him pass an argument for the optional parameter. Best of both worlds in my opinion.

Are you happy with how you define tweens with the Tween component currently? Would it be beneficial to use the approach as described in my last point above? (It would certainly help simplify the code from a developers viewpoint, but would it also benefit the user?)

@mucaho
Copy link
Contributor Author

mucaho commented Dec 14, 2015

It might be worth thinking about whether there's an easy way to abstract the notion of chainable actions out such that you could tie together Animations, Tweens, and any custom-made user events. On the other hand, maybe it's better to just have something that works right now, and abstract that bridge later.

Yep, matthijsgroen discovered to use promises for chaining actions (either in parallel or sequence) together. See https://groups.google.com/forum/#!topic/craftyjs/DadBdot-NkA.

@matthijsgroen
Copy link
Member

For animations, I made a simple component: https://github.com/matthijsgroen/game-play/blob/master/app/scripts/components/generic/TweenPromise.coffee

Crafty.c 'TweenPromise',
  init: ->
    @requires 'Tween'

  tweenPromise: (args...) ->
    d = WhenJS.defer()
    @one('TweenEnd', -> d.resolve())
    @tween args...
    d.promise

It simply wraps the tween animation in a promise using WhenJS. And from there I can chain them using sequence, parallel, etc.

But since most of this power comes from an external library (WhenJS), and there are different flavours available, I'm not sure if Crafty should solve this problem (since solving it is quite easy)

@mucaho
Copy link
Contributor Author

mucaho commented Mar 29, 2017

It simply wraps the tween animation in a promise using WhenJS. And from there I can chain them using sequence, parallel, etc.

I think Bluebird is a noteworthy promise library because it could be used to cancel a chain of promises. I don't know of any other promise library that supports this out-of-the box.

But since most of this power comes from an external library (WhenJS), and there are different flavours available, I'm not sure if Crafty should solve this problem (since solving it is quite easy)

Yeah, agreed, an external, nicely written component is the way to go here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants