倉庫番とTenorionを合わせたらどうなるか?


タイトルのようなものを、年末あたりに思いついたんですが、途中まで作って完成させていませんでした。

Tenorionは正確にはTENORI-ONと書く、ヤマハの電子楽器です。→詳しくはこちら

これをFlashで再現されたのがこのFlashで、SiONというライブラリを使って実装されています。

SiON Tenorion

面白いですよね。

これを何かと合わせて別のものができないか、と考えたのがこちらになります。

倉庫番+Tenorion実験(音注意!)

倉庫番 + Tenorion 実験 – wonderfl build flash online

緑が自機。青が箱、黄色がターゲットで箱が重なってる時は薄い青になります。倉庫番のルールはそのままで、緑の人を動かして、青い箱を黄色の所に全て配置すればクリアです。箱の位置によって、音が変わります。全て配置すると・・・?

普段作成するコンテンツがPlayer9ばかりだったもので、Vector型をまともに使うのが初めてで、ちょっと混乱しました。

これで音がうまいこと作られたら楽しいことになりそうです。しかしそうなるとステージを作るのが難しくなるので、両立は難しそうですが。まあ実験でした。

TweenerのuseFrames


Tweenerを普段良く使うのですが、あまり使ってなかった機能で、最近便利だと思った機能があります。useFramesというオプションです。

使い方は次のような感じ。

Tweener.addTween(target, {useFrames:true, alpha:1, time:3, transition:'easeOutQuad'});

useFramesをtrueにすると、timeの値がフレーム数で指定できるようになります(この場合は3フレーム)。また、アニメーションもタイマーではなく、フレームレートによるタイミングで動作します。(古いリビジョンでは動かないとありますが、最新のものは大丈夫そうです)

つまりフレームレートが落ちているときに、タイミングがずれたりしないのです。これがすごく大事。

タイムラインアニメーションとスクリプトによるアニメーションを併用することがわりとあると思いますが、Tweenerは基本的にタイマーで動作するため、フレームレートが落ちたときに、アニメーションがずれてしまうことがあります。このオプションでこのズレを回避できます。

できるだけフレームレートが落ちるような処理を回避して軽く作る、というのが大事と思っていますが、低スペックマシンで再生したときに変な動きをする、あるいはエラーで止まってしまうなんて事が無いように、両方使う場合には使ってみるといいかもしれません。

他のTweenライブラリでこういうフレームレートに応じた処理を入れてるライブラリはあるんだろうか・・・と思ったらBetweenAS3にもあるみたい(_frame)。さすが。

Eventメタデータタグを便利に使う


AS3のEventメタデータタグは何のためにあるの?というTogetterを見て、そういえば自分も調べたけど何も書いてなかったなぁと思ったのでメモ。

自分でカスタムイベントを作成すると、addEventListenerしたときのコードヒントにカスタムイベントが出てこなくて面倒だな、と思っていたんですが、Eventメタデータタグを使うと楽ができます。

ActionScriptのメタデータタグについては公式のこちらをどうぞ。

使い方は

[Event(name="eventName", type="package.eventType")]

というような感じで、カスタムイベントクラスの中・・・ではなく、そのイベントをdispatchするクラス(IEventDispacherなクラス)に書く感じになります。

すると、他でそのdispatchするクラスを使ってaddEventListenerしたときにコードヒントがでてくれます。

注意点としては、メタデータタグを書く位置をclassの書いてある位置の上(public class Hoge{}より外側)にすること。メタデータタグ内のプロパティは2重引用符/ダブルクォーテーション(“)で囲うこと

普段文字列はシングルクォーテーション派なので、何をどうやっても動かず、かなり悩まされました。。普通ダブルクォーテーションなんですかね。(FlashBuilderでの場合。FlashDevelop他では動くんでしょうか)

また、Eventのtypeに入れた名前がそのまま定数として大文字+アンダーバーに変換されるので、「hogeFugaXML」みたいなtypeにすると、「HOGE_FUGA_X_M_L」とか残念な変換をされてしまいます。これが実際のEvent側で用意している定数と違う場合、動作しなくなってしまうので注意が必要そうです(この場合はhogeFugaXmlと書けば正常に動作するはず)。

自分で作ったクラスの場合は特に書かなくてもいい場合がほとんどと思いますが、人に渡すものだったりする場合は、書いたほうが親切かなと思うので、有効に使っていきたいです。

参考:

カスタムクラスのプロパティをfor..inで出力


wonderflに昔、こんな感じでforkしてみたものがあったんですが、理由が分からなかった部分を調べたまとめ。

通常、for..inをした場合、Objectとして作成したものは出力できますが、カスタムクラスのプロパティだとそれができません。

//Objectだとできる
for(var i:uint = 0; i < LOOP; i++){
    var id:String = 'id' + String(i+1);
    var name:String = 'name' + String(i+1);
    var obj:Object = new Object();
    obj.id = id;
    obj.name = name;
    _listObject.push(obj);
}
for(i = 0; i < LOOP; i++){
    var o:Object = _listObject[i];
    for(var prop:String in o){
        trace(o[prop]);//できる
    }
}

//カスタムクラスのプロパティはでない
for(var j:uint = 0; j < LOOP; j++){
    var id:String = 'id' + String(j+1);
    var name:String = 'name' + String(j+1);
    var obj:TestObject = new TestObject();
    //TestObjectはidとnameをpublic変数に持つものとする
    obj.id = id;
    obj.name = name;
    _listObject.push(obj);
}
for(j = 0; j < LOOP; j++){
    var o:Object = _listObject[j];
    for(var prop:String in o){
        trace(o[prop]);//何も出力されない
    }
}

何故できないのか、と考えてみたんですが、for..inする場合には、そのクラスでpropertyIsEnumerable(プロパティ名)というメソッドを使った時にtrueが帰ってくる必要がありそうです。

ただ、こちらのメソッド、Objectに定義されているものをoverrideすることはできないので、書く必要があるんですが、全てtrueが帰るようにしてもうまく動作しません。prototypeを拡張しても効果無しです。

しかし、たまたまいじっていたらpropertyIsEnumerableがtrueになった、というかfor..inで出力されるようになりました。そのクラスのprototypeにプロパティと同名の変数を定義した場合です。

Object型の場合は値を代入した瞬間に同様の処理をされているのか?とも思いますが、理由は良く分かりません。

サンプルはこちら。

どうせデバッグ用にしか使わないだろうので、処理速度がどう変わるのか、などは検証していません。これが自動化できれば凄く便利な気もします。ただそもそもプロパティの列挙をするためにプロパティを全て知らなければいけないという面倒さがありますし、整形して出力したければ、toStringを実装する時にそのように書いた方が楽な気がしますし。

というわけで、調べたことのメモでした。

Flashのライブラリから画像をエクスポートするJSFL


どうもお久しぶりです。

移転してから何も書いてなかったんですが、仕事に余裕がでてきたので何か書いてみようと思う次第であります。

今回のはFlash自体にはありそうでない機能、ライブラリにある画像をファイルとして書き出すJSFLです。

ソースはこんな感じに。

var _doc = fl.getDocumentDOM();
var _lib = _doc.library;
var _exportFolderURI = '';

function main(){
	var selectedItems = _lib.getSelectedItems();
	var numItem = selectedItems.length;
	if(numItem == 0){
		fl.trace("何かファイルを選択してください。");
	}
	else{
		_exportFolderURI = fl.browseForFolderURL('画像の保存先を選択してください');
		if(_exportFolderURI){
			for(var i = 0; i < numItem; i++){
				exportImage(selectedItems[i]);
			}
			fl.trace("エクスポートが完了しました。");
		}
		else{
			fl.trace('キャンセルしました');
		}
	}
}

/**
 * 画像ファイルだったらエクスポート
 * @param item:Item
 */
function exportImage(item){
	if(item.itemType != 'bitmap'){
		return;
	}
	var path = item.name;
	var pathAry = path.split('/');
	var name = pathAry.pop();
	var ext = '';
	if(name.indexOf('.') == -1){
		ext = (item.originalCompressionType == 'photo') ? '.jpg' : '.png';
	}
	
	item.exportToFile(_exportFolderURI + '/' + name + ext);
}
main();

現在選択しているライブラリの~とか余計な部分を省くと、

item.exportToFile(_exportFolderURI + '/' + name + ext);

だけですw 簡単ですね!CS4から使えるようになった機能なので、CS3以前では使えません。圧縮率を戻して画面のキャプチャを取れば大体はなんとかなるかもですが、アルファかかってるものは面倒そうですしね。こちらでさくっとエクスポートするのが良いかと思います。

上のコピペでもいけると思いますが、一応ファイルも。

imageExport.zip

使い方はこちらの公式資料を参考に。CS5でも同じような位置にあるかと思います。