Drag & Drop / CreateJS

チュートリアルの Drag & Drop やってみる。
まずはオブジェクトをクリックした時のイベント指定。

1
object.onPress = handlePress;

この時 handlePress 内で onMouseMove と onMouseUp のイベント指定しちゃいます。
そうする事でマウスのボタンが押されている間だけこの指定が有効になります。

1
2
3
4
function handlePress(){
    e.onMouseMove = handleMouseMove;
    e.onMouseUp = handleMouseUp;
}

ドラッグ時の移動はマウス座標を使って指定します。
この時対象のオブジェクトは下記のように target として取得できます。

1
2
3
function handreMouseMove(e){
    e.target.setTransform(e.stageX, e.stageY);
}

CreateJS使うと簡単ね。

氷菓のエンディングっぽい動き / CreateJS

CreateJSつかって氷菓のエンディングにあるテキストでキャラクタが描かれる動きをつくってみるよ。
2クール目EDの1分過ぎくらいのとこね。

とりあえず、前回やったお絵かきを使おうかな。
描画の時に使った座標をひと通り保存して、それをテキストに置き換えることに。
なんか既に重くなりそうな雰囲気だが…

テキストはあらかじめ a-z, A-Z で用意しとく。
CreateJSのテキストオブジェクトで1文字ずつ用意してみる。

1
2
3
4
5
6
7
8
9
var text = [];
for (var i = 65; i <= 90; i++){
    var t = new createjs.Text(String.fromCharCode(i), '20px serif', color);
    text.push(t);
}
for (var i = 97; i <= 122; i++){
    var t = new createjs.Text(String.fromCharCode(i), '20px serif', color);
    text.push(t);
}

絵を描いて再生ボタンを押すとアニメーションを再生。
その際に各座標ごとにランダムでテキストオブジェクトを割り当てます。
既にあるテキストオブジェクトから下記のようにして生成できます。

1
2
var index = Math.floor(Math.random() * text.length);
var shape = new createjs.Shape(text[index]);

正確な再現はあきらめて、ランダムな位置から描画した座標に移動、そして消えるようにしてみました。
wait で指定時間だけ動きを止めることができます。
他にも scale, rotation, alpha などランダムで動かすとよりそれらしくなると思います。

1
2
3
4
5
6
7
stage.addChild(shape).setTransform(x, y);
createjs.Tween.get(shape, { loop: true })
    .wait(800)
    .to({ x: drawX, y: drawY }, 1600)
    .wait(1000)
    .to({ x: drawX + dx, y: drawY + dy, alpha: 0 }, 1500)
    .wait(300);

こんな感じでとりあえずそれらしくは出来るのですが、ちょっと細かい絵を描くとすんごい重くなります…
まあ、座標の数が増えればそんだけテキストオブジェクトの数も増えるんだから当たり前よね。
という訳で、標準で用意されてるキャッシュの機能とかで軽くなるか試してみました。

まずは snapToPixel をオンにして描画される座標を丸め込みします。
特にビットマップ画像の時は有効みたいです。
これは親オブジェクトや stage についてもオンにしておかないと有効にならないようです。

1
2
3
4
5
// stage でオン
stage.snapToPixelEnabled = true;

// オブジェクトでオン
t.snapToPixelEnabled = true;

あとはキャッシュ機能もオンにするとだいぶ改善されます。
最初のテキストオブジェクト生成時に下記のよう指定します。
引数はキャッシュする範囲の始点と幅と高さです。
この場合はオブジェクトの大きさにします。

1
2
3
var w = t.getMeasuredWidth();
var h = t.getMeasuredHeight();
t.cache(0, 0, w, h);

拡大するときはさらにオプションで指定可能です。
移動や回転、透過してもキャッシュは有効なのでかなり自由度高いと思う。

マウスの動きに合わせて線を引く / CreateJS

チュートリアルにある Finger Paint やってみる。
マウスイベントの続きだけど、canvas (CreateJSのstage) でのイベント処理と言う感じ。

MouseMove イベントで拾ったマウス座標を使って、一つ前から今の座標まで線を引きます。
stage でも図形と同じように下記のように指定します。

1
stage.onMouseMove = handleMouseMove;

前回の座標を old として、MouseMove イベントで呼び出される度に線を引きます。
現在の座標は event.stageX, event.stageY を使います。

1
2
3
4
function handleMouseMove(event){
    line.graphics.s('#F00').ss(size, 'round').mt(old.x, old.y).lt(event.stageX, event.stageY);
    old = { x: event.stageX, y: event.stageY };
}

ちなみにキャンバスからマウスがはみ出た場合に、座標がキャンバスサイズ以上にならないオプションも用意されてます。
その際、キャンバスからはみ出た実際の座標は event.rawX, event.rawY で取得できるみたい。ホント気が利くなあ。

1
2
stage = new createjs.Stage('canvas');
stage.mouseMoveOutside = true; // はみ出ない

Mouse Interaction / CreateJS

CreateJSでつくったオブジェクトをマウスイベントに反応させる。
付属のチュートリアルに沿ってやってくよ。

クリックだけなら必要ないけど、マウスオーバー・マウスアウト使う時は下記のような宣言が必要です。
enableMouseOver は引数に一秒間に何回マウスオーバーを拾うか指定できる。(20回がデフォ)

1
2
stage = new createjs.Stage('canvas');
stage.enableMouseOver(10);

イベントはオブジェクト毎に指定します。
onClick, onMouseOver, onMouseOut, onPress, onDoubleClick などに指定可能です。

1
2
3
4
var object = new createjs.Shape();
object.onClick = function(){
    alert('クリック');
};

テキストだと隙間があるので hitArea の指定が可能です。

1
2
3
text = new createjs.Text('Text with hitArea', 'bold 20px Arial', 'red');
text.hitArea = new createjs.Shape();
text.hitArea.graphics.f('white').dr(0, 0, text.getMeasuredWidth(), text.getMeasuredHeight());

他にも、複数オブジェクトをまとめられる Container とかあって便利!
その場合は、コンテナにイベント付けたら子のオブジェクトのイベントを無視できたりと、すごくよくできてます。

1
2
container = new createjs.Container();
container.mouseChildren = false;

座標系変換 / CreateJS

CreateJSのチュートリアルにある座標系変換。
マウス座標をオブジェクトの座標に変換する場合、以下のようにします。

1
var pt = circle.globalToLocal(stage.mouseX, stage.mouseY);

stage.mouseX, stage.mouseYからマウス座標がとれるので、それを globalToLocal でオブジェクトの座標系に変換します。
この場合、pt.x, pt.y に変換後の座標がはいってます。
さらに hitTest を使用すれば、マウスがオブジェクトに乗っかってるか判定できます。

1
2
3
if (circle.hitTest(pt.x, pt.y)){
    // hit!
}

これで複雑な親子構造になっているオブジェクトでも簡単に座標計算できます。
逆の localToGlobal も、アニメーションするオブジェクト同士の localToLocal も用意されてます。

Tween 機能でアニメーションをつける / CreateJS

CreateJSのTween機能でアニメーションつけてみる。
これを使うとまとめて設定できます。

1
2
3
var start = 0;
var end = 400;
createjs.Tween.get(circle,{loop:true}).to({x:end}, 5000).to({x:start}, 0);

get で対象オブジェクトを指定します。
その際にオプション指定できます。
{ loop: true } はアニメーションのループを指定。
オプションは公式のドキュメント参照。
http://createjs.com/Docs/TweenJS/Tween.html

to で動きの指定と、完了までの時間をミリ秒で指定できます。
to は複数指定できるので、一連のアニメーションをまとめられます。
Tween には easing 機能も用意されてるので、いろんな動きも指定できるみたいで楽しそう。

アニメーション基礎 / CreateJS

CreateJSでアニメーションやってみる。
チュートリアルにある Animation and Ticker を参考にしつつ。

フレームごとに少しずつオブジェクトを動かします。まあ、基本的な考え方はどれも同じよね。

1
2
circle.x += 100; // 100pix移動
stage.update();

ループは setInterval や setTimeout でもよいけど、Ticker と言う機能が用意されてます。
すると tick という関数が毎度呼ばれるので、これに処理を記述します。
フレームレートの指定もできます。(デフォルトは20FPS)

1
2
3
4
5
6
7
8
9
10
11
12
var FPS = 30;
var speed = 100; // pix / sec
speed /= FPS;
function init(){
    // 初期化処理の中で指定
    createjs.Ticker.addListener(window);
    createjs.Ticker.setFPS(FPS);
}
function tick(){
    // Ticker から毎フレーム呼ばれる
    circle.x += speed;
}

ただ、これだとフレームレートが動的に変化するような場合に、移動スピードも変わってしまいます。
これに対応する機能が CreateJS では用意されています。
下記のように elapsedTime にミリ秒単位で時間差を取得できるので、これを元に移動量を決定します。

1
2
3
4
5
var speed = 100; // pix / sec
speed /= 1000; // pix / ms
function tick(elapsedTime){
    circle.x += elapsedTime * speed;
}

CreateJSさわってみる

ゲーム系のJavaScriptライブラリの中でCreateJSが気になってたのでちょっとさわってみることに。
とりあえず付属してるチュートリアル参考にしつつ。

まずはライブラリの読み込み。
最近はCDN用意されてるもの増えたね。

1
<script src="http://code.createjs.com/easeljs-0.5.0.min.js"></script>

あとは描画用の canvas と onload で呼ばれる関数の指定。
まずはチュートリアルにしたがって下記のように指定。

1
2
3
<body onLoad="init();">
    <canvas id="demoCanvas" width="640" height="480"></canvas>
</body>

ひとまず準備はこれだけ。
あとは init 関数に処理指定すればイイみたい。

描画する canvas は id 属性にて指定、最後にupdateします。
stage とかは Flash の ActionScript ライクになってる模様…ActionScript 知らんけど。

1
2
3
4
5
6
7
function init(){
    var stage = new createjs.Stage("demoCanvas");

    // 図形の処理とかここに描く

    stage.update();
}

例えば半径50pxの赤い円を描きたければ次の感じで。
いったん Shape つくって、drawCircle や drawRect、lineTo など指定します。

1
2
3
4
5
var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
circle.x = 100;
circle.y = 100;
stage.addChild(circle);

それぞれ、ショートカットも用意されていて、beginFill = f, drawCircle = dc とか用意されてます。
ドキュメントは見当たらなかったけど、Graphics.js みると最後の方にまとめて指定あります。
そうすると、まとめて下記のようにもかけます。

1
stage.addChild(new createjs.Shape()).setTransform(100,100).graphics.f("red").dc(0, 0, 50);