AS3.0の最近のブログ記事

今更ながら周りの影響で、QucikBox2Dをいじってます。@alumican_net さんが書かれたブログがわかりやすいので拝見してますが、『 QuickBox2DやBox2DFlashAS3での衝突判定をグループ分け 』という記事で以下のような記述がありました。

自分と何かが衝突するかどうかは、自分のmaskBitsと相手のcategoryBitsの論理積をとって計算できる。結果が0なら衝突しない、0以外なら衝突する。

普段あまり使わないので「論理積ってなに?」って状態だったんで調べてみると、大重美幸さんのActionScript3.0入門ノートにわかりやすい解説がありました。

ビット単位の論理和では値を2進数に換算して各ビットごとに比較し、どちらかが1ならば1にします。たとえば、6(2進数で110)と5(2進数で101)のビット単位の論理和は7(111)になります。同様にビット単位の論理積では両方が1のときに1にし一方が0ならば0にします。6と5のビット単位の論理積は4(100)になります。
2進数における桁のシフトは2のn階乗で変化します。次のサンプルで使われているrgbToHex()はRGBの各色の値から0xFFFFFFの形式の16進数に変換する関数です。

なるほど!ということで、実際に計算してみました。

maskBits:0x0007(0111) &  categoryBits:0x0004(0100) >> 4(0100):衝突する

maskBits:0x0007(0111) &  categoryBits:0x0008(1000) >> 0(0000):衝突しない

maskBits:0x0007(0111) &  categoryBits:0x0002(0010) >> 2(0010):衝突する

maskBits:0x0007(0111) &  categoryBits: 0x00020010) >> 2(0010):衝突する

maskBits:0x0007(0111) &  categoryBits:0x0008(1000) >> 0(0000):衝突しない

maskBits:0x0007(0111) &  categoryBits: 0x00040100) >> 4(0100):衝突する

・■
maskBits:0x0001(0001) &  categoryBits: 0x00020010) >> 00000):衝突しない

maskBits: 0x00010001) &  categoryBits: 0x00040100) >> 0(0000):衝突しない

maskBits: 0x00010001) &  categoryBits: 0x00081000 >> 0(0000):衝突しない

ふむふむ。確かに先の引用通り「結果(論理積)が0なら衝突しない、0以外なら衝突する。」になっています。

そこでを categoryBits:0x0001, maskBits:0x0003 に変更してみました。すると・・・

maskBits:0x0003(0011) &  categoryBits:0x0004(0100) >> 0(0000):衝突しない

maskBits:0x0007(0111) &  categoryBits: 0x00010001) >> 1(0001):衝突する

と、基準を変えて計算すると違う結果になってしましました。
そこで色々調べてみたら、QucikBox2Dのユーザーマニュアルに次のように書いてありました。

Here is the rule for a collision to occur:

uint16 catA = fixtureA.filter.categoryBits;

uint16 maskA = fixtureA.filter.maskBits;

uint16 catB = fixtureB.filter.categoryBits;

uint16 maskB = fixtureB.filter.maskBits;

 

if ((catA & maskB) != 0 && (catB & maskA) != 0)

{

  // fixtures can collide

}



つまりAとBを比較する時に「それぞれを基準に計算した結果が、どちらも0でない場合に衝突する」ということなんんですね。上に書いたの場合とも合致しますね。納得。

以下のサイトを参考にしました。感謝。



NetStreamを使ってるswfをHTMLと別階層に配置することになって、flvが読めなくなって混乱。改めてヘルプを見ると、flvHTMLでなくswfからの相対パスになるってことなのね。以下引用。

ローカルファイルの再生

メディアファイルの場所。引数には、String、URLRequest.url プロパティ、またはこのどちらかを参照する変数を使用できます。アプリケーションセキュリティサンドボックス外にある Flash Player および AIR コンテンツの場合、SWF ファイルまたはサブディレクトリと同じディレクトリに保存されているローカルビデオファイルを再生できます。ただし、上位レベルのディレクトリに移動することはできません。

アプリケーションセキュリティサンドボックス内の AIR コンテンツの場合、メディアファイルに指定するパスは、SWF ファイルのディレクトリに相対します。ただし、SWF ファイルのディレクトリより上位に移動することはできません。AIR でパスを相対パスとして処理するため、完全なパスは指定しないでください。


「参照するパスの起点はHTML」って考えが染みついていると、普段HTMLとswfは同階層に置くことが多いので、ちょっと混乱しました(笑)。ヘルプの該当箇所はこちらから。

XMLをいじっていて不思議な現象が。下記のようなXMLを定義します。

var xml:XML = 
<itemlist>
<itemGroup name="X">
<itemGroup name="XX">
<itemGroup name="XXX">
<item name="XXX001" />
<item name="XXX002" />
<item name="XXX003" />
<item name="XXX004" />
<item name="XXX005" />
</itemGroup>
</itemGroup>
<item name="X-001" />
<item name="X-002" />
</itemGroup>
</itemlist>;

この中のitemエレメントで@name="XX001"のデータの親を参照すると、下記のようになります。これは問題なし。

trace(xml..item.(@name=="XXX001").parent());

----
<itemGroup name="XXX">
  <item name="XXX001"/>
  <item name="XXX002"/>
  <item name="XXX003"/>
  <item name="XXX004"/>
  <item name="XXX005"/>
</itemGroup>


次に同じ条件でitemエレメントを検索して、それを別XMLの子として追加します。

var xmlList:XMLList = xml..item.(@name=="XXX001");
var xml2:XML = new XML("<top></top>")
for each (var item:XML in xmlList) {
xml2.appendChild(item);
}

xml2に対して、itemエレメントで@name="XX001"のデータの親を参照すると、下記のようになります。これも問題なし。

trace(xml2..item.(@name=="XXX001").parent());

----
<top>
  <item name="XXX001"/>
</top>

この後に、元々のXML(xml)に対して、同じく親を参照すると・・・

trace(xml..item.(@name=="XXX001").parent());

----
<top>
  <item name="XXX001"/>
</top>

と、別XMLの親を参照してしまいます。該当エレメントを別XMLに追加してしまうと、元XMLの該当エレメントの参照も変わってしまうようなのです。

これってどういうことなんでしょうね???もっとも別XMLにしたいなら、XML.copy()で複製を作れって話ではあるんですけけど、ちょっと納得いかない感じです。

某所から「flvが再生できないので見て欲しい」と連絡があって(私が作ったものではない)、flaファイルを見たらコンポーネントにflvをリンクしているだけ。

いろいろ調べてみたら、flvのファイルパスの起点は、swfが貼ってあるHTMLではなく、swfになるらしい。いつのバージョンからだったか、外部読み込みのパスがswfからHTMLになったのは覚えていたけど、flvのパスがまた別だとは知らなかった。

※ちなみにコンポーネントのスキンはswfなのでHTML起点だけど、パブリッシュ設定でswfの出力先をサブフォルダにすると同じ場所に書き出されてしまう。この辺りは「ちょっとなあ」と思う。

フツーにHTMLとswfが同階層にあれば何もする必要はないし、サーバ絡みのコンテンツだとflv自体が別サーバだったりすることもあるからか、今まで問題に遭遇したことがなかったです。

う〜ん、わかっているようで気づいてないことがいろいろあるなあ。

下記サイトのお世話になりました。感謝。



文字通り、特定のエレメントから遡って、全ての親エレメント名を取得するための関数を書きました。XMLは下層に向かっての処理はいろいろあるけど、上層に向かっての処理は少ない気がする。前提として、XMLは上から下に向かって使うものなのか? いや、そんなことないよね。単に階層化されたデータな訳だから。

//---------------------------
// 親ノード名取得(再帰)
//---------------------------
function getParentName_xml(xml:XML,array:Array):void
{
if (xml.parent() != undefined)
{
array.unshift(xml.parent().name());
getParentName_xml(xml.parent(),array);
}
}

前回の件みたいに単なる見落としの可能性もあるので、もっと簡便な方法を知ってる方は教えてください。
XMLをいじってて、XMLオブジェクトのすべての子孫(子、孫、ひ孫など)から特定のエレメントを抽出するには、descendant accessor(..)を使って

var resultList:XMLList = xml..aa;

と出来るのですが、このaaが文字列の場合にはどうすればいいか?

何かメソッドがあるはずだと探しまくって発見したのが、XML.descendants()でした。

var resultList:XMLList = xml.descendants("aa");

しかし散々探したあげく、見つけた場所がdescendant accessor(..)のヘルプにある関連項目からのリンクだったという・・・。灯台下暗しというけれど、ヘルプの見方に問題がありありです。うう...(T_T)。


ここのところ必要に迫られて、いろいろ図形の描画をしました。で、前回のカスタム線に続いて、今度は外接円を描きました。サンプルはこちら

円の公式(r*r = (x - a)* (x - a)+(x -b)*(x -b))と3点の座標から連立方程式を作って、解いただけです。...と書くと簡単そうですけど、ASの式にするのに結構手間がかかりました。数学苦手だし(笑)。スクリプトはこんな感じです。

//3点から円を描く
function drawCircleFromPoint()
{
//任意の3点から円の半径、中心点を求める
//(3点の座標と円の公式の連立方程式)
var A:Number = Math.pow(point1.x,2) - Math.pow(point0.x,2) + Math.pow(point1.y,2) - Math.pow(point0.y,2);
var B:Number = point1.y - point0.y;
var C:Number = Math.pow(point2.x,2) - Math.pow(point0.x,2) + Math.pow(point2.y,2) - Math.pow(point0.y,2);
var D:Number = point2.y - point0.y;
var E:Number = point1.x - point0.x;
var F:Number = point2.x - point0.x;

var b:Number = (F*A - E*C)/(B*F - D*E)/2;
var a:Number = (C - 2*b*D)/(2*F);
var r:Number = Math.sqrt(Math.pow(point0.x - a,2) + Math.pow(point0.y - b,2));

//求めた円を描画
var sp_gr:Graphics = sp.graphics;

sp_gr.clear();

//円;
sp_gr.lineStyle(1,0x00FF00,1);
sp_gr.drawCircle(a,b,r);

//中心点;
sp_gr.moveTo(a-3,b-3);
sp_gr.lineTo(a+3,b+3);
sp_gr.moveTo(a-3,b+3);
sp_gr.lineTo(a+3,b-3);
}

※point0,point1,point2はそれぞれ円のmcを指します(サンプル参照)。

いざ書こうとすると意外と面倒なのでメモとして。あんまり用途がないかもしれませんけど...。





普段あまり使わないのだけれど、Arrayは・・・

var array:Array = new Array(0,2)

とやっても生成できます。で、たまたま横着してこの方式で・・・

array = new Array(0)

とやって、array[0] == 0 になると思ったら、要素ゼロの配列になってしまい、しばらく「何でだろうな??」とはまってしまいました。ヘルプ通りの仕様なんですけどね。

var array:Array = new Array(0,2)
trace(array,array.length) >> 0,2 2
array = new Array(0)
trace(array,array.length) >>  0

まあこんなコトで躓くこともないと思いますが、自分ではまたやりかねないのでメモ。
素直にこうすれば、何の問題も起きないんですけどねw。

array = [0]
trace(array,array.length) >> 0 1


[追記]2011.5.11
野中さんから情報いただきました。初期化は[]を使う方が速いらしいです。

GraphicsでmoveTo,lineToで線を描く時に、Flash上でできる破線、点線などの描画が出来ない。みんなどうしてるのか・・・と調べると、結局自作するしかないようなので、CustomLine用のクラスを書いてみました。点線、破線、波線、二重線に対応してます。サンプルはこちら

こういうのって汎用ライブラリはないのかな〜。役に立つようならwonderflにでも投稿してみようかしらん。でももうあるかな?

この手のいいライブラリがあったら教えて下さい。



ちょっとはまったのでメモ。

AACファイルをNetStreamを使って再生する場合、FLVと同様に・・・

rcv_ns.play(url_flv);
rcv_ns.seek(0);
rcv_ns.pause();

みたいな感じで、先頭に位置づけておいて、NetStream.resume()とNetStream.puase()を切り替えて、再生・一時停止を実装しています。例えば、こんな感じ。

if (isNowPlaying) {

//終了の場合は、巻き戻して再生
if (flg_finish) {
flg_finish = false;
rcv_ns.seek(0);
}
rcv_ns.resume();
} else {
rcv_ns.pause();
}


この状態で、NetStream.seek(0)で一時停止(NetStream.pause())した状態で放置しておくと、NetStream.resume()してもAACが再生されなくなってしまいます。つまり初期状態や先頭まで巻き戻した状態でそのままにしておくと、再生ボタンが効かなくなるということです。

FLVでテストしても問題は発生せず、どうもAACに固有の問題のようです。結局、NetStream.resume()の前には、強制的にNetStream.timeで位置合わせしてやることで解決しました。


if (isNowPlaying) {

//終了の場合は、巻き戻して再生
if (flg_finish) {
flg_finish = false;
rcv_ns.seek(0);
} else {
rcv_ns.seek(rcv_ns.time);
}
rcv_ns.resume();
} else {
rcv_ns.pause();
}

う〜ん、なんか釈然としないけど、バグなんだろうか?

直接は関係ないですが、AdobeのサイトにAAC関連の記事を見つけたので貼っておきます。NetStreamで読み込むAACにSoundTransformを使う方法なんて事も書いてあります。



このアーカイブについて

このページには、過去に書かれたブログ記事のうちAS3.0カテゴリに属しているものが含まれています。

前のカテゴリはAS2です。

次のカテゴリはBitmapDataです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。