トップへ戻るニュースフォーラムFLASH-ML 過去ログBak@Flaダウンロードよくある質問と答
ログイン
ユーザ名:

パスワード:


パスワード紛失

新規登録
メインメニュー
メイン
   コーダーズルーム【スクリプト系】
     ムービー内のクリップ全体に再帰的処理させる場合の問題について
投稿するにはまず登録を

スレッド表示 | 新しいものから 前のトピック | 次のトピック | 下へ
投稿者 スレッド
colori
Åê¹ÆNo.21212
投稿日時: 2005-11-2 0:38
半人前
居住地: 東京都
投稿: 39
使用環境:
Professional(SP2) + Professional
ムービー内のクリップ全体に再帰的処理させる場合の問題について
お世話になります。
今、ムービー中のムービークリップ全体(入れ子のものも含め)に、ある処理をさせたく、
再帰的に関数を実行させようと思ったのですが、
上位階層のクリップを参照しているムービークリップで無限ループに陥って困っています。

/*
_rootの2フレーム目にあるフレームアクション。
この時点でムービークリップは沢山登場しています。
*/

//関数定義
this.hoge = function(p_mc) {
	for (var i in p_mc) {
		var c_mc = p_mc[i];
		//ムービークリップであり、かつ親子関係であれば再帰的にhogeを実行
		if (c_mc instanceof MovieClip) {
			arguments.callee(c_mc);
		} else {
			//独自処理
		}
	}
}

//自分より階層が上、あるいは同じ
//ムービークリップの参照が設定されている
this.foo = _root;

this.hoge(this);
this.stop();

ここの
if (c_mc instanceof MovieClip) {

の部分に「p_mcとc_mcが親子関係であれば」という条件を付加して、
なんとか「this.foo」のような、親子関係でないインスタンスの参照を無視できないかと思っています。
_targetプロパティも考えましたがエレガントでなく、イレギュラーな事態も起こりかねないので、
他の方法を探しています。 よろしくお願い致します。m(_ _ )m
野中文雄
Åê¹ÆNo.21214
投稿日時: 2005-11-2 2:59
ちょんまげら
居住地: 東京
投稿: 4531
使用環境:
CS5.5 .6.8 Vista Home Premium (SP1)
Re: ムービー内のクリップ全体に再帰的処理させる場合の問題について
調べる対象のMovieClipを何らかのかたちで特定することが、デザインとしては望ましいように思います。

それが難しいという前提で、重複の確認を加えた処理の例です。[追記] No.21265の投稿を受けて,スクリプトを修正しました。
引用:
coloriさんは書きました:
今、ムービー中のムービークリップ全体(入れ子のものも含め)に、ある処理をさせたく、
再帰的に関数を実行させようと思ったのですが、
上位階層のクリップを参照しているムービークリップで無限ループに陥って困っています。
/*
_rootの2フレーム目にあるフレームアクション。
この時点でムービークリップは沢山登場しています。
*/
//関数定義
function xIterate(_mc:MovieClip):Void {
	var oExisting:Object = new Object();
	if (_mc instanceof MovieClip) {
		// oExisting[_mc] = true;  //【削除】
		this.hoge(_mc, oExisting);
	}
}
this.hoge = function(p_mc, oExisting) {
	trace(["MovieClip", p_mc]);
	oExisting[p_mc] = true;  //【挿入】
	for (var i in p_mc) {
		var c_mc = p_mc[i];
		//ムービークリップであり、かつ親子関係であれば再帰的にhogeを実行
		if (c_mc instanceof MovieClip) {
			// arguments.callee(c_mc);
			if (!oExisting[c_mc]) {
				arguments.callee(c_mc, oExisting);
			} else {
				trace(["duplicated", i, c_mc]);
			}
		} else {
			//独自処理
			trace(["other than MovieClip", i, c_mc, typeof c_mc]);
		}
	}
};
//自分より階層が上、あるいは同じ
//ムービークリップの参照が設定されている
this.foo = _root;
this.xIterate(this);
this.stop();

ここの
if (c_mc instanceof MovieClip) {

の部分に「p_mcとc_mcが親子関係であれば」という条件を付加して、
なんとか「this.foo」のような、親子関係でないインスタンスの参照を無視できないかと思っています。


----------------
 

Fla4man
Åê¹ÆNo.21224
投稿日時: 2005-11-2 10:58
職人
居住地: かまくら
投稿: 517
使用環境:
WinMe,Win2000,
Flash4,アズさん,大仏、delphi
Re: ムービー内のクリップ全体に再帰的処理させる場合の問題について
再帰呼び出しを再帰呼び出し表記で記述するときは
再帰の「深度」をパラメータとして持たせて
子に入ったら+1
孫に入ったらさらに+1
孫が終わって戻るときに-1 0でないならば継続
次の孫に入ったら+1
孫からでるときに-1 0でないならば継続
子から戻るときに-1 0でないならば継続 0になった!!

としていき0になったら終了

というようにするのが基本です。

再帰処理はコードは短くなりますが
仕事量は減るわけでは無いので
再帰処理をせずに処理する方法があればそれが良いと思います。

Flashでコッホ曲線の類を書くコーディングするのは
結構楽しいです。


----------------
通常のハンドル名:×○○× ねた回収モードに突入 現在1/100

youich
Åê¹ÆNo.21226
投稿日時: 2005-11-2 12:26
職人
居住地: kobe
投稿: 349
使用環境:
Tiger
Re: ムービー内のクリップ全体に再帰的処理させる場合の問題について
引用:


の部分に「p_mcとc_mcが親子関係であれば」という条件を付加して、
なんとか「this.foo」のような、親子関係でないインスタンスの参照を無視できないかと思っています。
_targetプロパティも考えましたがエレガントでなく、イレギュラーな事態も起こりかねないので、
他の方法を探しています。 よろしくお願い致します。m(_ _ )m

movieclipの親子関係ということだけならば素直に親子かどうか
c_mc._parent == p_mcを条件に付け足せばよろしいのではないかと思います。
もしpropertyを対象にということでしたら野中さんのポストされているよう
なやり方になると思います。
this.hoge = function(p_mc) {
    for (var i in p_mc) {
        var c_mc = p_mc[i];
        //ムービークリップであり、かつ親子関係であれば再帰的にhogeを実行
        if (c_mc instanceof MovieClip && c_mc._parent == p_mc) {
			trace(c_mc);
            arguments.callee(c_mc);
        } else {
            //独自処理
        }
    }
}


----------------
- yo

Fla4man
Åê¹ÆNo.21228
投稿日時: 2005-11-2 14:12
職人
居住地: かまくら
投稿: 517
使用環境:
WinMe,Win2000,
Flash4,アズさん,大仏、delphi
Re: ムービー内のクリップ全体に再帰的処理させる場合の問題について
for in というのは今まで使わなかったので
今回調べたところ「制御変数iが存在しない」ということに気がつきました。
スクリプト上は単なるループ文に見えますがかなりやばい代物だったのです。

 for in ループは
enumerateValue(MC)
命令後スタックから順次拾ってくるだけです。
ようするにこの命令は配列などに取得しないでリストを全部スタックに吐き出す関数であり
吐き出す個数分処理を行わないとおかしくなるということです。
大抵の命令は送り出した数もスタックに入れるか
その場で完結しているのでスタックに不確定数データを残す関数というのは珍しいです。

つまりこのループ中でもう一度for inを行うことはリスクが高いと感じました。

それゆえ一旦for inで子リストを取得して配列に入れるなりしてから
その配列に対してしょりしなければならないといえそうです。
配列自体はMCのメンバーにしておけば良いでしょう。
私は
MC.Props=getenumerateMC(MC)
とPropsという配列を用意して
ポジションとPropsを各MCのメンバー変数に記録する方式でしました。
これだと配列内を自由に探索できます
今回のケースだと for inループ内で取得したc_mcを
配列にpushしていけばいいと思います。

ネスティングが無い場合はfor inでもいいかもしれませんが
結構 鬼門なので将来的に代わりの形が提供されるかなと思いました。
(既にある?AS2 or AS3)

ちょっとエレガントには程遠い感があるし
たしにならないかもしれないけれど参考までに


----------------
通常のハンドル名:×○○× ねた回収モードに突入 現在1/100

youich
Åê¹ÆNo.21237
投稿日時: 2005-11-2 19:07
職人
居住地: kobe
投稿: 349
使用環境:
Tiger
Re: ムービー内のクリップ全体に再帰的処理させる場合の問題について
引用:

Fla4manさんは書きました:
for in というのは今まで使わなかったので
今回調べたところ「制御変数iが存在しない」ということに気がつきました。
スクリプト上は単なるループ文に見えますがかなりやばい代物だったのです。

 for in ループは
enumerateValue(MC)
命令後スタックから順次拾ってくるだけです。

enumrateValue(MC)?? ASViewとかflasmの用語でしょうか?
flash_file_format_specification.pdfではActionEnumerateのことですね。

It does the following:
1 Pops the name of the object variable (which may include slash-path or dot-path syntax) off of
the stack.
2 Pushes a null value onto the stack to indicate the end of the slot names.
3 Pushes each slot name (a string) onto the stack.

引用:

ようするにこの命令は配列などに取得しないでリストを全部スタックに吐き出す関数であり
吐き出す個数分処理を行わないとおかしくなるということです。
大抵の命令は送り出した数もスタックに入れるか
その場で完結しているのでスタックに不確定数データを残す関数というのは珍しいです。

つまりこのループ中でもう一度for inを行うことはリスクが高いと感じました。

と言いますとfor in を抜けた後もFlashPlayerがstackをemptyにしないということでしょうか?
とすると、それはどういう所で解りました?

fla4manさんはあまりfor inループを使った事がなかったそうですが、
割と一般的ですよ、macromediaのソースでもよく出てきます。(^^;

例えばfocusManagerのgetMaxTabIndexファンクションでは

	function getMaxTabIndex(o:UIComponent):Number
	{
		var z:Number = 0;

		var i:String;
		for (i in o)
		{
			var x = o[i];
			if (x._parent == o)
			{
				if (x.tabIndex != undefined)
				{
					if (x.tabIndex > z)
						z = x.tabIndex;
				}
				if (x.tabChildren == true)
				{
					var y:Number = getMaxTabIndex(x);
					if (y > z)
						z = y;
				}
			}
		}
		return z;
	}

これはfor in の中で再帰的にgetMaxTabIndexを呼び出していますが
これもNGでしょうか?


----------------
- yo

Fla4man
Åê¹ÆNo.21252
投稿日時: 2005-11-3 13:32
職人
居住地: かまくら
投稿: 517
使用環境:
WinMe,Win2000,
Flash4,アズさん,大仏、delphi
Re: ムービー内のクリップ全体に再帰的処理させる場合の問題について
for inについて私は最初制御変数がないのがなぞだったので
ループする前にスタックの中身を全部呼び出すものを作ってみました。
結果for in関数は全メンバー値と0を吐き出していることが分かったのです。
つまりメンバーのないものはスタックに0をおくので
for in loopはゼロがでてくるのを待ってループ終了します。

おっしゃられたfor inを無事に抜けるスクリプトは大丈夫だと思いますが、
全変数、オブジェクト、子MCを吐き出すので特に_rootとか結構な数になるはずです。
つまりスクリプト自体に対しては保障できません。
またASでうまくできるか分かりませんがNULLをスタックに送り込んだ状態でループをまわると誤判断して終了します。

for inはループ内飛び出ることも可能であるという点がまずいです、
例えば
var x = o[i];
って記述があるけれど xは存在するけれどiが存在しません。
これは最適化とかレジスターという意味ではなくて全く存在しません
普通の発想だとiをチェック用の値として使ったりしようと思うじゃないですか?
ループからでちゃあいけない仕様ならば言語的にはそういう記述にすべきだったと思います。
breakは無効なんでしょうか?

特にぽんとボタンをおいてその中でイベントハンドラでかいちゃうと
単一空間だしregister0を固定として使っている点で
途中でクラスメンバーでない関数(function())で最適化されて
レジスター0を使っているとこわれるし
戻り方ではネスティングされたところでおしこまれた0で誤判断するコードも
可能だとおもいます。

コンポーネントやMCやオブジェクトのメンバー関数内でfor inを使う場合は
スタックが別空間なのでトラブルはおきにくいです。
コンポーネントの場合propのスコープがグローバルにいっちゃうのか
メンバー内でおさまるのかわからないけれど
ASの書き出すコードがもしも
this(this.prop)ならば「いいんじゃない」といえるけれどthis"prop"たからやばげ
タブとかはその場だけでおさまっているからだいじょうぶなんだと思いますが「保障はできないコード」にみえます。

基本的にfor inはオブジェクトや変数が少ないムービー限定
0チェックとかに使うくらいのほうがいいのではないでしょうか?
ためすよりも素直にforinで配列を取得する方が無難です。
その他よりダサい方法としてはfor in内にカウンターを設けてチェックするという方法もありますが
やはり子ムービーなりオブジェクト追加時に登録する方法がいいですね、


----------------
通常のハンドル名:×○○× ねた回収モードに突入 現在1/100

colori
Åê¹ÆNo.21262
投稿日時: 2005-11-4 1:43
半人前
居住地: 東京都
投稿: 39
使用環境:
Professional(SP2) + Professional
Re: ムービー内のクリップ全体に再帰的処理させる場合の問題について
 みなさま、ありがとうございました。
野中様の書いてくださったスクリプトで単純なムービー部分
についてはうまくいったのですが、Buttonコンポーネントを
配置した場合はやはり無限ループに陥ってしまいました。

テストした結果、Labelコンポーネントでは発生せず、Buttonコンポーネントや
Listコンポーネントで発生したことから、mx.core.UIComponentクラスが
怪しいかなと思い、再帰の前に対象を出力するなどしてみたのですが、
明確な判断はできませんでした。

if (!oExisting[c_mc]) {
	trace(["new child", i, c_mc]);
	arguments.callee(c_mc, oExisting);
} else {

コンポーネントのメンバ変数には特殊な参照があるのでしょうか?
youich
Åê¹ÆNo.21263
投稿日時: 2005-11-4 2:05
職人
居住地: kobe
投稿: 349
使用環境:
Tiger
Re: ムービー内のクリップ全体に再帰的処理させる場合の問題について
引用:

coloriさんは書きました:
 みなさま、ありがとうございました。
野中様の書いてくださったスクリプトで単純なムービー部分
についてはうまくいったのですが、Buttonコンポーネントを
配置した場合はやはり無限ループに陥ってしまいました。

テストした結果、Labelコンポーネントでは発生せず、Buttonコンポーネントや
Listコンポーネントで発生したことから、mx.core.UIComponentクラスが
怪しいかなと思い、再帰の前に対象を出力するなどしてみたのですが、
明確な判断はできませんでした。

if (!oExisting[c_mc]) {
	trace(["new child", i, c_mc]);
	arguments.callee(c_mc, oExisting);
} else {

コンポーネントのメンバ変数には特殊な参照があるのでしょうか?

えーと、どんなコードを書いておられます?
たとえばListコンポーネントを_rootに配置"myList"と名前を付けて
以下のコードを実行すると。。
this.hoge = function(p_mc) {
	ASSetPropFlags(p_mc, null, 0, 1);
	for (var i in p_mc) {
		var c_mc = p_mc[i];
		//ムービークリップであり、かつ親子関係であれば再帰的にhogeを実行
		if (c_mc instanceof MovieClip && c_mc._parent == p_mc) {
			trace([i, c_mc]);
			arguments.callee(c_mc);
		} else {
			//独自処理
			//trace(['other',i,c_mc]);
		}
	}
};

id = setInterval(this, 'doHoge', 300);

function doHoge() {
	clearInterval(id);
	hoge(myList);
}

出力が以下です、Buttonコンポーネントも同様にできると思います。
listContent,_level0.myList.content_mc
mask_mc,_level0.myList.mask_mc
border_mc,_level0.myList.depthChild0
mask_mc,_level0.myList.mask_mc
content_mc,_level0.myList.content_mc
boundingBox_mc,_level0.myList.boundingBox_mc
depthChild0,_level0.myList.depthChild0


----------------
- yo

youich
Åê¹ÆNo.21264
投稿日時: 2005-11-4 2:20
職人
居住地: kobe
投稿: 349
使用環境:
Tiger
Re: ムービー内のクリップ全体に再帰的処理させる場合の問題について
んー、すみません何を言いたいのかよくわかりませんでした。

ActionScriptを使わずflasm等を使うと、もちろんStackに積み続けて
リークを起こせますよね、、、じゃなくて
もしActionScriptのfor in でクラッシュが起きるということでしたら
検証できるActionScriptのコードをください(^^;


----------------
- yo

(1) 2 »
スレッド表示 | 新しいものから 前のトピック | 次のトピック | トップ

投稿するにはまず登録を
 
Copyright (C) 2003 FLASH-japan. All rights reserved.
Powered by Xoops