海外のこんな記事に行き着いた。
More performance tuning in Actionscript 3
http://www.danielhai.com/blog/?p=55
パフォーマンスの違いは確かにわかるけど、根本的に比較する条件が違うよーな気がする。
海外のこんな記事に行き着いた。
More performance tuning in Actionscript 3
http://www.danielhai.com/blog/?p=55
パフォーマンスの違いは確かにわかるけど、根本的に比較する条件が違うよーな気がする。
前回のエントリー「XMLのロードでnullが返ってくる」で as 演算子と クラス名(target)の違いについて調べてみた。
as演算子によるとキャストできなかった場合にnullが返ってくるかエラーになるかの違いらしい。
でも前回の場合、as の場合はnull で括弧を使った場合は読み込めるっていう感じだった。
あ、野中さんの記事発見。
as演算子は、キャストに利用することができます。ただし、データ自体を変えることはありません。データを変更しなければデータ型が変換できない場合には、nullを返します。
ていうことは、、、
あぁ、やっと気づいた。
つーかURLLoaderでテキストで読み込んでるんだからStringだよね。
バカバカバカ!!!
通常はこうするのね。
function init():void
{
var l:URLLoader = new URLLoader();
l.addEventListener(Event.COMPLETE,onLoadComplete);
l.load(new URLRequest("tinco.xml"));
}
function onLoadComplete(e:Event):void
{
var xml:XML = new XML(e.target.data);
}
あふぉーなオレはこうしていました。
function init():void
{
var l:URLLoader = new URLLoader();
l.addEventListener(Event.COMPLETE,onLoadComplete);
l.load(new URLRequest("tinco.xml"));
}
function onLoadComplete(e:Event):void
{
var xml:XML = XML(e.target.data); // これでも一応XMLに変換できたけど
}
対象ファイルの拡張子とか中身がXML表記でも読み込まれた時はString型なわけ。
URLLoaderのロードしたデータがString型なのに「これはXMLだ!」って言いはっていたわけ。
as演算子を使うとそんなウソは通用しません!っていうことで一件落着。
ちなみにこの記事「【AS3入門】as演算子とカッコ()を使ったキャストの違いCommentsAdd Star」はとても参考になりました。
しょーもないことでしばしばつまづいてしまうのでメモ。
URLLoaderでXML読み込んで、Event.target.dataでXMLを取得する場合。
function init():void
{
var l:URLLoader = new URLLoader();
l.addEventListener(Event.COMPLETE,onLoadComplete);
l.load(new URLRequest("tinco.xml"));
}
function onLoadComplete(e:Event):void
{
// 誤
var xml:XML = e.target.data as XML;
trace(xml) // null
// 正
var xml:XML = XML(e.target.data);
trace(xml) // xmlがちゃんと返ってくる
}
キャストで クラス名() っていうのと as クラス名 ってのの違いをイマイチ理解していない。
他でも同じようなことがたまにあるからちゃんと調べよ。
普段は大量の画像を読み込む場合にBulkLoaderを使っているんだけど、これを自作クラスで
バイナリ一括読み込み→高速表示
的な感じにならないかなーと思って実験。
140枚(中途半端)の画像を読み込み→配置。
// BulkLoaderバージョン
private var imgArray:Array;
public function init(e:Event = null):void
{
t = getTimer();
/*
* BulkLoaderUtilは
* BulkLoaderと画像データxmlを一括読み込みするカスタムクラス。
*/
var l:BulkLoaderUtil = new BulkLoaderUtil("main", "images.xml", "", true); // 自動的にロード開始
l.addEventListener(Event.COMPLETE, onLoadComplete);
}
/*
* 読み込んだ画像をSpriteにぶちこんで配置
*/
public function onLoadComplete(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, onLoadComplete);
imgArray = [];
var l:BulkLoader = BulkLoaderUtil(e.target).getLoader();
/*
* ビットマップを引っ張り出す
*/
for each(var tgt:XML in BulkLoaderUtil.__xml..image)
{
imgArray.push(l.getBitmap(tgt.@id));
}
var n:int;
for (var xx:int; xx < 40; xx++)
{
for (var yy:int; yy < 40; yy++)
{
if (imgArray[n] != null)
{
var sp:Sprite = addChildAt(new Sprite(),0) as Sprite;
sp.addChildAt(imgArray[n], 0);
imgArray[n].x = 50 * xx + 200;
imgArray[n].y = 50 * yy + 200;
n++;
}
}
yy = 0;
}
trace("終了: ",getTimer() - t); // 結果:4300ミリ秒
}
んでこっちはバイナリで読み込み。
// バイナリバージョン
private var imgArray:Array;
private var bildr:BinaryImageLoader;
public function init(e:Event = null):void
{
t = getTimer();
var l:URLLoader = new URLLoader();
l.dataFormat = "text";
l.addEventListener(Event.COMPLETE, onXMLComplete);
l.load(new URLRequest("images.xml"));
}
/*
* 画像をバイナリで読み込み
*/
public function onXMLComplete(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, onXMLComplete);
var xml:XML = XML(e.target.data);
bildr = new BinaryImageLoader();
for each(var image:XML in xml.image)
{
bildr.add(image.@src);
}
bildr.addEventListener(Event.INIT, onLoadComplete);
// 画像のバイナリデータを読み込み
bildr.load();
}
/*
* 読み込んだバイナリを画像に変換
*/
public function onLoadComplete(e:Event):void
{
trace("onLoadComplete");
var bildr:BinaryImageLoader = e.target as BinaryImageLoader;
bildr.removeEventListener(Event.INIT, onLoadComplete);
bildr.addEventListener(Event.COMPLETE, done);
// 全てのバイナリデータをローダーで画像に変換
bildr.createAllImages();
}
/*
* 生成した画像を取得、配置
*/
public function done(e:Event):void
{
var n:int;
var bildr:BinaryImageLoader = e.target as BinaryImageLoader;
imgArray = bildr.getAllImages();
for (var xx:int; xx < 40; xx++)
{
for (var yy:int; yy < 40; yy++)
{
if (imgArray[n] != null)
{
addChildAt(imgArray[n], 0);
imgArray[n].x = 50 * xx + 200;
imgArray[n].y = 50 * yy + 200;
n++;
}
}
yy = 0;
}
trace("終了: ",getTimer() - t); // 結果:4880ミリ秒
}
結果、変わらなかった。むしろ後者のほうが気持ち遅い。
結局読み込み後の変換作業でLoader.loadBytes()で生成、っていうのがあるからそこで時間がかかる。
バイナリデータだけの読み込みは1秒かからないから一瞬心が躍ったのに。
あ、ちなみに画像の数だけLoaderを生成、とかはしてないですよ!
つーことで次回はzipファイル読み込みでどのくらい効率化できるか挑戦してみる。
SoundSpectrumをいじるようになってこれまで敬遠してきたByteArrayとかバイナリとか触るようになってきた。
全然関係ないけど、URLLoaderでバイナリ読み込みのファイルをLoaderにぶち込むと表示できるのね。
var ul:URLLoader = new URLLoader();
ul.dataFormat = "binary";
ul.addEventListener(Event.COMPLETE,comp);
ul.load(new URLRequest("hoge.swf")) // jpegとかでもOK
function comp(e:Event):void
{
var l:Loader = new Loader(); // 表示用ローダー
l.loadBytes(e.target.data);
addChild(l);
}
バイナリを読み込んでるなら拡張子適当に変えても読み込めるのかなと実験。
var ul:URLLoader = new URLLoader();
ul.dataFormat = "binary";
ul.addEventListener(Event.COMPLETE,comp);
ul.load(new URLRequest("hoge.dat")) // hoge.swfの拡張子だけ変更
function comp(e:Event):void
{
var l:Loader = new Loader(); // 表示用ローダー
l.loadBytes(e.target.data);
addChild(l);
}
表示できた。
もっとバイナリ勉強しよ。バイナリバイナリー
flag = !flag; // true flag = !flag; // false
これだけでスイッチできるのねん。
Flash始めて1年以上経つのに今さら気づいた。。。
今までこんな感じでやってたのさ、、
flag ? false : true; // まだマシ if(flag) flag=false; else flag = true; // 帰ってください、、
BulkLoaderで生成したローダーはBulkLoaderクラス内部にインスタンスを保持しているようで、BulkLoader.getLoader(name)で生成済みのローダーをスタティックに参照できる。
/**
* ClassA.asでローダーを生成
*
**/
var loader:BulkLoader = new BulkLoader("main");
loader.add("images/hoge.jpg",{id:"hoge"});
loader.addEventListener(Event.COMPLETE,onComplete);
loader.start();
/**
* ClassB.as
* getLoader("main")で生成済みローダー"main"の参照を取得
**/
var loader:BulkLoader = BulkLoader.getLoader("main") as BulkLoder;
// ロードした画像を取得
var bm:Bitmap = loader.getBitmap("hoge"); // 設定したidから画像を取得
adChild(bm);
ローダーを分けて生成しても個別にBulkLoaderクラスに保持されているので色々と管理が楽。
ぶるぶる振動するジッターエフェクトを作っていて、たまに大きな波を起こしたいと思いまして。
小さな波の中に低確率で大きな波を持たせる方法。
var sp:Sp = new Sp();
addChild(sp);
function update(e:Event):void
{
sp.x = 200 * Math.pow(Math.random(),10);
sp.y = 100;
}
Math.random()関数を10回繰り返す。べき乗されるごとに確立は1/2になっていく、のかな?
値によって何パターンか処理を分岐させる場合はswitchとかだけど、取得した乱数の値をそのまま使用する場合にはお手頃。
タイムライン上に配置したビットマップはShapeとして書き出されることを今知った。CS3ですが。
素材だけタイムラインに置いてクラス側で制御、わざわざ各素材をシンボル化するのが面倒だからgetChildAt()とかで操作しようとしてエラー。
どうなっているのかと表示リストを出力してみたら[Object Shape]が返ってきた。しかも複数のビットマップも書き出し後は単一シェイプとして書き出されていた。
ということで、個別にMovieClipとしてシンボル化するか、クラス側で生成って結論。かな?
CS3のライブラリパネルは使い心地がちょっと、、なのであまり数を増やしたくないというのがそもそもの発端。
これはかなりハマったのでメモ。
Max3DSクラスで拡張子.3dsのモデリングを読込み、ビットマップテクスチャとシェードを適用させたかったんですけど、通常通り読み込み時にShadedMaterialを渡すとレンダリング時にエラーが出てしまう。。
いろいろ試してみた結果、後から(読込み完了後かな)replaceMaterialByName()で画像を差し替えることで解決。
private function setModel(src:String):void
{
var texture:BitmapMaterial = new BitmapMaterial(new Bitmap(new Image(0,0)).bitmapData);
var shader:GouraudShader = new GouraudShader(_light, 0xFFFFFF, 0x000000, 20);
var shaded:ShadedMaterial = new ShadedMaterial(texture, shader);
_model = new Max3DS();
/**
* ここでShadedMaterialを当てるとエラー
**/
_model.load(src, new MaterialsList( { all: texture} ));
_model.addEventListener(FileLoadEvent.LOAD_COMPLETE, function():void
{
/**
* このタイミングでShadedMaterialを差し替えるとOK。
**/
_model.replaceMaterialByName({shaded,"all"})
_scene.addChild(_model);
_renderer.renderScene(_scene, _camera, _viewport);
});
}
ShadedMaterialというか、シェード関連を当てるとエラーになった。現象を把握できるほどPV3Dの知識ないので追求はしないにょ。
ちなみに解決までの足取りはこっちにいろいろ書かせていただきました。