「Canvas」カテゴリーアーカイブ

【CreateJS】AS3からHTML5 Canvasに書き出す場合のJavaScript(その3)2017年版

【MacOS Seria+Adobe Animate CC 2017.5リリース】
swfで作ったコンテンツをHTML5 Canvasに書き出すお勉強のその3です。

その2から随分間が空きましたが(笑)、ちょうど以前開発したAS3コンテンツをまとめてCanvas化する仕事があって、思い出しつつ調べつつ作業したので、2017年10月の時点でどのように変換したかをまとめておきます。

前提とするコンテンツは下記のようなものです。

・Flash IDE(いわゆる純正のFlashアプリケーション)で作成されたもの。
・スクリプトを外部ファイル化していない(関数などは1フレーム目にまとめて定義)。
・タイムラインとActionScriptを併用している(定義した関数や変数をフレームで呼び出すようなもの)

ちょっとしたインタラクションとアニメーションを絡めたようなコンテンツは、わざわざクラスファイルを外部化するのも面倒だし、こういう作り方してる人も多いんじゃないかと思います。FlashDevelopやFlash Bulderなんかでガリガリ作ったものは、その筋の人たちにお任せします(笑)。

0.FlaファイルをCanvas形式に変換する。

コマンド>他のドキュメント形式に変換 を選択します。

ドキュメントタイプコンバーターで「HTML5 Canvas」を選択してファイル名、保存場所を指定してOKを押します。

ドキュメントタイプコンバーターのポップアップ

※この時、全てのActionScriptはコメント化されます。「this.stop();」などそのまま使えるものもコメント化されるので要注意。

1.型は全て削除する(:uint や as MovieClipなど)。

JavaScriptにはないので当然ですね。アクションパネルなどで一括置換が漏れがなくてオススメです。

2.タイムラインのどこからでも使いたいものは、アクション>グローバル>スクリプトに書く(のグローバル化)

1フレーム目に関数(function)を書いて、別のフレーム(例えば10フレーム目)で呼び出すのは、ASではよくやりますが、これがそのままではJavascriptで動きません。その場合は、アクションパネルでアクション>グローバル>スクリプトを開いて、ココに書きます。ココに書かれた変数や関数はグローバル化されるので、this参照なしでどこからでも呼び出せます。

アクションパネルの左側から、グローバル>スクリプトを選択します。

・スクリプト例(定義:グローバル>スクリプト)

//---アニメフラグ
var flg_anime = true;

//ボタン:切替
function switchBtn(flg)
{
	if (flg)
	{
		//アニメーション開始;
		startAnimation();
	}
}

・スクリプト例(呼び出し;フレームスクリプト)

//ボタン:初期化
switchBtn(flg_anime);

※ flg_anime, switchBtn()共にグローバルなので、this等の修飾なしで使用できる。

グローバル>スクリプトの関数で、ステージ上に配置されたMovieClipやボタン、ステージのタイムラインなどを使用する場合は、exportRootで参照します。

・スクリプト例(定義:グローバル>スクリプト)

//アニメーション開始
function startAnimation()
{
	exportRoot.gotoAndPlay("f_anime");
}

3.MovieClip内の関数

タイムラインが1フレームしかないもので、MovieClip内で完結する変数、関数は、そのままthis等の参照なしでフレームに書いてOK。
・そのMovieClip内に閉じたものは、function xxx(){} で定義したものをthis.xxx()で参照すればよい。

・スクリプト例(MovieClip;フレームスクリプト)

//何か例を入れる

但しMovieClipの外部から参照する変数、関数はプロパティにする必要があります。
・this.xxx = function(){} な書き方。

//何か例を入れる

4.プロパティパネルに書いたインスタンス名は参照出来ない。

ボタンやMovieClipでインスタンス名で参照したいときは、明示的にnameプロパティに文字列を設定する必要があります。

・スクリプト例(定義:グローバル>スクリプト)

//ボタン:初期化
function inithBtn()
{
	exportRoot.btn_up_year.name = "btn_up_year";
	exportRoot.btn_up_month.name = "btn_up_month";
	exportRoot.btn_up_day.name = "btn_up_day";
}

※MovieClipなら、MovieClip内のフレームで、this.name = “xxx” でも定義できる。

5.円形グラデーションやフィルターなどは使えない。

・HTML5 Canvasに書き出すのに制限があります。ライブラリ上でビットマップに変換しておくか、場合によってはビットマップで作り直す必要があります。

6.MouseEvent.MOUSE_UP >> pressup

・ここは “mouseup” じゃないので要注意。

処理 AS JavaScript
クリック MouseEvent.CLICK click
マウスオーバー MouseEvent.MOUSE_OVER mouseover
マウスアウト MouseEvent.MOUSE_OUT mouseout
マウスダウン MouseEvent.MOUSE_DOWN mousedown
マウスアップ MouseEvent.MOUSE_UP pressup
ロールアウト MouseEvent.ROLL_OUT rollout

7.Movieclip内の関数でのthis参照

関数内でのthisを参照すると、ページのルートであるWindowを指します(詳しくは、別記事の「4.thisの参照」を参照のこと)。
MovieClip内の関数で、相対的にパスを指定したいときは、関数外で変数にthisを入れておき、それを使って参照します。

・スクリプト例(定義:MovieClip内のフレームスクリプト)

//関数内での参照用にthisを変数化
var my_mc = this;

//初期化
this.init = function ()
{	
	my_mc.open_cap.visible = false;
	my_mc.close_cap.visible = false;

}

8.MovieClipボタンのカーソル対応

“buttonMode” は”cursor”に変更します。

処理 AS JavaScript
指カーソルにする MovieClip.buttonMode = true; MovieClip.cursor = “pointer“;
デフォルトカーソルにする MovieClip.buttonMode = false; MovieClip.cursor = “default“;

9.TFLは使えない。

・強制的に普通のテキストに変換されるので、注意が必要です。

10.Dateオブジェクトの扱いに注意

ActionScriptにもJanaScriptにも同じようにDateオブジェクトがありますが、年月日時分秒を取得する際に、ActionScriptはプロパティで、JavaScriptはfunctionのため、微妙に違うので要注意。

処理 AS JavaScript
Dateオブジェクト生成 var date:Date = new Date(); var date = new Date();
年(4桁) date.fullYear date.getFullYear()
date.month date.getMonth()
date.date date.getDate()
date.hours date.getHours()
date.minutes date.getMinutes()
date.seconds date.getSeconds()

11.MovieClipのwidth,height

MovieClip.nominalBoundsで取得可能です。

・スクリプト例(定義:MovieClip内のフレームスクリプト)

this.tft07.nominalBounds.width
this.tft07.nominalBounds.height

【参考】
・X-LABO: Toolkit for CreateJS & Haxe : シンボルの初期表示サイズ・位置情報取得 nominalBounds
・Animate CCで書きだしたCreateJSのグラフィックスの色をプログラム上から変更する – Qiita

createjs – How to change the width of a movieclip in flash html5 canvas? – Stack Overflow

12.MovieClipをリストアップする

多くのMovieClipを配置して制御する場合、ひとつずつに名前をつけたりするのも大変なので、MovieClipだけを配列化して使う場合があります。

・ActioScript例

function initBit():void
{
	array_bit = [];
	
	for (var i:uint=0; i<this.numChildren; i++)
	{
		var ds:DisplayObject = this.getChildAt(i);

		if (ds is MovieClip)
		{
			array_bit.push(ds);
			ds.visible = false;
		}
	}

}

この「is MovieClip」がjavaScriptにないので、どうしようかな?と考えて、MovieClipにはtimelineが存在するので、それを代替にしてMovieClipのみをリストアップすることにしました。まあ気づけばたいした話ではないんですが。

・JavaScript例

his.initBit = function ()
{
	array_bit = [];
	
	for (var i=0; i<this.numChildren; i++)
	{
		var ds = this.getChildAt(i);

		if (!!ds.timeline)
		{
			array_bit.push(ds);
			ds.visible = false;
		}
	}
}

だいたいこんなところだと思いますが、抜けがあったらまた更新します。

以前書いたブログもよければご参考に。

【CreateJS】AS3からHTML5 Canvasに書き出す場合のJavaScript(その1) | AS blind side
【CreateJS】AS3からHTML5 Canvasに書き出す場合のJavaScript(その2) | AS blind side

【追記】
早速、12.を追記しました(2017.10.11)。

A-FRAMEを使ってみた(2)タグ編

A-FRAMEのドキュメントを見ていて、サンプルなどに出てくるタグが見当たらないことがあったのでまとめてみました。ドキュメントは機能や要素毎にまとめられているので、タグから引けないので。

A-FRAME タグ一覧(version 0.2.0 版)

タグ名 ドキュメント 備考
<a-scene> Scene A-FRAMEの global root object。canvasもここに含まれる。
<a-entity> Entity オブジェクトの位置、回転、およびスケールのなどを定義するタグ。
<a-animation> Animations アニメーションを定義するためのタグ
<a-assets> Asset Management System プリロード要素を定義するためのタグ
<a-mixin> Mixins <a-assets>内に定義する、再利用可能なコンポーネント属性を定義するタグ
<a-asset-item> Asset Management System <a-assets>内に定義する3D用のファイル(.dae,.mtl,obj)。
<audio> Asset Management System <a-assets>内に定義する音声ファイル。
<img> Asset Management System <a-assets>内に定義する画像ファイル。
<video> Asset Management System <a-assets>内に定義するビデオファイル。
<a-box> <a-box> 箱状オブジェクト。ver 0.1.0までは、<a-cube>
<a-camera> <a-camera> カメラオブジェクト
<a-collada-model> <a-collada-model> 3D COLLADA オブジェクト(.dae)
<a-cone> <a-cone> 円錐オブジェクト
<a-cursor> <a-cursor> カーソルポインタ
<a-curvedimage> <a-curvedimage> 湾曲した板状オブジェクト
<a-cylinder> <a-cylinder> 円柱オブジェクト
<a-image> <a-image> <a-plane>に画像を適用したオブジェクト
<a-light> <a-light> 照明オブジェクト
<a-obj-model> <a-obj-model> 3Dオブジェクト。.obj、.mtlを指定可能。
<a-plane> <a-plane> 板状オブジェクト
<a-ring> <a-ring> 板状のリングオブジェクト。radius-inner=”0″ (内径=”0″)で円盤状になる。
<a-sky> <a-sky> シーンの背景
<a-sphere> <a-sphere> 球体オブジェクト
<a-torus> <a-torus> 円管形状オブジェクト(arc=360 でドーナツ状)
<a-video> <a-video> <a-plane>にビデオを適用したオブジェクト
<a-videosphere> <a-videosphere> シーンの背景に動画を適用したオブジェクト

上記の説明は、執筆時点でのA-FRAME version 0.2.0 を前提としています。

不備、誤りなどありましたらご指摘下さい。

A-FRAMEを使ってみた(1)360°画像編

Playstation VRの予約が始まったり、諸々盛り上がりを見せつつあるようにみえるVR界隈。興味はあるけど、Oculus Riftもその開発にPC用意するとか考えると結構なお値段だし、基本静観してたのですが、HTMLベースのVR用のフレームワークである「A-FRAME」の記事をみつけたので、試してみました。

「A-Frame」でVR開発入門!HTMLの追記だけでスマホブラウザから好きな場所を360度パノラマ画像体験 – paiza開発日誌

まずは上の記事を参考に、360°パノラマ画像のVRを作ってみました。

1.特別な機材なしで360°パノラマ画像を作る。

通常、360°パノラマ画像を作るにはRICOH THETAなどの対応カメラが必要ですが、iOS/Android用のGoogle ストリートビューアプリで作成が可能です。使い方は、上の参考リンクに詳しいのでをそちらを参照のこと。

複数の画像をつないで全天球型の画像を作成するので、撮影回数が多くなるのが難点ですが、特別な投資なしで作れるのでテストとしては十分だと思います。ちなみにこんな感じの画像が生成されます。

ストリートビューアプリで作成した360°画像。なるべく被写体(人や物)が近くにない方が繋ぎがうまくいく(ズレが目立たない)ようです。
ストリートビューアプリで作成した360°画像。なるべく被写体(人や物)が近くにない方が繋ぎがうまくいく(ズレが目立たない)ようです。

2.HTMLを書く

VRコンテンツとして表示するために、HTMLを書きます。A-FRAMEは基本的にはタグベースなので、A-FRAMEのjsライブラリを読み込んで、必要なタグを書くだけです。以下、サンプルのHTML全文です。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>神保町の路地 | A-Frame</title>
    <meta name="description" content="神保町の路地 | A-Frame">
    <script src="https://aframe.io/releases/0.2.0/aframe.min.js"></script>
  </head>
  <body>
    <a-scene>
        <a-sky src="img/IMG_2277.jpg"></a-sky>
        <a-camera wasd-controls-enabled="true"></a-camera>
    </a-scene>
  </body>
</html>

<a-scene>は、canvasタグに相当します。その中に要素を定義していきます。
<a-sky>は、VR空間の背景です。VR空間が大きな球体として定義されていて、その内側にカメラがあるイメージです。その球体の内側に色や360°パノラマ画像を指定することで背景として表示されます。
<a-camera>は、カメラです。スマホだと端末の傾き、PCならマウスのドラッグ方向で、このカメラの向きが変わります。

※<a-camera>が省略された場合は、デフォルトのカメラが設置されるので、このタグがなくても表示されます。

iPhoneで見た様子。右下のメガネアイコンをタップするとWebVRモードで表示されます。
iPhoneで見た様子。右下のメガネアイコンをタップするとWebVRモードで表示されます。
WebVRモードで表示した様子。PCブラウザなどWebVRがサポートされていない場合は切り替えできない。
WebVRモードで表示した様子。PCブラウザなどWebVRがサポートされていない場合は切り替えできない。

実際のサンプルは、下のリンクからどうぞ。

神保町の路地 | A-Frame

【CreateJS】Canvasのアニメーションを動的に切り替える

Canvasでアニメーションだけなら、JavaScript書かずにFlash CC(Animate CC)で書き出せばいいよね。Flashまだまだ使えるよ!なんですが、実際運用するとなると、ある時期でアニメーション切替、追加、削除等の変更が出てきます。AS3.0ならloadMovieでswf切り替えればよかったんですが、「CanvasにはloadMovieとかないし、どうするの?」と思ったら、意外とカンタンな話だったのでまとめておきます。

まずはアニメを作ります。
1つ目。Flash CC(今回はFlash CC 2015を使用)で、新規から「HTML5 Canvas」を選択してクラッシックトゥイーンでアニメーションして書き出しただけ。完成品はこちら

アニメその1

 

2つ目。作り方は同じ。完成品はこちら

anime2

 

で、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