nipx 待ち受けFlash / Heart
- 2010 年 1月 20 日
|
普段気にすることはありませんが、addEventListenerのuseCaptureについて。
AS3ではイベントが3段階で処理されている。原則的にイベントはステージから、イベントが発生したオブジェクトに向かい、オブジェクトに辿り着いたら今度はステージに戻ってくる。
入れ子になった表示オブジェクトは、この経路にしたがってイベントをリレーしているわけだ。
普段意識せず、useCapture = false のままに設定しているなら、イベントが発生したオブジェクトの段階か、ステージに戻ってくる段階の通知をキャッチしている。
このことを示した図がリファレンスに書かれている。
イベントフロー
この図はとてもよく説明されているのだけど、実際に動いているもので確認したくて試しました。
Eventオブジェクトには、イベントのリレーを止める、stopPropagationとstopImmediatePropagationってメソッドもあるので、この二つの挙動についても試している。
イベントフローを意識することがあるのは、入れ子になった表示オブジェクトの場合が想定されるので、大きい方から順番にA、B、Cと円を定義して、入れ子にする。
var A:Sprite = new Sprite(); A.name = "A"; var B:Sprite = new Sprite(); B.name = "B"; var C:Sprite = new Sprite(); C.name = "C"; A.graphics.lineStyle(5, 0x000000 ); A.graphics.beginFill( 0x000000, 0 ); A.graphics.drawCircle( 0,0, 100 ); B.graphics.lineStyle(2.5, 0x404040 ); B.graphics.beginFill( 0x404040, 0 ); B.graphics.drawCircle( 0,0, 75 ); C.graphics.lineStyle(1, 0x808080 ); C.graphics.beginFill( 0x808080, 0 ); C.graphics.drawCircle( 0,0, 50 ); //BはAの子、CはBの子 A.addChild( B ); B.addChild( C ); addChild( A ); |
全ての円にキャプチャ段階とターゲット・バブリング段階それぞれにリスナーを定義します。
stopPropagation、stopImmediatePropagationを試すべく、優先順位をつけてリスナーを二つ登録しました。
優先順位の高い方のリスナーは、ラジオボタンに応じてstopPropagation、stopImmediatePropagationが実行されるようにします。
リスナーはテキストエリアに処理された内容を表示します。
//優先度の高いリスナー A.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownCaptureing1, true ); B.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownCaptureing1, true ); C.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownCaptureing1, true ); A.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownTarget1, false ); B.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownTarget1, false ); C.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownTarget1, false ); //優先度の低いリスナー A.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownCaptureing2, true, -1 ); B.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownCaptureing2, true, -1 ); C.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownCaptureing2, true, -1 ); A.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownTarget2, false, -1 ); B.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownTarget2, false, -1 ); C.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDownTarget2, false, -1 ); private function _onMouseDownCaptureing1(e:MouseEvent):void{ if( group1.selectedData == 1 ) e.stopPropagation(); else if( group1.selectedData == 2 ) e.stopImmediatePropagation(); var str:String = "#1 " + e.currentTarget["name"] + "がキャプチャ段階のリスナーで、" + e.target["name"] + "をターゲットに" + e.type + "イベントを" + _returnPhase(e) + "で処理。"; _field.appendText( str + "\n" ); } private function _onMouseDownTarget1(e:MouseEvent):void{ if( group2.selectedData == 1 ) e.stopPropagation(); else if( group2.selectedData == 2 ) e.stopImmediatePropagation(); var str:String = "#1 " + e.currentTarget["name"] + "がターゲット・バブリング段階のリスナーで、" + e.target["name"] + "をターゲットに" + e.type + "イベントを" + _returnPhase(e) + "で処理。"; _field.appendText( str + "\n" ); } private function _onMouseDownCaptureing2(e:MouseEvent):void{ var str:String = "#2 " + e.currentTarget["name"] + "がキャプチャ段階のリスナーで、" + e.target["name"] + "をターゲットに" + e.type + "イベントを" + _returnPhase(e) + "で処理。"; _field.appendText( str + "\n" ); } private function _onMouseDownTarget2(e:MouseEvent):void{ var str:String = "#2 " + e.currentTarget["name"] + "がターゲット・バブリング段階のリスナーで、" + e.target["name"] + "をターゲットに" + e.type + "イベントを" + _returnPhase(e) + "で処理。"; _field.appendText( str + "\n" ); } private function _returnPhase(e:MouseEvent):String{ return ( EventPhase.AT_TARGET == e.eventPhase ) ? "ターゲット段階" : ( EventPhase.BUBBLING_PHASE == e.eventPhase ) ? "バブリング段階" : "キャプチャ段階"; } |
こちらで試せます。場合によっては意図に反して2回処理されていたみたいな間違いはありそうだね。
こんなものを意識して何か作ることが無いことを祈るばかり。
|
新しい試みで、オリジナル 待ち受けFlash を作りました。
Flash Liteは1.1対応で作るのが汎用的と思いますが、ウチのは2.0以上の対応です。
昨今もAS2の仕事があったりするんでそのノウハウを活かそうと考えた。PCでは過去のものになりつつあるAS2も、Flash Liteに置き換えれば前向きに考えられるかと思ったわけです。携帯Flashは全然やってないので実機で充分に動くものになっているか少し不安です。
実機確認は手もとにあったWILLCOM WS011SHのFlash Lite 2.1でしか出来ていないので、もし試されたならご覧いただいた機種や動作状況を教えていただけるとありがたいです。
Cool HomePages.com に nipx.jp 載せてくれたらしい。今日メールがきてた。
作ったの1年前の話なんだが…。ともあれ、ありがとうございました。
スペースシャトルは今年で退役って話なんで来年までにリニューアルしたい。
Flashで開発する際、コメントってどうしてます?
僕の場合、自分しかさわらない一度っきりのプロジェクトにいちいち緻密にコメントつける必要性は微妙と思いつつも、見直してみると大抵コメントをつけているようです。
最近はどうせコメントをつけるならとASDocに対応した形式で記述するようにしました。
このASDocの書式には結構多様な指定が出来るようになっています。
刺身のつまみたいなもんなんで、全部覚えようなんて気にはまったくならないのだけども、いざ書き出そうって時にエラーってことが頻繁なんで、自分的な要点を記録しておきます。
先にヘルプのインデックスへリンク。
参考:ASDoc の使用
コメントの記述は以下の書式。/** と */ の間にコメントを書く。
コメント行頭の * は無くても問題なく書き出されるような気がしますが、ASDocで解析するのに使うと参考にあるので記述する。この書式をクラスやメソッド、プロパティなどを記述している直前に書く。この位置にコメントを書くことは多いと思うので、どうせならこれにしておくって感じ。
/**
* Main comment text.
*
* @tag Tag text.
*/ |
@の部分がASDocのタグになっていて、ASDocを書き出す時に整形されます。
参考:ASDoc タグ
いろいろありますが、メソッドやコンストラクタの引数用に@param。戻り値用に@return。くらいしか使っていない。自分用にはこの位でいんじゃないかと思います。僕的にコケたところで、getter/setterの場合、ASDocのコメントは1カ所に書きます。
/** * 直線を定義します。 */ public class Line{ /** * 直線を定義します。 * * @param a 直線を(ax + by + c = 0)で表す場合のaです。 * @param b 直線を(ax + by + c = 0)で表す場合のbです。 * @param c 直線を(ax + by + c = 0)で表す場合のcです。 */ public function Line( a:Number, b:Number, c:Number ){ this._a = a; this._b = b; this._c = c; this._update(); } /** * 直線を(ax + by + c = 0)で表す場合のaです。 * @return ax + by + c = 0 の a です。 */ public function get a():Number{ return this._a; } public function set a(n:Number):void{ this._a = n; this._update(); } private var _a:Number; } |
コメントはHTMLタグが使える。
参考:一般に使用される HTML エレメントの一覧
ASDocを書き出した時に改行くらい無いと読みづらいものあるので<p>タグは良く使う。
<br>はうまく利かない気がする。あと<a>タグも使えるので参考がある時は記述しておきますね。
コメントを勢いで書くとよく失敗するのが特殊文字。参考の下にある実体参照は注意した方がいい。< > &みたいなHTMLオーサでもよく使うものはすぐ気づいたのだけど、@(アットマーク)とか*(アスタリスク)ってあまり実体参照で使わないと思うので。これがあると書き出しの時エラーになります。
@ = @
* = ~~ (実体参照じゃないけど、ASDoc書式ではチルダ二つで書く)
コメントの記述はこの位にしてASDocの書き出し方。
Flex SDKとターミナルを使います。
FlashDevelop環境ならGUIからいけるっぽいが、自分はMac環境。Mac版作って欲しい。
なのでここからターミナルの操作要点になります。(自分はこの使い方をいつも忘れるのでこっちの方が重要メモ)
ターミナルを立ち上げたら、asdocの実行ファイルディレクトリに移動します。実行ファイルはFlex SDKのbinディレクトリの中にある。コマンドラインを見ると気分が悪くなる僕みたいな人向けの移動する方法。
ターミナルにcd を入力してbinフォルダをドロップ。
次にコマンドを入力します。
参考: ASDoc ツールの実行
コマンドオプションが沢山ありますが必要に応じて指定します。
僕は書き出すファイルをまとめて-doc-sourcesを指定するだけで書き出してます。
まず、asdocを指定する。./を忘れないように注意。
./asdoc
Flex SDKのバージョンによりますが、FlashPlayer10以降のクラスが含まれる場合(Matrix3DとかVector3Dとか)-target-player オプションを入れます。
参考:Flex Builder 3をFlash Player 10に対応させる
./asdoc -target-player=10.0.12
ライブラリにSWCを使っている場合(Progressionとか)、-library-path オプションを入力してSWCファイルのディレクトリを指定します。これもフォルダドロップでOK。
./asdoc -target-player=10.0.12 -library-path /Users/name/project/libs/
書き出したいディレクトリを-doc-sourcesで指定します。フォルダドロップでOK。
./asdoc -target-player=10.0.12 -library-path /Users/name/project/libs/ -doc-sources /Users/name/project/src/jp/nipx/
これを実行すればbinの中にasdoc-outputフォルダが生成され中にASDocが入っています。
知っておくと便利そうなターミナル操作
Control + A 行頭へ移動
Control + E 行末へ移動
Control + U カーソルより左の文字をすべて消去
Control + W カーソルより左の文字を単語単位で消去
Control + K カーソルより右の文字をすべて消去
(ターミナルの設定 > キーボード > メタキーとしてOptionキーを使用にチェックを入れて)
Option + B 単語単位で左に移動
Option + F 単語単位で右に移動
ところで世に配布されているありがたいライブラリなんかは、間違いなく整然としたコメントがつけられています。
数式と文章って真逆なようでそうでもないものだと思う。わかりやすいソースはわかりやすい言葉で説明できるものだと思いました。
年末の忘年会で、外部SWFに埋め込んだフォントを使う話題がありました。埋め込んだフォントがうまく有効にならないってことで、その時は多分出来るんじゃない?位に思ってましたけど、やってみたらすんなりとはいかなかったので記録しておきます。
話題に上がったのは、たぶんこういうファイル構成だと思う。
これを前提にして試してみた。
fonts.swfのステージにダイナミックテキストを置いて、ヒラギノ角ゴ Pro W6、ヒラギノ明朝 Pro W6を配置。
両方とも“日本語(かな)(318文字)”を埋め込んでパブリッシュ。
コンストラクタで、
public function Fonts(){ var arr:Array = Font.enumerateFonts( false ); for each( var i:Font in arr ){ trace( i.fontName ); } } |
としてトレースして結果は期待どおり。
続いてpreloader.swfからfonts.swfを読み込んでトレースしてみる。
埋め込みが参照できれば、—▼Preloader▼—の下にフォント名が出力されるはず。
public function Preloader(){ var loader:Loader = new Loader(); loader.load( new URLRequest( "fonts.swf" ) ); loader.contentLoaderInfo.addEventListener( Event.INIT, function(e:Event):void{ trace( "---▼Preloader▼---" ) var arr:Array = Font.enumerateFonts( false ); for each( var i:Font in arr ){ trace( "Preloader:" + i.fontName ); } }); } |
あれ?出力されない…。どうもこの時点でfonts.swfの埋め込みを参照できないっぽい。
で、色々試してみたらFont.registerFont()でグローバルフォントリストに追加しないといけないようだ。
Font.registerFont()にはクラスを渡すことになっているのだけど、今回みたいな一部フォントの場合、どうやればよいか?(フォントシンボルですべての文字を埋め込む場合は、フォントシンボルのクラスでOK。)
これはメタタグを使えばうまくいった。
fonts.swfのダイナミックテキストによる埋め込みをやめて、Embedタグで埋め込む。
public class Fonts extends Sprite{ [Embed(source='../../assets/ヒラギノ角ゴ Pro W6.otf', fontName= "Hiragino Kaku Gothic Pro W6", mimeType='application/x-font', unicodeRange="U+3000-U+303F,U+3041-U+309F,U+30A0-U+30FF,U+FF61-U+FF9F" /* Japanese Kana */ )] private static var HIRAGINO_KAKUGO_PRO_W6:Class; [Embed(source='../../assets/ヒラギノ明朝 Pro W6.otf', fontName= "Hiragino Mincho Pro W6", mimeType='application/x-font', unicodeRange="U+3000-U+303F,U+3041-U+309F,U+30A0-U+30FF,U+FF61-U+FF9F" /* Japanese Kana */ )] private static var HIRAGINO_MINCHO_PRO_W6:Class; public function Fonts(){ Font.registerFont( HIRAGINO_KAKUGO_PRO_W6 ); Font.registerFont( HIRAGINO_MINCHO_PRO_W6 ); } } |
embedの書式について詳しくは、Flexのヘルプ参照。
埋め込みフォントの使用
sourceにはフォントファイルへのパスを書く。相対パスの基準はEmbedを書くasファイルから。
fontNameはasから参照するときのフォント名をつける。上記みたいなそのまんまのネーミングは混乱のもとになる予感。My 〜 とかの方がよさそうな気がする。
unicodeRangeで埋め込む範囲を指定するのだけど、これについては後ほど。
Embedタグの下の変数はEmbed参照用の変数ね。これをFont.registerFontで登録する。
ひとまずこれでPreloaderから参照できるか試してみる。
今度は参照できるようになった。
グローバルに追加されていればindex.swfからも問題なく使える。
public function Index(){ trace( "---▼Index▼---" ); var arr:Array = Font.enumerateFonts( false ); for each( var i:Font in arr ){ trace( "Index:" + i.fontName ); } var field:TextField = new TextField(); field.autoSize = TextFieldAutoSize.CENTER; field.defaultTextFormat = new TextFormat( "Hiragino Mincho Pro W6", 24 ); field.embedFonts = true; field.x = 200; field.y = 138; field.rotation= 15; field.text = "あけましておめでとうございます"; this.addChild( field ); } |
最後にunicodeRangeについて。
埋め込み文字の範囲はこれにUnicodeの文字コードを指定し行うようだ。
指定の仕方は、
文字範囲の設定
に詳しく書かれているようです。
がっつり英語が読めるならこれらしい。
15 Fonts
で論より実践でいきます。上記リンクに記載がありますが、Flex SDKの中に、
flash-unicode-table.xmlってファイルがあって、日本語のかなだけとか、漢字 JIS第一水準みたいなFlashにある文字セットが記載されているのでまとめて埋め込む時はこれを使えばよさそう。
個別の文字だけど、U+3041でいうところの3041の部分、U+~の~が16進数で表された文字コードになっているようなのでActionScriptで以下のような変換を使って出せると思う。
var str:String = "あ"; //Unicode 10進数表記 var num:Number = str.charCodeAt(0); //Unicode 16進数表記 var code:String = num.toString( 16 ); //文字 var txt:String = String.fromCharCode( parseInt( code, 16 ) ); trace( num ); trace( code ); trace( txt ); /* 出力 12354 3042 あ */ |
ってことで、めんどくさいけどいけるんじゃないんですかね。 >> Shuさん
あけましておめでとうございます。
昨年はお仕事でお世話になったみなさま、どうもありがとうございました。
おかげさまで、無事年を越して新年を迎えました。
ニピクセル、今年もどうぞよろしくお願いいたします。
このブログを読んでいただいている、すべての方へ。
いつもありがとうございます。2BLOGを今年もよろしくお願いします!
FlowerWallPaper、Adobe AIR Galleryに登録しました。
登録から2週間、載せてもらえないのかと思ったよ。よかった。
airアプリを作った際、その初期設定を保存するようにしました。
その保存フォーマットはオブジェクトをJSONでエンコードしてテキスト形式を使っていたのだけど、良くみてみるとActionScriptではAMFってフォーマットがある。
これを使えばActionScriptで生成したオブジェクトを丸ごと保存するってことが出来そうだ。
とりあえず、見つけた資料はこのあたり。
AS2.0までに対応する規格AMF0とAS3.0以降に対応する規格AMF3がある。
AMF 0 規格仕様
AMF 3 規格仕様
ググった感じサーバーとのやり取りに使うケースが主目的っぽいのと、なぜMovieClipは渡せないの?(上の規格資料だとAMF0規格時からサポート外となってるっぽい)とかまだ不明なところがあるのだが、今回のような目的ならJSONで保存するより便利そうと気づいた点が2点あります。
まず、JSONでうまくエンコードできなかったSpriteなどのオブジェクトもそのまま保存出来た。
以下のようなSpriteを含むオブジェクトをJSONでエンコードした場合(エンジンはas3corelibで試してます。)エラーになったけど、AMFではそのまま保存出来る。
次にAMFにある型のオブジェクトは、そのままの型で受け取れる。
var file:File; var stream:FileStream = new FileStream(); stream.objectEncoding = ObjectEncoding.AMF3; var read:Object var sp:Sprite = new Sprite(); sp.x = 10; //保存するオブジェクト var write:Object = { arr:[ "a", "b", "c" ], date:new Date(), xml:<root>root</root>, sprite:sp, byte:new ByteArray() } //AMF------------------------------------------ file = File.desktopDirectory; file = file.resolvePath( "AMF.dat" ); stream.open( file, FileMode.UPDATE ); stream.writeObject( write ); stream.position = 0; read = stream.readObject(); trace( "AMF:", read.arr, read.arr is Array ); trace( "AMF:", read.date, read.date is Date ); trace( "AMF:", read.xml, read.xml is XML ); trace( "AMF:", read.sprite.x, read.sprite is Sprite ); trace( "AMF:", read.byte, read.byte is ByteArray ); file.clone(); |
traceの結果は、
AMF: a,b,c true
AMF: Tue Dec 8 18:52:43 GMT+0900 2009 true
AMF: root true
AMF: 10 false
AMF: true
JSONで試すと以下の結果でした。
//JSON------------------------------------------ file = File.desktopDirectory; file = file.resolvePath( "JSON.txt" ); stream = new FileStream(); stream.open( file, FileMode.UPDATE ); var json:String = JSON.encode( write ); stream.writeUTF( json ); stream.position = 0; read = stream.readUTF(); read = JSON.decode( json ); trace( "JSON:", read.arr, read.arr is Array ); trace( "JSON:", read.date, read.date is Date ); trace( "JSON:", read.xml, read.xml is XML ); trace( "JSON:", read.byte, read.byte is ByteArray ); file.clone(); |
traceの結果は、
JSON: a,b,c true
JSON: [object Object] false
JSON: [object Object] false
JSON: [object Object] false
ひとまず、型が記録されるAMFの方が読み込み後のチェックなど便利そうに思える。
もう一点、AMFはバイナリデータである為、保存したファイルをテキストエディタで開いてもなんのことかわからない。
JSONもなんのことかわからないといえば、わからない訳だけどフォーマットを手書きで記述することが出来ないこともないと思う。
この辺も用途によるかなぁと思った。