Help us understand the problem. What is going on with this article?

[CreateJS] Tween.pause()とTween.pausedを間違えると詰まる

先に結論だけ

Tween.pause()関数は再生中のTweenアニメーションを停止する関数ではありません。
再生中のTweenアニメーションを停止したい場合は、以下のように指定しましょう。

⭕️ アニメーションの即時停止

Tween.paused = true

はじめに

TweenJSには.pause()関数と.pausedプロパティというよく似た名前のメンバーがあります。この2つはまったく違う機能です。この点が頭から抜けていると予期せぬ挙動で詰まることがあります。詰まりました。

この記事はこの2つの機能を確認、共有するためのものです。

想定する環境

この記事は以下のバージョンのTweenJSを前提として書かれています。バージョンが異なると機能が変化している場合があります。記事を読む前にバージョンの確認をしてください。

tweenjs : "1.0.2"

想定する読者

この記事は現在CreateJSやTweenJSを利用しているユーザーを想定しています。インストールガイドなどは含みませんのでご了承ください。

問題の機能

この記事で問題とするのは、以下のような記述をした場合の機能の差です。

const tween = createjs.Tween.get(circle)
  .to({ alpha: 0, y: 225 }, 10000)

tween.pause(); // <- ここではアニメーションが止まらない。
tween.paused = true; // <- ここでアニメーションが止まる。

ユーザーの操作をトリガーに、アニメーションの中断や再開をすることはよくあります。しかし中断が正常にできないと、以下のような問題が発生します。

  • アニメーションが多重起動する。
  • ターゲットの状態が変更され続ける。その間他の操作を受け付けない。
  • メモリリークする。

とくにloopするアニメーションは、正常に中断できないとバグの温床となります。

何が起きているか

それぞれの関数とプロパティを追って、実際の処理を確認します。

Tween.pause()

まずはTween.pause()関数の公式ドキュメントを読んでみます。
公式ドキュメント : Tween.pause()

Adds an action to pause the specified tween.

ポーズのためのアクションを追加します、とありますがこの文面では直感的に機能を理解できません。ドキュメントにはソースコードへのリンクがありますので、どのような処理を行なっているのか確認します。

ソースコード : Tween.pause()
pause関数は、Tweenクラス内部の_addAction関数を呼び出しています。変更するパラメーターとして{paused:true}というオブジェクトを渡しています。

ソースコード : Tween._addAction()
_addAction関数は、TweenActionというインスタンスを生成し、Tweenインスタンスのメンバー変数に保存しています。

ソースコード : TweenAction
TweenActionはTween内のプライベートクラスです。アクションが実行される時間tと、その時に実行される関数funcを保存しています。TweenActionはprevnext変数にTweenActionインスタンスを抱えており、チェーン状に参照が続いています。pause()関数で登録されるTweenActionは、規定の時間tになるとpausedパラメーターをtrueに変更します。

再生中のTweenをpause()するとどうなるか

現在再生中のTweenでpause()を実行すると、TweenActionチェーンの末尾にpauseアクションが追加されます。すべてのアクションが完了した段階で、pauseアクションが呼び出されます。結果としてアニメーションの再生は停止しません。

_addActionを行う関数

pause()以外にも_addAction()を行う関数があります。
以下の関数がTween._addAction()を行う関数です。

  • play() : 引数に指定したTweenを再生する。
  • pause() : 引数に指定したTweenを停止する。
  • set() : 引数に指定したプロパティをTweenターゲットに反映する。
  • call() : コールバック関数を呼び出す。

これらの関数で指定したプロパティはその瞬間には反映されず、TweenActionチェーンに登録されます。
play()とpause()関数は、実際には{paused:true or false}というプロパティを渡すset()関数のラッパーです。

Tween.paused = true

Tween.pausedプロパティはTweenのコンストラクタ内で_setPaused, _getPausedというアクセサメソッドに接続されています。
_setPaused関数は、createjs.Tween._register()という関数でTweenインスタンスの登録と解除を行ないます。登録解除されたTweenインスタンスは、createjsのTickerで処理されなくなり、アニメーションはその瞬間に停止します。

なぜこのような設計なのか

TweenJSは、メソッドチェーンでアニメーションを柔軟かつ簡単に記述できることを特徴としています。公式サイトのGETTING STARTEDに掲載されているサンプルがその設計を代表しています。

createjs.Tween.get(circle, { loop: true })
  .to({ x: 400 }, 1000, createjs.Ease.getPowInOut(4))
  .to({ alpha: 0, y: 175 }, 500, createjs.Ease.getPowInOut(2))
  .to({ alpha: 0, y: 225 }, 100)
  .to({ alpha: 1, y: 200 }, 500, createjs.Ease.getPowInOut(2))
  .to({ x: 100 }, 800, createjs.Ease.getPowInOut(2));

このような記述ができるように、メソッドチェーンの一部にできる.pause()関数と、アニメーションを停止する.pausedプロパティの2つの手段が用意されています。

設計と機能からこの2つを理解すると腑に落ちるのですが、直感的には理解しにくいと思います。この記事が皆様の一助となれば幸いです。

以上、ありがとうございました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした