サイトトップ

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

HTML5テクニカルノート

Flash Professional CCのHTML5 Canvasドキュメントで子インスタンスに定めた関数を呼出す

ID: FN1405003 Product: Flash CC Platform: All Technique: HTML5 and JavaScript Library: CreateJS

Flash Professional CC 13.1から加わったドキュメント形式の[HTML5 Canvas]を用いれば、入れ子にしたタイムラインのインスタンスがCreateJSで親子の階層としてActionScript 3.0のように扱えます(新たなドキュメント形式については、「Flash Professional CC 13.1のHTML5 CanvasドキュメントとCreateJS」をご参照ください)。ただし、子インスタンスに定めた関数を呼出そうとすると、かなり勝手が違ってきます。


01 子インスタンスを参照しただけではその中に定めた関数が呼出せない

メインタイムラインに置いたインスタンスに、つぎのような簡単なアニメーションの関数(rotate())を定めたとします(図001)。たとえば、インスタンスをクリックしたとき呼出したいのであれば、さらにこの[アクション]パネルにJavaScriptコードを書き足して、イベントリスナーとして加えればよいでしょう。

function rotate() {
  this.rotation += 90;
}

図001■子インスタンスの[アクション]パネルにJavaScriptコードで定めた関数
図001

けれど、子インスタンスのシンボルに定めた関数を、親のタイムラインから呼出したいことがあります。親オブジェクトから子インスタンスを参照するには、this参照に続けて[プロパティ]パネルに定めたインスタンス名(my_mc)を書き加えます。さらに、そのシンボルの中に定義した関数は、ActionScript 3.0なら識別子(rotate())を添えれば呼出せます。

this.my_mc.rotate()

ところが、Flash Professional CCの[HTML5 Canvas]ドキュメントでは、関数は実行されません。ブラウザの開発ツールなどで調べると、関数が参照されていない(undefined)ようです。インスタンスに定めた関数は、プロパティと同じようには扱えないことに注意しなければなりません。

TypeError: 'undefined' is not a function (evaluating 'this.my_mc.rotate()')

02 関数をインスタンスのプロパティとして定める

[HTML5 Canvas]ドキュメントの[パブリッシュ]で書出されるJavaScript(JS)ファイルを調べると、[アクション]パネルでMovieClipインスタンスに加えたJavaScriptコードは、つぎのように0から始まるフレーム番号の「frame_連番」という関数によりフレームごとに分けられています。そして、[アクション]パネルに定めた関数(rotate())は、その中に入れ子になっているのです。

// timeline functions:
this.frame_0 = function() {
  function rotate() {
    this.rotation += 90;
  }
}

これは、おそらくJavaScriptコードがどのフレームで使われるのかを管理する仕組みでしょう。さらには、他のフレームの関数と重複したり、予期せぬ影響が及ぶのを防ぐことも考えられたのかもしれません。ここで大切なのは、入れ子の関数はローカル変数と同じで、外から参照できないということです[*1]。つまり、このかたちで定められた関数は、親インスタンスからは呼出せません。

子インスタンスのシンボルに定めた関数を、プロパティと同じようにインスタンスの参照に添えた識別子でドットアクセスするにはどうしたらよいでしょう。まさに、関数をインスタンスのプロパティとして加えるのです。先ほど子インスタンスの[アクション]パネルに書いた関数(rotate())であれば、つぎのようにインスタンスのthis参照に関数の識別子を与え、名前のない関数のかたちで代入します。

// function rotate() {
this.rotate = function () {
  this.rotation += 90;
}

すると、親タイムラインからは、子インスタンスの参照にドットアクセスで関数の識別子を添えて呼出せるようになります。つぎの親インスタンスのJavaScriptコードは、CreateJSで定めたステージ(stage)をクリックすると、イベントリスナー(callTest())から子インスタンスに定めた関数(rotate())を呼出します[*2]。クリックのたびにインスタンスが90度回るのです(図002)。

var my_mc = this.my_mc;
stage.addEventListener("stagemousedown", callTest);
function callTest(eventObject) {
  my_mc.rotate();
}

図002■ステージをクリックするたびにインスタンスは90度回る
図002


[*1]「入れ子の関数」は「クロージャ」と呼ばれ、その中あるいは外からの参照について特別な性質をもちます。詳しくは、MDN「関数と関数スコープ」の「入れ子の関数とクロージャ」、および「JavaScriptでオブジェクトに設定した関数のスコープ」をお読みください。

[*2] 子インスタンスの参照は、予め変数(my_mc)にとりました。これは、CreateJSのイベントで、リスナー関数内におけるthis参照がグローバルオブジェクトになるためです。


03 子インスタンスの関数を初めに呼出す

前項でご説明したとおり、関数は子インスタンスのプロパティとして定めれば、親オブジェクトから呼出せます。ただし、気をつけなければならないのは、子インスタンスが初めに置かれたフレームで、親オブジェクトから直ちに関数を呼出したい場合です。親子の階層でフレームに書かれたスクリプトは、親から子の順に実行されます。つまり、親のJavaScriptコードは、子が関数をインスタンスのプロパティに定める前に処理されてしまうのです。

そこでどうするかといえば、やむを得ません、1フレーム待ちましょう。CreateJSではTicker.tickイベントでフレームごとのアニメーションを扱います。そのイベントリスナーから、つぎのように子インスタンス(my_mc)の関数(rotate())を呼出し、すぐにリスナー関数は除きます。その前に子インスタンスを見せたくなければ、予め非表示にしておくといったことも必要になるかもしれません

var my_mc = this.my_mc;
createjs.Ticker.addEventListener("tick", callTest);
function callTest(eventObject) {
  my_mc.rotate();
  createjs.Ticker.removeEventListener("tick", callTest);
}

このように見てくると、少なくともFlash Professional CCから[HTML5 Canvas]ドキュメントを[パブリッシュ]するときには、子インスタンスの中は単純なフレーム移動にとどめておき、JavaScriptコードはメインタイムラインに書くのがよさそうです。シンボルの中にメソッドを組込んで、ActionScript 3.0のコンポーネントのようなものをつくるのはかなり難しいでしょう。ActionScriptと同じくクラスのリンケージができると、応用の幅が広がりそうに思えます。



作成者: 野中文雄
作成日: 2014年5月30日


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