通常マウスイベント等のリスナー関数には引数を持たすことができないが、クロージャ(←よくわかってないけど、関数の中に関数があるような状態のときみたい)を使うと、可能になります。
hakuhinさんの記事がわかりやすいと思います。
クロージャを使って関数にパラメータを保持する
このときに地雷があったのでご報告。
通常、こんな処理があったとします。
上の四角をクリックで、下のボタンにイベントを設定。
下のボタンをクリックすると上のボタンをクリックした回数が表示される。
//フレームアクション
//ボタン1となる四角を作成
var mc1:MovieClip = new MovieClip();
var mcg1:Graphics=mc1.graphics;
mcg1.beginFill(0xFFCC00);
mcg1.drawRect(0,0,100,50);
mcg1.endFill();
addChild(mc1);
mc1.buttonMode=true;
//ボタン2となる四角を作成
var mc2:MovieClip = new MovieClip();
var mcg2:Graphics=mc2.graphics;
mcg2.beginFill(0x88CC00);
mcg2.drawRect(0,0,100,50);
mcg2.endFill();
mc2.y=100;
addChild(mc2);
mc2.buttonMode=true;
//ボタン1クリック回数
var count:uint=0;
//ボタン位置のクリック動作
mc1.addEventListener(MouseEvent.CLICK, addMouseEvent);
function addMouseEvent(e:MouseEvent):void {
count++;
mc2.addEventListener(MouseEvent.CLICK,xClick);
trace(count);
}
function xClick(e:MouseEvent):void {
trace("count : "+count);
}
これをcountがローカル変数だったとして、クロージャ的に書くと
//フレームアクション
//ボタン1となる四角を作成
var mc1:MovieClip = new MovieClip();
var mcg1:Graphics = mc1.graphics
mcg1.beginFill(0xFFCC00);
mcg1.drawRect(0,0,100,50);
mcg1.endFill();
addChild(mc1);
mc1.buttonMode = true;
//ボタン2となる四角を作成
var mc2:MovieClip = new MovieClip();
var mcg2:Graphics = mc2.graphics
mcg2.beginFill(0x88CC00);
mcg2.drawRect(0,0,100,50);
mcg2.endFill();
mc2.y = 100;
addChild(mc2);
mc2.buttonMode = true;
//ボタン1クリック回数
var count:uint = 0;
//ボタン位置のクリック動作
mc1.addEventListener(MouseEvent.CLICK, addMouseEvent);
function addMouseEvent(e:MouseEvent):void{
count ++;
mc2.addEventListener(MouseEvent.CLICK,xClick(count));
trace(count);
}
function xClick(mc1):Function {
return function(e:MouseEvent):void {
trace("count : "+count);
}
}
実行するとわかるのですが、上の四角をクリックした回数だけ、下のボタンのイベントが重複します。
上の例ではどんだけ上の四角をクリックしても重複しなかったのですが、下の例では重複しまくります。
これ、気づくまでかなり時間かかりました・・・
まぁそもそもイベント登録が重複してしまう設計が悪いのでしょうけど・・・
ともかくクロージャってイベントリスナーに引数を持たせたいときはより厳密に設計しないとまずそうです。
Tags: AS3, Flash
CS4のデフォルト書き出しはFP10です。
FP9まではダイナミックテキストにアルファ処理はフォント埋め込まないと無理でしたが、FP10からはフォント埋め込まなくてできるみたい。
//FP10用
var tf:TextField = new TextField();
tf.text = "TEST";
addChild(tf);
tf.alpha = 0.1;
FP9での書き出しでは聞きません。
FP9の場合(フォント埋め込み後)
//FP9用
var tfm:TextFormat = new TextFormat();
tfm.font="HGSMinchoE";
var tf:TextField = new TextField();
tf.embedFonts=true;
tf.defaultTextFormat=tfm;
tf.text="あいうえお";
addChild(tf);
tf.alpha = 0.1
フォントの埋め込みはライブラリに埋め込んでないとだめみたいです。
ググるとtipsがたくさんありましたが、意外とはまったので書いときます。
ライブラリの右上のオプションボタンから「新しいフォント…」を選択
好きなフォントを選びます。
上の例では、HGS明朝Eをえらんでます。
リンケージのActionScript用に書き出しにチェック。
このときクラス名はなんでもいいです。(空手バカとかでもOK)
この埋め込んだフォントをASでどう設定するかというところで悩みました。
具体的には↓で設定してるのですが、
tfm.font="HGSMinchoE";
で、”HGSMinchoE”はなんぞや、という感じですが、これがHGS明朝Eのこと。
ボクはここを↓のようにやっていてできませんでした。
//だめな例
tfm.font="HGS明朝E";
ではHGS明朝E→HGSMinchoE、これをどうしらべるかですが。
trick7さんのとこの記事に調べ方がありました。
AS3 フォントリスト取得&確認用コード
これでライブラリ上で埋め込んであるフォントの名前がわかりました。
※2010/06/26追記
フォント名は文字列ではなく、FontクラスのfontNameプロパティを参照した方が安全。
//フォントにリンケージで指定したクラス名がMyFontだった場合
var myFont:Font = new MyFont();
var tfm:TextFormate = new TextFormat();
tfm.font = myFont.fontName;//これでフォント名が指定できる
Tags: AS3, Flash, FlashPlayer10
setTextFormatはTextField.textにテキストを入れてから、実行する。
テキスト入れるまえでは意味がない感じ。
//テキストフォーマットを定義
var tfm:TextFormat = new TextFormat();
//行間の設定
tfm.leading=10;
//テキスト
var blogListTextArray:String="あんぽんたんあんぽんたんあんぽんたんあんぽんたんあんぽんたんあんぽんたんあんぽんたんあんぽんたん";
//テキストフィールドを定義
var tfCreator:TextField = new TextField();
//幅設定
tfCreator.width=50;
//折り返すよ、の設定
tfCreator.wordWrap=true;
//テキストフィールドにStringを入れる
tfCreator.htmlText=blogListTextArray;
//中身が入ってる状態で、フォーマット
tfCreator.setTextFormat(tfm);
//メインのタイムラインに追加
addChild(tfCreator);
順番が重要で、これじゃだめだった。
//先にフォーマット
tfCreator.setTextFormat(tfm);
//フォーマット後に、テキストフィールドにStringを入れる
tfCreator.htmlText=blogListTextArray;
Tags: AS3, Flash
どういうことかというと。
メインのタイムラインにMC3というムービークリップ
MC3の中にはMC2があり、
MC2の中にはMC1があるという状態。
つまりステージからMC3をクリックしまくって、MC1に達したときの階層がこんな感じになってる状態。
シーン1→MC3→MC2→MC1
この状態で、
メインのタイムライムラインに
trace(“main”);
MC1のタイムラインに
trace(“1”);
MC2のタイムラインに
trace(“2”);
MC3のタイムラインに
trace(“3”);
これでプレビューすると出力結果は、
main
3
2
1
ステージに近い方から実行されていくというのはなんとなく予想通り。
ここで、各MCにクラスファイルをリンケージしてみる。
(全て1フレーム目に書き出しの設定)
MC1にはTest1.as
MC2にはTest2.as
MC3にはTest3.as
それぞれクラス名をトレースするだけの内容が書いてある。
例)Test1.as
package {
import flash.display.MovieClip;
public class Test1 extends MovieClip{
public function Test1() {
trace("Test1");
}
}
}
この状態で実行するこうなりました。
Test1
Test2
Test3
main
3
2
1
入れ子の一番深いリンケージクラスファイルが一番初めに実行、どんどん上に上がっていって、リンケージしたクラスファイルが終わったら、フレームアクションをステージ側から実行していって、一番深いところを目指す。
予想と違ったのでなんか驚いた。
Tags: AS3, Flash
progressionのページタイトルについて。
ブラウザの上に表示される、アレですね。
SceneObjectのプロパティtitleに設定することでブラウザに反映されるとあります。
だがしかし読み込み直後はこれが表示されない。
なんか別のタイトルが表示されてます。
なんだろう、index.asとかになんか書いてあるのか?といろいろ調べまわり・・・
グーグル先生に聞いてみても質問が悪いのか教えてくれず・・・
Twitterでえらい人の一言で解決しました。
index.htmlのtitle属性の値でした。。。
最近SWFファイルしか作ってないから何だか根本的にダメダメだ。。。
Tags: AS3, Flash, progression
いつも、どっちがどっちかわからなくなるのでメモ
まずAS3
ステージ上に、
インスタンス名:切り抜かれるMC(青い長方形)
インスタンス名:切り抜きの型となるMC(赤い三角)
二つのインスタンスを重ねた状態で、
切り抜かれるMC.mask = 切り抜きの型となるMC;
これで、青い三角ができあがる、と。
AS2だと
切り抜かれるMC.setMask(切り抜きの型となるMC);
切り抜かれるMCが常に最初と覚えておくことにしよう。
あとインスタンス名とかって全角の日本語でもOKなんですよねぇ。
AdobeMAXで城戸さんのセッションでやっててこういう使い方もありかと思いました。
Tags: AS3, Flash
ユーザーのPCに変数情報等を保存できる。
Flash版のCokkieみたいなものらしい。
(そもそもCookieをよくわかっていないが)
何ができるかといったら、swfファイル間で同じ変数情報を共有可能。
使い方、owner.flaをつくりのそのフレームアクションに、
// 共有オブジェクトを作成する
var so:SharedObject =SharedObject.getLocal("MyData","/");
//containerBox0という箱を定義して値を設定
so.data.containerBox0="test0";
//ローカルにファイル(MyData.sol)を保存する。
var str = so.flush();
つづいて、user.flaを作ってそのフレームアクションに、
var so:SharedObject=null;
so=SharedObject.getLocal("MyData","/");
var tf:TextField = new TextField();
addChild(tf);
tf.text=String(so.data.containerBox0);
owner.flaをパブリッシュすると、MyData.solが保存される。
保存場所は上記スクリプトの場合は、
C:\Documents and Settings\(ユーザーID)\Application Data\Macromedia\Flash Player\#SharedObjects\NFWUQ76F\(ドメイン名)
もしくは
C:\Documents and Settings\(ユーザーID)\Application Data\Macromedia\Flash Player\(ドメイン名)
といった感じになるようだ。
参照サイト
ちなみにサーバーにあげないでローカルで試してるときは、(ドメイン名)はlocalhostになる。
ファイルができたことを確認して、user.flaをパブリッシュすると、text0が表示される。
ここで少し注意が必要でした。
owner→userの順でパブリッシュすると期待通りの動きですが、
user→owner→userの順でパブリッシュすると、MyData.solが削除されてしまいます。
理由はちゃんと理解してませんが。。。
多分先に作ったSharedObjectインスタンスに情報が入ってないから、なんちゃらかんちゃらな感じ。
なので情報が入ってるか入ってないかを判定して、入ってなかったら、その場でSharedObjectインスタンスを破棄するような処理が必要。
というわけでuser.flaを以下のように変更するとOKでした。
var so:SharedObject=null;
so=SharedObject.getLocal("MyData","/");
if (so.data.containerBox0==null) {
so.clear();
so=null;
} else {
var tf:TextField = new TextField();
addChild(tf);
tf.text=String(so.data.containerBox0);
}
ファイル保存の際はエラー処理書いておかないとまずいですね。。。
Tags: AS3, Flash, SharedObject
例えば、フレームアクションで、
var sp:Sprite = new Sprite();
this.addChild(sp);
removeChild(sp);
sp = null;
スプライトを作って、
メインのタイムラインに追加して、
メインのタイムラインから削除して、
スプライトの参照も削除
当然これで、spはGC対象となる。
でもこの場合ではsp=nullは特に要らないみたい。
var sp:Sprite = new Sprite();
this.addChild(sp);
removeChild(sp);
この場合は、これでもspはGCの対象となるようす。
removeChild()した時点で、GC対象となっている。
removeChildについてのドキュメントより、
DisplayObjectContainer インスタンスの子リストから指定の child DisplayObject インスタンスを削除します。
削除された子の parent プロパティは null に設定されます。その子に対する参照が存在しない場合、そのオブジェクトはガベージコレクションによって収集されます。
参考サイト:
FlashPlayer9のガベージコレクタのメモリ解放の考察
DisplayObjectじゃない(addChildしてない)変数をGC対象とするときは○○=nullを使って参照を切ればいいってことなのかな。
Tags: AS3, Flash, GC
教えてもらったこと。
index.asにて
MovieClip(stage.getChildAt(0))
でpreloader本体を指定可能。
例)
preloader.flaに、hoge1_mcとかhoge2_mcとか置いてあった場合。
index.asからhoge1_mcにアクセスするには、
MovieClip(stage.getChildAt(0)).hoge1_mc
でOK
Tags: AS3, Flash, progression
緑色の↓(下矢印)のついたアイコンのファイルがコンパイル対象となる。
※右クリックでAlwaysCompileにチェックが入ってる
mxmlとかasファイルとかに指定する。
変更するときは、変更したいファイルを右クリックしてAlwaysCompileにチェック。
(さっきまでチェックされてたファイルのアイコンから緑下矢印が消える)
Tags: AS3, Flash, FlashDevelop, Flex SDK