dポイントプレゼントキャンペーン実施中!

actionscript2.0を使い、bg0~bg9と配列で並んだムービークリップに対して、hit判定があった場合、hitしたムービークリップの数の分だけ、位置がずれていくという動的なムービークリップの移動と配置をさせたいと考えています。(画像参照)
また、「hitBar」を外した際に、元いた位置に戻ってほしいです。

ムービークリップの配置の配列は、下記のスクリプトを使用しています。

objA = new Array(2* 5);

D = 0;
sy = 112;
for (y = 0; y < 2; y++) {
sx = 70;
for (x = 0; x < 5; x++) {
objA[D] = _root.attachMovie("bg" , "bg" + D, D + 100);
objA[D]._x = sx;
objA[D]._y = sy;
D++;
sx += 36;
}
sy += 36;

}

actionscriptはまだまだ未熟なもので、いろいろと試してみたのですが、どうにも上手くいかずに困っています…
どうかお知恵を貸していただけたら幸いです。
画像のような動きができれば、上記のスクリプトを用いらずともまったくかまいません。
よろしくお願いいたします。

「actionscript2.0で動的な位」の質問画像

A 回答 (4件)

#1です。


返事が遅くなってしまいましたが。

> 01234
> 56789
>
> が
>
> □□□3 4
> 5 6 7 8 9
> 0 1 2

なるほど,
#1のスクリプトだと確かにそうなりますね。
私の確認不足でした。
すみません。

それではスクリプトを次のように変更してみてください。

//-----------------------------------------------
//「bg○」の参照を入れる配列を用意
var objA:Array = new Array(2*5);

//「bg○」の座標を入れる配列を用意
var posA:Array =[
[70, 112], [106, 112], [142, 112], [178, 112], [214, 112],
[70, 148], [106, 148], [142, 148], [178, 148], [214, 148],
[70, 184], [106, 184], [142, 184], [178, 184], [214, 184],
[70, 220], [106, 220], [142, 220], [178, 220], [214, 220]
];

//「bg○」の入る位置番号を入れる配列を用意
var numA:Array = new Array(objA.length);

//「bg○」の生成&配置
for (var i:Number=0; i<objA.length; i++) {
objA[i] = _root.attachMovie("bg", "bg"+i, i+100);
//●動作確認用(本題とは関係なし)
//objA[i].createTextField("tf",0,-15,-15,24,24);
//objA[i].tf.text = i;
objA[i]._x = posA[i][0];
objA[i]._y = posA[i][1];
}

//「hitBar」をドラッグできるようにする
hitBar.onPress = function():Void{
this.startDrag();
};
hitBar.onRelease
= hitBar.onReleaseOutside = function():Void{
this.stopDrag();
};

//毎フレーム実行
this.onEnterFrame = function():Void{
//配列「numA」の初期化と「bg○」の配置
for (var i:Number=0; i<objA.length; i++) {
numA[i] = i;
objA[i]._x = posA[numA[i]][0];
objA[i]._y = posA[numA[i]][1];
}
//
//「bg○」に関するループ
for (i=0; i<objA.length; i++) {
//「bg○」が「hitBar」にヒットしている間はループ
while(objA[i].hitTest(hitBar)){
//★ j:Number=0; を j:Number=i; に変更
for (var j:Number=i; j<objA.length; j++) {
numA[j]++;
//★座標移動をココから削除(下に移動)
}
//★この for 文を付け足し
for (j=0; j<objA.length; j++) {
//★座標移動
objA[j]._x = posA[numA[j]][0];
objA[j]._y = posA[numA[j]][1];
}
}
}
};
//-----------------------------------------------



変更したのは ★ を付けた部分で,その他は基本的にそのままです。
(● を付けてコメントアウトしてある部分は,私自身のための動作確認用スクリプトです。)
    • good
    • 0
この回答へのお礼

お礼が遅くなりまして申し訳ありません!
わざわざこちらの要望に合わせて改変してくださってありがとうございます…!
お陰様で無事に動作させることができました。
本当に感謝感激です。ありがとうございました!

お礼日時:2013/01/27 14:59

#2の解説です。




ムービークリップ bg0 ~ 9 の下に、四角形のムービークリップ grid0 ~ 19 を非表示にして並べます。
バーとの当たり判定は grid の方で取り、バーおよび bg のいずれも占有していないマスを探し、空いているマスの上に bg0 から順番に配置していきます。

作例で bg は 10 個ですが、バーに押し出された時に bg はバーの分だけはみ出して配置されるので、グリッドのマスは 10 個では足りません。
また、バーは最低でも2段、バーの高さによってはそれ以上の段にまたがる可能性もあります。
バーがどのように動いてもマス2段分で収まるくらいの高さとしても、グリッドのマスの初期配置である横5×縦2マスよりも2段ほど多く必要です。
#2の作例では横5×縦4マスのグリッドを想定しています。


マスの空き状況は配列変数で管理します。
画面では横5×縦4マスのグリッドなので、2次元配列の方が縦・横を直接対応させることができて便利のような気がします。
しかし、空いているマスを探すには単に1つ1つの要素を順番に見ていけばいいだけで、縦・横を考慮する必要はありません。ですから、実は1次元配列の方が楽に管理できます。

1次元で考えると分かりにくいのは、最初にマスをグリッド状に並べる時だけです。
grid0 ~ 19 を for の単ループで横5×縦4マスに並べるには、グリッド内での位置(○行○列)を考えると簡単です。
この位置は

 横(行)=ループカウンタを横のマス数で割った時の余り
 縦(列)=ループカウンタを横のマス数で割った時の商

で、求めることができます。
縦は Math.floor で小数点以下を切り捨て、整数にします。
こうして得られたグリッド内での位置にマスの大きさを乗算すると、実際の画面の座標に変換できます。
グリッドの左上がステージの左上ではない場合は、これに更にグリッドの左上にしたい座標をそれぞれ加算します。


要素数がマスの総数と同じ、作例では 20 個(インデックスは 0 ~ 19 )の1次元配列変数を用意します。作例では grid_status という配列変数です。
この要素1つ1つを、grid0 ~ 19 に何か接しているかどうかのフラグにし、バーおよび bg のいずれかが占有しているマスにあたる要素には 1 、占有されていない要素には 0 を入れるものとします。

バーがドラッグで動かされた時、まず、grid0 ~ 19 とバーとの当たりを総当たりで取り、この結果を配列変数に記録します。
作例では、関数 Clip_Align の冒頭でこの処理を行っています。
この時点では、バーと接触しているマスの番号に該当する要素のみ 1 になり、それ以外の要素は 0 になります。

次に、配列変数を順番に見て 0 になっている要素の番号を探しながら、bg0 ~ 9 を空いているマスの上に並べていきます。
これは、ループを2重にして調べます。
外側 i のループカウンタは 0 ~ bg の総数までカウントアップし、bg0 ~ 9 を全部参照できるようにします。
内側 j のループが、配列変数を調べ、空いているマスの番号を探すためのループです。
配列変数は常に 0 番から順番に見ていってもいいのですが、前回の時点でバーや自分より若い番号の bg が占有したことが明白なマスは、調べるだけムダです。
そこで、空きが見つかった時に、j の値を変数に残すことにします。これを j のループの初期値にすると、既に塞がっているマスを繰り返し調べてしまうムダを省くことができます。1次元の配列変数にすると、こうした処理が作りやすい利点があります。
内側 j のループは、空いているマスが見つかったら打ち切って構いません。作例では、ループの継続条件に配置できたかどうかのフラグ(変数 put_flg )の判定を設け、配置フラグが true になった時点でループを打ち切るようにしています。

このようにして空いているマスの番号(= j の値)を調べ、grid+ j 番のマスの上に bg + i 番のムービークリップを重ねて配置していくことで、バーが重なっているマスを避けてムービークリップを並べることができます。
なお、マスの単位で配置するため、バーが複数の段にまたがった場合は、どうしても隙間が大きく見える場合があります。


作例では、空いているマスの座標に bg を直接配置しています。
どちらのムービークリップも左上を基準点と想定しているので、つまり、grid の左上と bg の左上を合わせて配置する形です。
隙間を空けて見せたい・左上に貼りついて見えると見栄えが悪いなどの場合は、grid の大きさやそれぞれの基準点の位置を変えるか、関数 Clip_Align 内でムービークリップの位置を決めている

 base[ "bg" + i ]._x = base[ "grid" + j ]._x;
 base[ "bg" + i ]._y = base[ "grid" + j ]._y;

↑ この部分を調整してみてください。


今回はグリッドや動かすムービークリップをスクリプトで配置しましたが、ステージに予め配置しておくと、初期配置を決める処理を省略できます。
    • good
    • 0
この回答へのお礼

お礼が遅くなりまして申し訳ありません!
ベストアンサーはもう一人の方にお渡ししてしまったのですが、非常にわかりやすい解説とスマートなスクリプトに感動いたしました…!
なんとお礼を差し上げたら良いか…本当にありがとうございます!

お礼日時:2013/01/27 15:02

次のように考えてはいかがでしょう。



動かすムービークリップ bg の下に四角形のムービークリップを非表示にしてグリッド状に並べ、これらのマスのムービークリップそれぞれとバーとの当たり判定を取ります。

マスの数と同じ要素数の配列変数で、マスの空き状況を管理します。
配列変数のインデックス(要素の番号)がマスの番号に相当するものとし、バーが接している、および bg のムービークリップが占有しているマスの番号と同じ要素に 1 、何もない要素に 0 を入れます。
bg を並べる時は、配列変数を先頭から見ていき、空いているマス、つまり、要素に 0 が入っているインデックスを探し、bg0 から順番に、インデックスに該当する番号のマスの上に配置していきます。


作例です。

動かすムービークリップ(リンケージ名: bg )と、これよりも少し大きいくらいの四角形を描画したムービークリップ(リンケージ名: GRID )のシンボルを作り、それぞれリンケージを設定します。
bg と GRID の基準点は左上を想定しています。
バーのムービークリップ(インスタンス名: hitBar )は、予めステージに配置しておきます。

バーを避けて bg を配置するスクリプトの一例です。
メインのタイムラインのフレームに記述してください。

(↓ 各行頭に全角のスペースが入っています。コピーする際は、全て半角のスペースかタブに置き換えてください)


//***

/*
 初期設定
*/

//グリッドの左上の座標とマス目の数(横×縦)
var org_x:Number = 50;
var org_y:Number = 50;
var raw:Number = 5;
var col:Number = 4;

//並び替えるムービークリップの総数
var clip_max:Number = 10;

//ムービークリップがあるタイムラインを記録
var base:MovieClip = this;

//マスの空き状況を管理する配列変数
//バーやムービークリップが占有しているマスは1、何もないマスは0で管理
var grid_status:Array = new Array( raw * col );

//ドラッグフラグ
//ドラッグ中true、それ以外はfalse
drag_flg = false;


/*
 グリッドとムービークリップの初期配置
*/

function SetUp():Void
{
 var i:Number;
 var gx:Number , gy:Number;
 var temp:MovieClip;


 //当たり判定用のマスを配置
 for( i = 0 ; i < grid_status.length ; i++ )
 {
  //グリッド内での位置を求める
  gx = i % raw;
  gy = Math.floor( i / raw );

  //マスを配置し、非表示にしておく
  temp = base.attachMovie( "GRID" , "grid" + i , i );
  temp._x = temp._width * gx + org_x;
  temp._y = temp._height * gy + org_y;
  temp._visible = false;

  //空き状況の配列変数を初期化
  grid_status[ i ] = 0;
 }

 //マスにムービークリップを重ねて配置
 for( i = 0 ; i < clip_max ; i++ )
 {
  temp = base.attachMovie( "bg" , "bg" + i , base.getNextHighestDepth() );
  temp._x = base[ "grid" + i ]._x;
  temp._y = base[ "grid" + i ]._y;
 }
}

//グリッドとムービークリップを配置
SetUp();


/*
 当たり判定と並び替え
*/

function Clip_Align():Void
{
 var i:Number , j:Number , check_inx:Number;
 var put_flg:Boolean;


 //全マスとバーの当たりを総当たりで取り、
 //接触状況を配列変数に記録する
 for( i = 0 ; i < grid_status.length ; i++ )
 {
  grid_status[ i ] = Number( hitBar.hitTest( base[ "grid" + i ] ) );
 }


 //照合するインデックスをリセット
 check_inx = 0;

 //空いているマスにムービークリップを配置
 for( i = 0 ; i < clip_max ; i++ )
 {
  //配置フラグを初期化
  //配置できた時true、それ以外はfalse
  put_flg = false;

  //空いているマスを探して配置する
  //照合済みの要素は調べない
  for( j = check_inx ; j < grid_status.length && ! put_flg ; j++ )
  {
   //要素の値が0であれば、このインデックスと同じ番号の
   //マスの場所に配置
   if( grid_status[ j ] == 0 )
   {
    base[ "bg" + i ]._x = base[ "grid" + j ]._x;
    base[ "bg" + i ]._y = base[ "grid" + j ]._y;

    //配置の成功と、配置したマスの番号を記録
    grid_status[ j ] = 1;
    put_flg = true;
    check_inx = j;
   }
  }
 }
}


/*
 バーの処理
*/

//バーを一番上にする
hitBar.swapDepths( base.getNextHighestDepth() );

hitBar.onPress = function()
{
 //ドラッグを開始
 this.startDrag();

 drag_flg = true;
};

hitBar.onRelease = onReleaseOutside = function()
{
 //ドラッグを終了
 this.stopDrag();

 drag_flg = false;
};

hitBar.onMouseMove = function()
{
 //ドラッグ中のみ、ムービークリップを並び替える
 if( drag_flg )
 {
  Clip_Align();
 }

 //表示を更新
 updateAfterEvent();
};

//***


字数の制限上、詳細は次の回答で説明いたします。
    • good
    • 0

ステージ上には


「hitBar」というインスタンス名を付けた
横:約140px 縦:約40px ほどのムービークリップが1つあるものとします。

ライブラリの中には
「bg」という識別子を付けた
横:約30px 縦:約30px ほどのムービークリップが1つあるものとします。

そのような状況であるとした場合
「hitBar」が存在するタイムラインのフレームに書くスクリプトの一例です。

//-----------------------------------------------
//「bg○」の参照を入れる配列を用意
var objA:Array = new Array(2*5);

//「bg○」の座標を入れる配列を用意
var posA:Array =[
[70, 112], [106, 112], [142, 112], [178, 112], [214, 112],
[70, 148], [106, 148], [142, 148], [178, 148], [214, 148],
[70, 184], [106, 184], [142, 184], [178, 184], [214, 184],
[70, 220], [106, 220], [142, 220], [178, 220], [214, 220]
];

//「bg○」の入る位置番号を入れる配列を用意
var numA:Array = new Array(objA.length);

//「bg○」の生成&配置
for (var i:Number=0; i<objA.length; i++) {
objA[i] = _root.attachMovie("bg", "bg"+i, i+100);
objA[i]._x = posA[i][0];
objA[i]._y = posA[i][1];
}

//「hitBar」をドラッグできるようにする
hitBar.onPress = function():Void{
this.startDrag();
};
hitBar.onRelease
= hitBar.onReleaseOutside = function():Void{
this.stopDrag();
};

//毎フレーム実行
this.onEnterFrame = function():Void{
//配列「numA」の初期化と「bg○」の配置
for (var i:Number=0; i<objA.length; i++) {
numA[i] = i;
objA[i]._x = posA[numA[i]][0];
objA[i]._y = posA[numA[i]][1];
}
//
//「bg○」に関するループ
for (i=0; i<objA.length; i++) {
//「bg○」が「hitBar」にヒットしている間はループ
while(objA[i].hitTest(hitBar)){
for (var j:Number=0; j<objA.length; j++) {
numA[j]++;
objA[i]._x = posA[numA[j]][0];
objA[i]._y = posA[numA[j]][1];
}
}
}
};
//-----------------------------------------------




スクリプトには次の部分があります。

//「bg○」の座標を入れる配列を用意
var posA:Array =[
[70, 112], [106, 112], [142, 112], [178, 112], [214, 112],
[70, 148], [106, 148], [142, 148], [178, 148], [214, 148],
[70, 184], [106, 184], [142, 184], [178, 184], [214, 184],
[70, 220], [106, 220], [142, 220], [178, 220], [214, 220]
];


この部分は視覚的にわかりやすくするために
上のように手動で座標を記入しているだけです。
計算(ループ文)で数値を代入して行っても良いです。

この回答への補足

早速の回答ありがとうございます!
非常に丁寧かつ分かりやすいご説明に感激しております…!

けれど大変申し訳ございません、こちらの説明不足で上手く伝わらなかったようで…
頂いたサンプルですと、hitBarがbg0、1、2にhitした場合、

01234
56789



□□□3 4
5 6 7 8 9
0 1 2

□□□ = hitBar

このように最後に移動するように作って頂いたのですが、
できたら最後に移動するのではなく、hitBarによってその分押し出されたように移動させたいと考えていました(下記)

□□□0 1
2 3 4 5 6
7 8 9

このように移動させることは可能でしょうか…?
一度丁寧に教えて頂いて厚かましい限りですが、どうかお教え頂けたら幸いです。
何卒よろしくお願いいたします。

補足日時:2013/01/21 19:50
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!