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

パスワード:


パスワード紛失

新規登録
メインメニュー
メイン
   コーダーズルーム【スクリプト系】
     複雑な図形の当たり判定
投稿するにはまず登録を

スレッド表示 | 新しいものから 前のトピック | 次のトピック | 下へ
投稿者 スレッド
mnacko
Åê¹ÆNo.14754
投稿日時: 2005-2-3 18:43
新米
居住地:
投稿: 3
使用環境:
Mac OSX 10.3.7, Flash MX2004
複雑な図形の当たり判定
はじめまして。

世界地図上に、それぞれの国が持つデータ数に比例した円を作成する、
というものを作っています。
円はその国(MCにしてある)の中心に表示されます。
中心が海になっている場合もあるのですが、これはとりあえず考えないでおきます。

地図を拡大縮小できるようにしたため、
拡大したときにステージの外に円が作成されることがあり、
その国のステージに表示されている部分の中心に表示させたいのですが、
なかなかうまい方法が見つからないでいます。

思いついたのは小さな正方形のブロックを敷き詰め、
このブロック群のうち、その国と重なっているものだけを配列にして、
その真ん中のブロックと同じ位置に円を作成するという風にしました。


//ヒットガイド(20*20の正方形)の作成
//guide_mcはステージと同じ
function createHitGuide(){
    gw = 20;
    gh = 20;
    g_num_x = Math.ceil(guide_mc._width/gw);
    g_num_y = Math.ceil(guide_mc._height/gh);
    for(i=0;i<g_num_x;i++){
        for(j=0;j<g_num_y;j++){
            hg = guide_base.attachMovie("hit_guide","hit_guide_"+i+"_"+j,i*g_num_y+j);
            hg._x = gw*i;
            hg._y = gh*j;
        }
    }
}



//アイテム数に応じて円を作成
function createCircle(){
    //o_arrayはアイテムの多い国の順に並んでいる("アイテム数","国番号")
    //c_arrayにはguide_mcにヒットした国だけ入れる。
    c_array = new Array();
    for(i=0;i<o_array.length;i++){
        map_num = o_array[i].split(",")[1];
        if(m_array[map_num].hitTest(guide_mc)){
            c_array.push(o_array[i]);
        }
    }

    //largestは全体で最多のアイテム数
    //msは地図の拡大率
    largest = o_array[0].split(",")[0];
    ms = map_mc._xscale;

    //createHitGuide();
    for(m=0;m<c_array.length;m++){
        size = c_array[m].split(",")[0];

        c_number = c_array[m].split(",")[1];
        map = "map_mc.m"+c_number;		
        map_loc = eval(map);

        pre_circle = circle_base.attachMovie("circle", "circle"+c_number,m);
        pre_circle._xscale = pre_circle._yscale = size/largest*ms;
        pre_circle._x = map_mc._x+map_loc._x*ms/100;
        pre_circle._y = map_mc._y+map_loc._y*ms/100;

        //円がguide_mcの外にある場合、その国とヒットガイドブロックとの当たり判定
        if(pre_circle.hitTest(guide_mc)==false){
            hit_array = new Array();
            for(i=0;i<g_num_x;i++){
                for(j=0;j<g_num_y;j++){
                    hg = eval("guide_base.hit_guide_"+i+"_"+j);
                    if(map_loc.hitTest(hg._x,hg._y,true)==true){
                        //hg_loc=[X座標,Y座標,インスタンス名]
                        hg_loc = hg._x+","+hg._y+","+hg;
                        hit_array.push(hg_loc);
                    }
                }
            }
            hit_array.sort(orderSort0);//項目[0]の大きい順に並び替え
            hit_array.sort(orderSort1);//項目[1]の大きい順に並び替え
            hit_mid = Math.round(hit_array.length/2);//配列の真ん中(ちょっとなげやり)
            centering = eval(hit_array[hit_mid].split(",")[2]);
            pre_circle._x = centering._x;
            pre_circle._y = centering._y;
        }
    }
}


うまく説明できているか分かりませんが、
ヒットガイドのブロックの大きさを小さくしていけば、
より厳密な当たり判定になるのでしょうが、その分、処理もかなり重くなります。
guide_mcと国が重なっている領域が分かって、
なおかつ、その中心が求められれば良いのですが、
どなたか、良いアイデアはないでしょうか?
空野大二郎
Åê¹ÆNo.14760
投稿日時: 2005-2-3 20:06
職人
居住地: 愛知
投稿: 389
使用環境:
 XP:Home
FlashMX
IE6.0+FlashPlayer7,0,19
CPU:Pentium4 2.26GHz
メモリ:1,024MB
Re: 複雑な図形の当たり判定
 まいど。

 mnackoさんは、代替案をお求めになっておられるのですね。

 ていねいにご説明されていますが、構造とオブジェクトの名称が
ややわかりにくいです。
 まずは、現状把握からはじめさせていただきます。

 <現状>
_root.map_mc (MovieClip:世界地図のグラフィックがある)
_root.circleC (MovieClip:「circle」のインスタンス。
「pre_circle」にパスを格納。「C」は番号)

 ・・・代替案です。
1:「map_mc」に座標取得MovieClip「pointX_mc」(「十」目印、
「X」は国番号)を国ごとの中心座標に配置
2:「map_mc」からの「pointX_mc」の座標を取得
3:縮尺比を適応して、_rootから見た絶対座標を取得
4:「circleC」に適応

 する事はいかがでしょうか?


----------------
空野 大二郎 アニメーター作家
桜の道

mnacko
Åê¹ÆNo.14766
投稿日時: 2005-2-3 22:23
新米
居住地:
投稿: 3
使用環境:
Mac OSX 10.3.7, Flash MX2004
Re: 複雑な図形の当たり判定
空野大二郎さん

ありがとうございます。
 作っているものから、ほとんど抜き出してきただけなので、
よけいな部分も混ざっていて、分かりにくかったですね。以後気をつけます。

構造としては、上のレイヤーから
_root.circle_base (「circle」のインスタンスcircleMが置かれる)
_root.map_mc (それぞれの国のMovieClip「mM」が配置してある)
_root.guide_base (当たり判定用MovieClip「hit_guide」のインスタンスhit_guide_X_Yがステージ表示領域に敷き詰められる)
という順です。
Mは国番号、XとYはhit_guideの列、行です。

_root.map_mc.mMは原点を国の中心点にしているので、
空野さんのおっしゃる(1)と同様ではないかと思います。

円を作成する手順は
circleMは_root.map_mc.mMの_rootから見た絶対座標に作られます。
見かけ上は、mMの原点に作成されるようにしています。
circle_base.attachMovie("circle", "circle"+M,M);
circle_base.circleM._x = map_mc._x+mM._x*ms/100;
circle_base.circleM._y = map_mc._y+mM._y*ms/100;

msはmap_mc._xscale(=map_mc._yscale)です。

問題はcircleMがStageの外にある場合で、
たとえばロシアのように大きな国で中心がモスクワに設定されていたとします。
これをズームして、アジア辺りを表示した場合、
ロシアの一部は見えているですが、モスクワは見えません。
ロシアの円circleRもモスクワにあるので、やはり見えません。

そこで、ステージ上に敷き詰められたhit_guide_X_YとmMとの当たり判定を
1個ずつ全部出していくと、
ロシアの見えている部分と重なるhit_guide_X_Y達が分かるのですが、
これらの内、見えている部分のちょうど真ん中ぐらいにあるhit_guide_X_Yが分からないものでしょうか?

ということなのですが、やっぱり分かりにくいですね。
サンプルをお見せできればいいのですが…。
永井勝則
Åê¹ÆNo.14767
投稿日時: 2005-2-3 22:24
職人
居住地: 白馬村
投稿: 796
使用環境:
Windows 7 :Flash CS4:
10.6.8 :Flash CS5.5
Re: 複雑な図形の当たり判定
またしても勘違いをしているかも知れませんが、
世界地図のグラフィック上に、各国のセンターを表すムービークリップを各国分その国の真ん中に配置して、その国を表すインスタンス名をつけて、それらのムービークリップを、世界地図のグラフィックもろともムービークリップにしてしまう、というのはどうでしょうか?
これですと拡大縮小は思いのままだと思うのですが。

国をクリックして選択するとなると、その国の形にできるだけ近い矩形をムービークリップで入れていく、はめていくとこになるかと思いますが。

何か勘違いしていますか?

それとも題のとおり、複雑な図形の当たり判定でないとだめなのでしょうか?
書いているうちに自信がなくなってしまいましたが、一応投稿してみます。

と書いているうちに、質問者の方の書き込みが直前にありました。
読んでも理解できなかったので、はずしている感じですが、一応この文も残しておきます。


----------------
永井勝則:
himco.jp :

永井勝則
Åê¹ÆNo.14768
投稿日時: 2005-2-3 22:40
職人
居住地: 白馬村
投稿: 796
使用環境:
Windows 7 :Flash CS4:
10.6.8 :Flash CS5.5
Re: 複雑な図形の当たり判定
よーく読んで少し見えてきました。

guid_mcに、ステージ場で表示されているかどうかを示すboolean値のプロパティを作って、拡大縮小させる度に、ステージ場で表示されているかどうかを調べて、表示されているguid_mcを集めて(これは行列(2x3とか、8x6とかいう縦横の図形になるのでしょうね))、その縦の真ん中、横の真ん中のguid_mcを判定し、表示されている(国の)複数のgiud_mcの中からセンターのguide_mcを決定するというのはどうでしょう?

ステージ場で表示されているかどうかは、各guid_mcの座標とステージの大きさを比べるのでしょうかねぇ。

もっといい案が浮かぶかも知れません。


----------------
永井勝則:
himco.jp :

mnacko
Åê¹ÆNo.14773
投稿日時: 2005-2-3 23:39
新米
居住地:
投稿: 3
使用環境:
Mac OSX 10.3.7, Flash MX2004
Re: 複雑な図形の当たり判定
永井さん
ありがとうございます。

言葉足らずでしたね。
世界地図は1枚のグラフィックではなく、
一カ国ごとに、ベクターで描いてムービークリップとしています。
日本とか中国とか作って、それぞれに"m"+国番号という名前を付けています。
これらのmMの集合体でできた世界地図がmap_mcなのです。

で、guide_mcというのは一辺が20の正方形のブロックがステージ上に埋まっています。
ステージサイズが400*300だと20*15個のブロックで
個々の国と当たり判定をしています。

ムービークリップ同士のhitTestだと、
たとえば日本の場合、北海道の右上から沖縄までの四角形(ブロックが3*4とかの)になるので、
土地のない海も含まれてしまいます。

結局、国のムービークリップとブロックの座標との
mM.hitTest(hit_guide_X_Y._x, hit_guide_X_Y._y, true)
で、土地との当たり判定をして、このhitTestがtrueのブロックだけ集めています。
hit_array = new Array();
for(i=0;i<g_num_x;i++){
    for(j=0;j<g_num_y;j++){
        hg = eval("_root.guide_base.hit_guide_"+i+"_"+j);
        if(_root.map_mc.日本.hitTest(hg._x,hg._y,true)==true){
            //hg_loc=[X座標,Y座標,インスタンス名]
            hg_loc = hg._x+","+hg._y+","+hg;
            hit_array.push(hg_loc);
        }
    }
}


何かもっとスマートな方法があればと思ったのですが、
むずかしいですかね。
永井勝則
Åê¹ÆNo.14778
投稿日時: 2005-2-4 0:18
職人
居住地: 白馬村
投稿: 796
使用環境:
Windows 7 :Flash CS4:
10.6.8 :Flash CS5.5
Re: 複雑な図形の当たり判定
元に戻ってお聞きしたいのですが、
1)代替案を求めておられるのか、
引用:
何かもっとスマートな方法があればと思ったのですが、
むずかしいですかね。


2)今のスクリプトから解決策を求めておられるのか、
引用:
ロシアの見えている部分と重なるhit_guide_X_Y達が分かるのですが、
これらの内、見えている部分のちょうど真ん中ぐらいにあるhit_guide_X_Yが分からないものでしょうか?


どちらですかね?

2)の方なら、hit_guide_X_Y達が分かっているのなら、その真ん中あたりのhit_guideムービークリップは特定できるのではないですか。
ブロックが、
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
11,12,13,14,15,16,17,18,19,20
とあって、このうち、
1, 2, 3, 4
11,12,13,14
が某国ムービークリップと重なっているのなら、真ん中は2,3,12,13あたりですよねぇ。
スクリプティングは面倒だと思いますが、ブロックの名前を扱いやすい名前して、横も分かりやすいように10刻みにしたら出来ると思います。

それともこれが面倒だから他の方法を求めておられるのでしょうか?


----------------
永井勝則:
himco.jp :

空野大二郎
Åê¹ÆNo.14784
投稿日時: 2005-2-4 1:19
職人
居住地: 愛知
投稿: 389
使用環境:
 XP:Home
FlashMX
IE6.0+FlashPlayer7,0,19
CPU:Pentium4 2.26GHz
メモリ:1,024MB
Re: 複雑な図形の当たり判定
 まいど。

 mnackoさんが問題意識を持っていらっしゃるのは、『ムービー
クリップブロックを使った現状の「ステージに表示中の、
国の中心座標を取得する」.swfムービーが、精度を高くするほど
CPU負荷が高くなってしまう』についてですね。

 それについては分かりましたが、代替案を求めていらっしゃるのか、
現状に対する改善案を求めていらっしゃるのかははっきりして
いただくと、フォーラム参加者としても回答しやすいです。
 永井勝則さんの意見に同意します。
引用:
永井勝則さんは書きました:
元に戻ってお聞きしたいのですが、



 さて、もし、現状の改善案となると、一つの例が挙げられます。

 <問題点>
 当たり判定用のムービークリップブロックを増やすと、CPU負荷が高くなる。

 <着眼点>
 対象のムービークリップは、座標を知るだけのために配置されている。
 衝突判定用のオブジェクトを、MovieClipではなく、Objectで代用できないか?

 <改善案>
 衝突判定用のオブジェクトをコンストラクタで生成し、
そのオブジェクトに参照用オブジェクト名でオブジェクトを生成し
(インスタンス名のように)、「x」「y」のプロパティを定義。

_rootのフレームアクションに記述
//衝突判定用のブロック座標オブジェクト生成関数
//hitXY_obj.xyX_Y.x(もしくは「y」)のように参照可能。
//「X」および「Y」は0からはじまる通し番号。
blockSet = function () {
	hitXY_obj = new Object ();
	//ループ用のオブジェクト数を「hitXY_obj」の変数に格納
	hitXY_obj.xMaxNum = 20;  //xの最大オブジェクト数、0から数える
	hitXY_obj.yMaxNum = 15;  //yの最大オブジェクト数、同上
	var j = 0;
	for (j = 0; j <= hitXY_obj.xMaxNum; j++) {
		var i = 0;
		var theXY_array = new Array ();
		for (i = 0; i <= hitXY_obj.yMaxNum; i++) {
			hitXY_obj["xy" + j + "_" + i] = new Object ();
			hitXY_obj["xy" + j + "_" + i].x = (j * 20);
			hitXY_obj["xy" + j + "_" + i].y = (i * 20);
		}
	}
};
blockSet ();
//確認、Xが0番目、Yが1番目の座標を取得。
trace ("xy0_1.x = " + hitXY_obj.xy0_1.x);
trace ("xy0_1.y = " + hitXY_obj.xy0_1.y);


 MovieClipクラスのインスタンスにくらべて、Objectクラスの
インスタンスは必要以外のプロパティが定義されていないため、
CPU負荷が軽くなる。

 構造をご理解されたら、オブジェクトの定義場所をmnackoさんの
お手元の状態に書き換え、ブロックムービークリップの代用に
お使い下さい。
 CPU負荷が軽くなった分ブロック座標数も増やせますが、
ループ処理が増えるのはどのみち避けられませんね。
 (やはり、代替案が必要かもしれません)


 注意:生成したObjectオブジェクトもMovieClip同様、_rootが
削除されない限り存在し続けますので、不要になったら、
「delete hitXY_obj;」のように削除して下さい。


----------------
空野 大二郎 アニメーター作家
桜の道

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

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