Canvasでアニメーションだけなら、JavaScript書かずにFlash CC(Animate CC)で書き出せばいいよね。Flashまだまだ使えるよ!なんですが、実際運用するとなると、ある時期でアニメーション切替、追加、削除等の変更が出てきます。AS3.0ならloadMovieでswf切り替えればよかったんですが、「CanvasにはloadMovieとかないし、どうするの?」と思ったら、意外とカンタンな話だったのでまとめておきます。
まずはアニメを作ります。
1つ目。Flash CC(今回はFlash CC 2015を使用)で、新規から「HTML5 Canvas」を選択してクラッシックトゥイーンでアニメーションして書き出しただけ。完成品はこちら。
2つ目。作り方は同じ。完成品はこちら。
で、2つ目のアニメを例に、Flash CCが書き出したHTMLとJavaScriptを見てみると・・・
・HTML抜粋(anime2.html)
<script> var canvas, stage, exportRoot; function init() { canvas = document.getElementById("canvas"); exportRoot = new lib.anime2(); stage = new createjs.Stage(canvas); stage.addChild(exportRoot); stage.update(); createjs.Ticker.setFPS(lib.properties.fps); createjs.Ticker.addEventListener("tick", stage); } </script>
・JavaScript抜粋(anime2.js)
// stage content: (lib.anime2 = function(mode,startPosition,loop) { this.initialize(mode,startPosition,loop,{}); // timeline functions: this.frame_119 = function() { //this.stop(); } // actions tween: this.timeline.addTween(cjs.Tween.get(this).wait(119).call(this.frame_119).wait(1)); // レイヤー 2 this.instance = new lib.mc_girl(); this.instance.setTransform(698.1,205,3,3,0,0,0,41.1,143.8); this.timeline.addTween(cjs.Tween.get(this.instance).to({x:283.1,y:463},59).to({scaleX:4,scaleY:4,x:-154.8,y:479},60).wait(1)); // レイヤー 3 this.shape = new cjs.Shape(); this.shape.graphics.f("#FF9900").s().p("Egq9AfPMAAAg+eMBV6AAAMAAAA+eg"); this.shape.setTransform(275,200); this.timeline.addTween(cjs.Tween.get(this.shape).wait(120)); }).prototype = p = new cjs.MovieClip();
JSファイルでは、アニメーション全体がlib.anime2として定義されていて、それをHTML側に書いたJavaScript(init)でstageにaddChildしているという構造です。
なので、アニメーションの再生フレームを監視して、再生し終わったらremoveChildで削除して、次のアニメーションをaddChildすれば言いわけです。で、この2つのアニメーションを切替再生するためにJavaScript部分を書き直したHTMLがこちら。
・HTML(anime_switch.html)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>anime_switch</title> <script src="http://code.createjs.com/easeljs-0.8.1.min.js"></script> <script src="http://code.createjs.com/tweenjs-0.6.1.min.js"></script> <script src="http://code.createjs.com/movieclip-0.8.1.min.js"></script> <script src="anime1.js"></script> <script src="anime2.js"></script> <script> var canvas, stage, exportRoot; var animeArray = ["anime1","anime2"]; var count_anime; function init() { canvas = document.getElementById("canvas"); // exportRoot = new lib.anime2(); count_anime = 0; exportRoot = new lib[animeArray[count_anime]](); stage = new createjs.Stage(canvas); stage.addChild(exportRoot); stage.update(); createjs.Ticker.setFPS(lib.properties.fps); createjs.Ticker.addEventListener("tick", stage); createjs.Ticker.addEventListener("tick",onCheckAnimationEnd); } function onCheckAnimationEnd(event){ if (exportRoot.timeline.position >= (exportRoot.timeline.duration-1)){ count_anime++; count_anime = count_anime > (animeArray.length-1) ? 0 : count_anime; stage.removeChild(exportRoot); exportRoot = new lib[animeArray[count_anime]](); stage.addChild(exportRoot); } } </script> </head> <body onload="init();" style="background-color:#D4D4D4"> <canvas id="canvas" width="550" height="400" style="background-color:#FFFFFF"></canvas> </body> </html>
※完成サンプルはこちら。
要点は以下の通り。
- 両方のアニメーションのjsを読み込む(9-10行目)
- アニメーションを切り替えるためのライブラリ名は配列化(15行目)
- 再生順を管理するためのカウンタ変数を追加(16行目)
- アニメーション再生監視用に関数を追加(31,34-45行目)
今回のCreateJSでのASとの相違部分は以下です。
処理 | AS | JavaScript |
現在のフレーム数 | mc.currentFrame | mc.timeline.position |
総フレーム数 | mc.totalFrames | mc.timeline.duration |
【追記】
2つのアニメーションを1つのflaファイルに、それぞれMovieClipとして作成した場合は、JSファイル上は・・・
- lib.anime1
- lib.anime2
のように定義されるので、この名前でaddChildできます。よって、必ずしもアニメーションを別ファイルで作成する必要はありません。
※今回のようにアニメーション全体を切り替える場合、実際には別ファイルと管理する方が楽だと思います。
上記の説明は、私の環境のFlash CCで書き出される下記のバージョンのCreateJSを前提としています。
<script src="http://code.createjs.com/easeljs-0.8.1.min.js"></script> <script src="http://code.createjs.com/tweenjs-0.6.1.min.js"></script> <script src="http://code.createjs.com/movieclip-0.8.1.min.js"></script>
【参考】
今回はtwitterでのやりとりが元になりました。gyoh_kさん、野中さんに感謝。
gyoh_kさんのツイート
野中 文雄さんのツイート1
野中 文雄さんのツイート2
【追記】2016.6.9
野中さんさんから、「MovieClip.currentFrameプロパティは前からあり、EaselJS 0.8.1 でMovieClip.totalFramesプロパティが加えられました。」とのご指摘を受けました。CreateJSとASの対応表を下記のように修正します。
処理 | AS | JavaScript |
現在のフレーム数 | mc.currentFrame | mc.timeline.position,mc.currentFrame |
総フレーム数 | mc.totalFrames | mc.timeline.duration,mc.totalFrames |
currentFrame,totalFramesを使ったサンプルはこちら。
参考
・FN1506001 | EaselJS 0.8.1: MovieClipオブジェクトの再生の長さ・フレーム数を調べる | HTML5 : テクニカルノート
・EaselJS v0.8.2 API Documentation : MovieClip – currentFrame
・EaselJS v0.8.2 API Documentation : MovieClip – totalFrames
アニメーションの数とか、誰がつくるのかの役割分担にもよりますけど。アニメーションを始めるときにコールバックを渡して、終わったらそれを呼ぶというかたちにすると、親から枚フレーム再生位置を確かめる手間が省けます。
なるほど。そうですね。そっちも試してみます。