サイトトップ

Director Flash 書籍 業務内容 プロフィール
 

Adobe Flash ActionScript講座
ActionScript 3.0
パフォーマンスチューニング
ActionScript 3.0による
三次元表現ガイドブック
■Twitter: @FumioNonaka / Mailing List: ActionScript 3.0

F-siteセミナー「Flash Professional CS6がやって来た ヤア!ヤア!ヤア!」

FLAからJSへ〜CreateJS中級編

Date: 2012年7月28日 Product: Flash Professional Platform: All Version: CS6/ActionScript 3.0


01 前回のあらすじ ー Bitmapクラスで外部画像をCanvasに置く

2012年5月19日に催されたF-siteセミナー「新登場!CreateJSとは?」02「ビットマップを配置する」で、BitmapインスタンスをCanvasに置くごく簡単なコードを紹介した(02-02「空のタイムラインから[パブリッシュ]したCanvasに外部画像を読込んで描く」コード002)。それをさらに簡素化したのがつぎのコード001だ(script要素)。外部画像がBitmapインスタンスに読込まれて、Canvas左上角に描かれる(図001)。

コード001■外部画像をBitmapインスタンスに読込んでCanvasに描くもっとも簡素なコード
  1. <script src="libs/easeljs-0.4.2.min.js"></script>
    <!--
    <script src="01_Bitmap.js"></script>
    -->
  2. <script>
  3. var canvas, stage, exportRoot;
  4. function init() {
  5.   canvas = document.getElementById("canvas");
      // exportRoot = new lib._01_Bitmap();
  6.   exportRoot = new Bitmap("images/Pen.png");
  7.   stage = new Stage(canvas);
  8.   stage.addChild(exportRoot);
  9.   stage.update();
      /*
      Ticker.setFPS(24);
      Ticker.addListener(stage);
      */
  10. }
  11. </script>

図001■Canvasに置かれた外部画像
図001

Tickerクラスはフレームレートで画面を描き替えるアニメーションに用いられるので、静止画であれば除いて差支えない(コード001第9行目と第10行目の間)。ただし、Stage.update()メソッドでCnavasを描くとき(第9行目)に画像の読込みが間に合わないと、Canvasには何も表示されない。再読込みすれば、キャッシュが使われるので画像が表れる。画像を確実に描くには、読込み待ちしなければならない。


02 PreloadJSで外部画像の読込みを待つ

CreateJS Suiteで外部ファイルの読込み待ちを担うのが、PreloadJSライブラリだ。外部ファイルを読込み終えたときの処理はつぎのように定める。

  1. PreloadJSインスタンスをつくる。
  2. PreloadJS.onFileLoadイベントに、読込み終えたとき呼出す関数(ハンドラ)を定める。
  3. PreloadJS.loadFile()メソッドで外部ファイルを読込む。

つぎのコード002は、PreloadJSで外部画像ファイルの読込みを待ち(第9〜11行目)、ロードし終えてからStage.update()メソッドでCnavasを描画している(第23行目)。

コード002■外部画像ファイルのロードが終わったら基準点の設定と描画を行う
  1. <script src="libs/easeljs-0.4.2.min.js"></script>
  2. <script src="libs/preloadjs-0.1.0.min.js"></script>
  3. <script>
  4. var canvas, stage, exportRoot;
  5. var file = "images/Pen.png";
  6. function init() {
  7.   canvas = document.getElementById("canvas");
  8.   stage = new Stage(canvas);
  9.   var loader = new PreloadJS(false);
  10.   loader.onFileLoad = fileLoaded;
  11.   loader.loadFile(file);
  12.   setInstance();
      // stage.update();
  13. }
  14. function setInstance() {
  15.   exportRoot = new Bitmap(file);
  16.   exportRoot.x = canvas.width / 2;
  17.   exportRoot.y = canvas.height / 2;
  18.   stage.addChild(exportRoot);
  19. }
  20. function fileLoaded() {
  21.   exportRoot.regX = exportRoot.image.width / 2;
  22.   exportRoot.regY = exportRoot.image.height / 2;
  23.   stage.update();
  24. }
  25. </script>
  26. </script>

画像の描画だけでなく、そのプロパティを使った処理も読込み待ちしなければならない場合がある。コード002ではロード後の処理を定めた関数(fileLoaded() )で、読込んだ画像のサイズから基準点(DisplayObject.regXregYプロパティ)を決めている(第21〜22行目)。これで、画像を読込んだBitmapインスタンスがCanvasの真ん中に描かれる(図002)。

図002■読込み後の画像から基準点を定めて中央に表示する
図002 図002

参考:「PreloadJSで外部画像ファイルの読込みを待つ


03 迫り来る仕様変更と復活の呪文 ー 名前空間の新設

CreateJSのサイトからダウンロードしたライブラリ(libフォルダ)に含まれる「NEXT」と示されたJSファイルは、つぎのリリースで予定されている新機能や仕様の変更が加えられている(図003)。

図003■「NEXT」がついたJSファイルはつぎのリリース予定を示す
図003

本稿を執筆しているEaselJS 0.4.2から大きく変わるのは、CreateJS Suiteのクラスすべてに「createjs」という「名前空間」が与えられることだ。すると、CreateJS Suiteに属するクラスを参照するには、必ず頭に名前空間createjsをつけなければならなくなる(コード003第6行目および第10行目)。

コード003■次期バージョンのCreateJSではすべてのクラスに名前空間が与えられる
    <!--
    <script src="libs/easeljs-0.4.2.min.js"></script>
    -->

  1. <script src="libs/easeljs-NEXT.min.js"></script>
  2. <script>
  3. var canvas, stage, exportRoot;
  4. function init() {
  5.   canvas = document.getElementById("canvas");
  6.   stage = new createjs.Stage(canvas);
  7.   setInstance();
  8. }
  9. function setInstance() {
  10.   exportRoot = new createjs.Shape();
  11.   exportRoot.x = canvas.width / 2;
  12.   exportRoot.y = canvas.height / 2;
  13.   draw(exportRoot.graphics);
  14.   stage.addChild(exportRoot);
  15.   stage.update();
  16. }
  17. function draw(myGraphics) {
  18.   myGraphics.beginStroke("blue");
  19.   myGraphics.beginFill("cyan");
  20.   myGraphics.drawCircle(0, 0, 40);
  21. }
  22. </script>

名前空間は、他のライブラリなどとクラス名が衝突することを防ぐ。けれど、すでにこれまでのバージョンでつくったコンテンツに、新しいバージョンのCreateJS Suiteライブラリをそのまま使うことはできなくなる。

CreateJS Suiteライブラリをscript要素で読込む前に、つぎのコード004第2行目のJavaScriptステートメント1行(復活の呪文)を加えれば名前空間が省ける。ただし、クラス名が重複するおそれは残る。

コード004■名前空間にWindowオブジェクトを定めれば省略が可能
  1. <script>
  2. createjs = window;
  3. </script>
    <!--
    <script src="libs/easeljs-0.4.2.min.js"></script>
    -->
  4. <script src="libs/easeljs-NEXT.min.js"></script>
  5. <script>
  6. var canvas, stage, exportRoot;
  7. function init() {
  8.   canvas = document.getElementById("canvas");
      // stage = new createjs.Stage(canvas);
  9.   stage = new Stage(canvas);
  10.   setInstance();
  11. }
  12. function setInstance() {
      // exportRoot = new createjs.Shape();
  13.   exportRoot = new Shape();
  14.   exportRoot.x = canvas.width / 2;
  15.   exportRoot.y = canvas.height / 2;
  16.   draw(exportRoot.graphics);
  17.   stage.addChild(exportRoot);
  18.   stage.update();
  19. }
  20. function draw(myGraphics) {
  21.   myGraphics.beginStroke("blue");
  22.   myGraphics.beginFill("cyan");
  23.   myGraphics.drawCircle(0, 0, 40);
  24. }
  25. </script>

参考:「CreateJS Suiteのクラスに名前空間が設定される


04 マウスイベントと座標変換

マウスイベントの基本とイベントハンドラの扱いについては、前回のF-siteセミナー「新登場!CreateJSとは?」03「CreateJSでマウスイベントを扱う」で簡単に説明した(表001参照)。その応用として、イベントオブジェクトから取出したマウス座標と座標空間の変換について解説したい。

表001■マウスイベントとハンドラ設定先
マウスイベント マウス操作 ハンドラの設定先
onClick マウスボタンを押して放す インスタンス
onPress マウスボタンを押す インスタンス
onMouseMove マウスを動かす イベントオブジェクト
onMouseUp マウスボタンを放す イベントオブジェクト

04-01 インスタンスをクリックした座標で回す

まずは、インスタンスをクリックしたときに回してみる。クリックはDisplayObject.onClickイベントで扱い、DisplayObject.rotationプロパティによりインスタンスの回転角を度数で定める。

インスタンスの回転は、基準点を中心に行われる。しかし、これから書くスクリプトは、クリックした座標を中心にして回す。課題となるのは、マウス座標がつねにステージの座標空間にもとづくことだ。インスタンスのクリックされた座標は、インスタンスの座標空間で調べなければならない。そして、そのクリックされた座標が回転でどこに動いたかを求め、そのずれを直せばクリック座標で回したことになる(図004)。

図004■回転した後クリック座標の位置を戻す
図004
クリック座標を記録
図004
インスタンスを基準点で回転
図004
クリック座標の位置を戻す

以下のJavaScriptコード005が、インスタンスをクリックした座標で回す処理だ。まず、クリックのイベントハンドラ(clicked())が受取った引数のマウスイベント(eventObject)から、クリックしたステージ上の座標(MouseEvent.stageXMouseEvent.stageYプロパティ)を取出す(第17〜18行目)。そのxy座標はDisplayObject.globalToLocal()メソッドで、インスタンスから見た座標のPointオブジェクトに変換する(第19行目)。

つぎに、インスタンスを回転してから、クリックされたインスタンスの座標がどこに動いたかを、DisplayObject.localToGlobal()メソッドでステージ上の座標として得る(コード005第21行目)。あとは、ステージの座標空間で、初めにクリックした座標(mouseXとmouseY)と回転で動いた後の座標(globalMouse)の差をとって、インスタンスの位置を直せばよい(第22〜23行目)。

コード005■インスタンスをクリックした座標で回す
  1. var canvas, stage, exportRoot;
  2. var file = "images/Pen.png";
  3. function init() {
  4.   canvas = document.getElementById("canvas");
  5.   stage = new Stage(canvas);
  6.   var loader = new PreloadJS(false);
  7.   loader.onFileLoad = fileLoaded;
  8.   loader.loadFile(file);
  9.   setInstance();
  10. }
  11. function setInstance() {
  12.   exportRoot = new Bitmap(file);
  13.   exportRoot.onClick = clicked;
  14.   stage.addChild(exportRoot);
  15. }
  16. function clicked(eventObject) {
  17.   var mouseX = eventObject.stageX;
  18.   var mouseY = eventObject.stageY;
  19.   var localMouse = exportRoot.globalToLocal(mouseX, mouseY);
  20.   exportRoot.rotation += 15;
  21.   var globalMouse = exportRoot.localToGlobal(localMouse.x, localMouse.y);
  22.   exportRoot.x += mouseX - globalMouse.x;
  23.   exportRoot.y += mouseY - globalMouse.y;
  24.   stage.update();
  25. }
  26. function fileLoaded() {
  27.   exportRoot.x = (canvas.width - exportRoot.image.width) / 2;
  28.   exportRoot.y = (canvas.height - exportRoot.image.height) / 2;
  29.   stage.update();
  30. }
  31. }

04-02 インスタンスをクリックした座標で回しながらドラッグする

つぎは、インスタンスをクリックした座標で回しながらドラッグする(コード006)。ドラッグは、インスタンス上でマウスボタンを押したとき(DisplayObject.onPressイベント)から処理が始まる(第14行目)。

DisplayObject.onPressイベントのハンドラ(clicked())は、クリックしたマウス座標をインスタンスの座標空間に変換する(コード006第18〜20行目)。変換した座標のPointオブジェクトは、関数外(グローバル)でvar宣言した変数(localMouse)に保持する(第3行目)。そして、MouseEvent.onMouseMoveMouseEvent.onMouseUpイベントに、それぞれハンドラの関数(mouseMoved()とmouseReleased())を定めた(第21〜22行目)。

マウスドラッグで呼出されるハンドラの関数(mouseMoved())は、ステージ上のマウス座標(mouseXとmouseY)を調べたうえで、前掲コード005のハンドラ(clicked())と同じ処理でインスタンスの位置を補正する(コード006第25〜30行目)。これで、インスタンスを初めにクリックした座標で回しながらドラッグできる(図005)。

コード006■初めにクリックした座標でインスタンスを回しながらドラッグする
  1. var canvas, stage, exportRoot;
  2. var file = "images/Pen.png";
  3. var localMouse;
  4. function init() {
  5.   canvas = document.getElementById("canvas");
  6.   stage = new Stage(canvas);
  7.   var loader = new PreloadJS(false);
  8.   loader.onFileLoad = fileLoaded;
  9.   loader.loadFile(file);
  10.   setInstance();
  11. }
  12. function setInstance() {
  13.   exportRoot = new Bitmap(file);
      // exportRoot.onClick = clicked;
  14.   exportRoot.onPress = clicked;
  15.   stage.addChild(exportRoot);
  16. }
  17. function clicked(eventObject) {
  18.   var mouseX = eventObject.stageX;
  19.   var mouseY = eventObject.stageY;
  20.   localMouse = exportRoot.globalToLocal(mouseX, mouseY);
  21.   eventObject.onMouseMove = mouseMoved;
  22.   eventObject.onMouseUp = mouseReleased;
  23. }
  24. function mouseMoved(eventObject) {
  25.   var mouseX = eventObject.stageX;
  26.   var mouseY = eventObject.stageY;
  27.   exportRoot.rotation += 15;
  28.   var globalMouse = exportRoot.localToGlobal(localMouse.x, localMouse.y);
  29.   exportRoot.x += mouseX - globalMouse.x;
  30.   exportRoot.y += mouseY - globalMouse.y;
  31.   stage.update();
  32. }
  33. function mouseReleased(eventObject) {
  34.   this.onMouseMove = this.onMouseUp = null;
  35. }
  36. function fileLoaded() {
  37.   exportRoot.x = (canvas.width - exportRoot.image.width) / 2;
  38.   exportRoot.y = (canvas.height - exportRoot.image.height) / 2;
  39.   stage.update();
  40. }

図005■インスタンスをクリックした座標で回しながらドラッグできる
図005

MouseEvent.onMouseMoveイベントのハンドラ(mouseMoved())が受取る引数(eventObject)から得られるマウス座標は、ドラッグしているマウスポインタの位置を示す(コード006第25〜26行目)。その座標と回転したインスタンスの初めにクリックされた座標(globalMouse)との差を埋めれば、インスタンスを回しつつドラッグすることになる。

参考:「EaselJSでインスタンスをクリックした座標で回しながらドラッグする

04-03 インスタンスをドラッグする勢いで回転を加速する

さらに応用した例として「EaselJSでインスタンスをドラッグする勢いで回転を加速する」がある(図006)。Tickerクラスの扱いや物理法則のシミュレーションを学ぶことになる。

図006■インスタンスがドラッグする勢いで回ってドロップすると回転と移動は減速する
図006左   図006右



作成者: 野中文雄
作成日: 2012年7月29日


Copyright © 2001-2012 Fumio Nonaka.  All rights reserved.