【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】

こんばんは。WinXP、Flash8Proにてオーサリングしています。

hitTestにて衝突判定を行っているのですが、
RPGの場合、キャラクターが障害物に衝突する際の
処理に頭を悩めております。

_global.obje_hit=function(){

if(_global.key_cord=='d'){

_root.main_mc.player_mc._x -= 20;

}else if(_global.key_cord=='a'){

_root.main_mc.player_mc._x += 20;

}else if(_global.key_cord=='w'){

_root.main_mc.player_mc._x += 20;

}else if(_global.key_cord=='s'){

_root.main_mc.player_mc._y -= 20;
}
_root.main_mc.player_mc.gotoAndPlay(1);
}

*キャラクターの移動は他のFunctionにて
キー入力により、ASで位置やMCの動きを制御しています。

W,S,A,Dのそれぞれのキーで上下左右の向きのMCを再生させて、場所移動によって動かしているのですが、
現時点では、プレイヤーのMCが障害物と反発する事でしか、障害物による静止処理ができていません。
跳ね返らずに、一般的なRPGの様に”行き止まる”様にしたいのですが、
ASだけでするには、どのようにしたら良いのでしょうか。
やはり、キャラクターの行動しているMCから調節しなくてはいけないのでしょうか。

どうぞ宜しくお願い致します。

A 回答 (4件)

#1、2です。



2D(初期の「ドラゴンクエスト」のようなタイプ)だと思ったら、擬似3Dだったのですね。


2Dは見た通りに当たりをとり、その手前で立ち止まらせればいいので直感的に考えられるのですが、3Dになるとそう簡単にはいきません。

例えば壁にぴったりくっついて立っている人を真後ろから見ると、人と壁は重なって見えます。
この人が壁から1歩離れたところに立っていたとしても、やはり、人は壁と重なって見えます。
つまり3Dでは、画面では接しているように見えるのに実際には接していないことがよくあります。
この区別をつけて当たりをとらなければならないことが、3Dの難しいところの1つだと思います。

***************************************

現在主流のポリゴンを用いた3Dのゲームでは、キャラクターも背景も3次元座標(水平・垂直・奥行き)を持っています。
ただ、画面に表示する時は2次元座標でないと描画できないので、表示する直前に3次元座標を2次元座標に変換しています。

3次元座標を持っているもの同士であれば、この座標を利用して奥行きの判断などもできます。
先の人と壁の例で言うと、画面では接して見えるが離れているというような状況でも、壁と人のZの座標を見ることで接していないと判断できます。

しかし、Flash は基本的には2次元座標しか扱いませんので、3次元座標を利用して奥行きを考慮した当たりをとることはできません。
また、”画面上では接しているが実際は接していない”という状況を判断するには、ムービークリップ同士(もしくはムービークリップとある1点)が接しているか否かしか判断できない hitTest では難しいでしょう。
あえて3次元的な衝突判定をとるのならば、ゲームの処理内だけで使う仮想の3次元座標を変数などで割り振っておく必要があるかと思います。

***************************************

3次元座標の計算やポリゴンの描画処理は複雑で、CPUの演算能力が要求されます。
いわゆるポリゴンによる3DCGが家庭用ゲーム機や一般向けのコンピュータでは夢物語だった頃、2次元座標だけで3次元らしく見せる手法が考案されました。
シューティングやアクションなど様々なジャンルのゲームに擬似3Dの傑作がありますが、RPGで有名なのは「ウィザードリィ」でしょうか。
移植物の画面写真ですが、

 ・ウィザードリィとは?
  http://www.sting.co.jp/game/wiz/info.htm

↑この中ほどにあるワイヤフレームのダンジョンの表現が、擬似3D迷路の基本かもしれません。


昔、こんな線画しか描けない能力のパソコンで作られた作品が、計算に時間のかかる3次元座標を採用して描画処理や当たり判定をとっていたのではありません。
このカラクリのタネは、2次元配列変数にマップデータを用意しておき、この値を見ながらプレイヤーの移動や迷路の描画をリアルタイムで行うというものです。
配列変数を使う擬似3Dはここで1から説明できるようなものではありませんので、考え方だけを簡単にご紹介します。

基本的には、プレイヤーが1歩進むごとに1歩先の地形(1つ隣の配列変数の要素)を調べて、通路ならば進む・壁があれば止まる・イベントの場所ならイベントの処理をします。
これなら衝突判定をとることもなく、プレイヤーが移動できる場所を簡単に制限できます。

迷路の作り方や表現は様々な技法が研究されていますが、よく知られていて使いやすいのは、やはり2次元配列を使う方法です。
迷路は2Dのマップのように最初から作っておくのではなく、随時プレイヤーの位置から見た風景を2次元配列のデータを元に調べ、迷路を構成するパーツを動的に配置します。
マップデータを配列変数で持っておくとプレイヤーから数歩先が壁なのか通路なのかなども判断できますから、迷路の描画はこの値を元に壁やイベントなどを配置していく流れになります。
奥行きや遠近感は、立体風に作ったパーツを予め何種類か用意しておき、奥の方から順にパーツを置いていくことで表現します。
Flash 8 から使えるようになったフィルタを駆使して、陰影や奥の方ほどかすんで見えるようなダンジョンを表現してみるのも、リアルさが出て面白いかもしれませんね。


ポリゴンでも擬似3Dでも、3Dではキャラクターが向いている方向の管理が必要です。
2Dでは、左キーを押すとキャラクターは左に、右キーを押すと右に・・・というように、方向キーとキャラクターの移動方向を対応させて処理することができます。
ところが3Dの場合は、キャラクターが北を向いている時は東が右・西が左ですが、東を向いた時は南が右・北が左と、キャラクターの向きによって方向が変化します。
方向がしっかり管理されていないと、左に曲がるはずなのに画面では右に行ってしまうなど、おかしな動作になることがあります。

2次元配列を使った擬似3Dでは、方向は配列変数の要素を見る位置に関係があります。
擬似3Dの迷路は基本的には4方向の移動ですから、キー入力に応じた方向で管理する方法が一般的です。
ポリゴンの3Dでは、ここ数年の家庭用ゲーム機には曲線的な操作ができるコントローラが添付されるようになったためか、移動方向は単純に4方向および8方向では済まない場合が多くなりました。
この手のゲームでは、キャラクターと対象の位置から角度を割り出して方向を調べるといった方法があります。

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

2Dのマップで衝突判定が上手くいかない点については、別の質問( No.2065184 )が立っているとのことですので、そちらで回答いたします。
    • good
    • 0

横から失礼いたします。

また回答遅くなりました。
#1&#2の方の#2案と並行できるかもしれませんし,
#1案とは別案なのですが,こんなのはどうでしょう。

質問者さまが書かれているとおり,跳ね返すのは跳ね返します。
でも20ピクセル跳ね返すのではなくて,
1ピクセルずつ hit しなくなるまで for文 で跳ね返すという方法です。
一応,接触したときに”行き止まる”様に見えます。

_root.main_mc.player_mc という プレーヤーMCはそのままで,
_root に obstacle1 (意味:障害物1)というインスタンス名の
四角い ムービークリップ を作った場合です。

あっちこっちに書くと説明がややこしいので,
_root のタイムラインの 1つのフレームに書くのスクリプトにしました。

-----------------------------------
//スピードの設定(可変)
_global.spd = 10;

//1ピクセルだけ跳ね返す
_global.obje_hit = function() {
if (_global.key_cord == 'd') {
_root.main_mc.player_mc._x--;
} else if (_global.key_cord == 'a') {
_root.main_mc.player_mc._x++;
} else if (_global.key_cord == 'w') {
_root.main_mc.player_mc._y++;
} else if (_global.key_cord == 's') {
_root.main_mc.player_mc._y--;
}
_root.main_mc.player_mc.gotoAndPlay(1);
};

// player_mc の移動と制御
_root.onEnterFrame = function() {

with (_root.main_mc.player_mc) {
if (Key.isDown(68)) {
_global.key_cord = "d";
_x += _global.spd;
} else if (Key.isDown(65)) {
_x -= _global.spd;
_global.key_cord = "a";
} else if (Key.isDown(87)) {
_y -= 10;
_global.key_cord = "w";
} else if (Key.isDown(83)) {
_y += 10;
_global.key_cord = "s";
}
}

// ヒットしなくなるまで _global.obje_hit を
// 繰り返し実行(上限_global.spd 回)
for (i=1; i<=_global.spd; i++) {
if (_root.obstacle1.hitTest(_root.main_mc.player_mc)) {
_global.obje_hit();
}
}

};
-----------------------------

↑こんな感じです。
_root に main_mc.player_mc とobstacle1 という
インスタンス名のムービークリップを作っていただくと
コピペで使えると思います。
実際は衝突したときに 1ピクセルだけ離れるのですが,
その1ピクセルの隙間はなんとかご容赦してください。

という案です。

今回,
実際に作ってみてわかったのですが,
for文 の中でも hit してるかどうかは,onEnterFrame のように,徐々に再計算&判定されるようです。
    • good
    • 0
この回答へのお礼

お返事有難うございます^^
さっそくためさせて頂きました。
擬似3Dなので応用させないとやはり無理でしたが、
単純なFlashでしたら十分いけそうです♪
どうも有難う御座いました。

お礼日時:2006/03/31 23:57

#1です。




#1の関数は障害物に接触した時にその手前でプレイヤーを立ち止まらせる処理だけで、衝突判定は行っていません。
衝突判定の処理は別途作成してください。

プレイヤーが障害物の手前で立ち止まるのは、言うまでもなく、障害物に接触した時だけです。
ですから、障害物に接触した時にだけ、該当する障害物の情報を利用してプレイヤーの位置を調整すればよく、常に全ての障害物に対して行う必要はありません。

衝突判定に hitTest を利用するのでしたら、接触した障害物のムービークリップのインスタンス名が判明すると思います。
プレイヤーが何かと接触したと判断される時に、その障害物のムービークリップの参照を引数にして関数を呼び出してください。


#1の関数内で使っている” obstacle ”は仮引数です。
ムービー内の特定のムービークリップを指すものではありませんから、どの階層に属するムービークリップであっても対応できます。

ただ、階層がかなり深く複雑になっているようですので、ターゲットパスの誤りにはご注意ください。
また、外部から読み込んだ swf ファイル内にあるものを参照する場合は、読み込みの完了を待つ処理もお忘れなく。

******************************************

例えば、_root 階層にあるマップのムービークリップが

 map
 ┣ house_wall
 ┃ ┣ wall_unit_a
 ┃ ┗ wall_unit_b
 ┃
 ┣ shop_wall
 ┃ ┗ block
 ┃
 ┗ rock

という構成になっているとします。
シンボルで作っても外部 swf ファイルを map に読み込んだ場合でも階層の関係は変わりませんが、外部から読み込んだファイル内では _root の指す対象が変わることがあるのでご注意ください。

map 内にある障害物との接触を調べ、その手前で立ち止まらせる処理は、次のような流れになります。
立ち止まらせる関数は、#1に書いた通りの関数が定義されているものとします。

(↓各行頭に全角のスペースが入っています。コピーする際はご注意ください)


 var ply:MovieClip , hit_flg:Boolean , child:Number;


 ply = _root.main_mc.player_mc;

 //障害物と接触時true、それ以外はfalse
 hit_flg = false;


 //mapムービークリップにあるオブジェクトを列挙
 for( name in _root.map )
 {
  child = 0;

  //mapの子が持つオブジェクトを列挙
  for( clip in _root.map[ name ] )
  {
   child++;

   //障害物との衝突判定
   //接触時のみ、プレイヤーを障害物の手前で立ち止まらせる
   hit_flg = _root.map[ name ][ clip ].hitTest( ply );
   if( hit_flg )
   {
    obje_hit( _root.map[ name ][ clip ] );
   }
  }

  //子がない場合は自分自身との衝突判定を行う
  if( ! child )
  {
   //障害物との衝突判定
   //接触時のみ、プレイヤーを障害物の手前で立ち止まらせる
   hit_flg = _root.map[ name ].hitTest( ply );
   if( hit_flg )
   {
    obje_hit( _root.map[ name ] );
   }
  }
 }


複数のムービークリップや変数などを効率よくさばく方法として、固有の名前+通し番号で名前を付け、for ループを利用して次々と参照していく手法があります。
しかしこの手法は、オブジェクトに付ける名前が限定されるところが欠点です。

同じく複数の対象を次々に参照できるものに、for in があります。
for in はオブジェクトに含まれる要素を列挙するもので、ムービークリップに対して使うと、子がある場合はそのインスタンス名を取得できます。
つまり、ムービークリップに含まれる子のインスタンス名が上記の例のように何の規則性もなかったとしても、全ての子のインスタンスを操作することができます。
(厳密にはムービークリップが持っている変数なども列挙されますが、上記のスクリプトでは hitTest メソッドがない要素が列挙されても何も起こりません)

ただし、for in はムービークリップで言うところの子のインスタンスしか列挙できません。
上記の例ですと、外側の for in ではムービークリップ” map ”の持っている子( house_wall , shop_wall , rock )だけが列挙されます。

map の子が持っているインスタンス名までは列挙できないので、for in を入れ子にして調べます。
house_wall と shop_wall は子を持っていますから、もう1つの for in でこれらの子を列挙します。

この例では、rock だけは子を持っていません。
map から見て2階層下のインスタンスを列挙する内側の for in の中だけで衝突判定をとると、rock との衝突判定が行われなくなってしまいます。
上記のスクリプトでは内側の for in では子の数をカウントし、子の数が0だった時には自分自身( map の子)のムービークリップで衝突判定をとるようにしています。


今回は一例として、特定のムービークリップ内に含まれる障害物とプレイヤーとの衝突判定をとり、接触時にその手前でプレイヤーを立ち止まらせるスクリプトをご紹介しました。
ある決まったムービークリップで調べるのではなく、for in で列挙するムービークリップの参照を引数で受け取る関数を設計すると、他のムービークリップとの衝突判定にも利用できます。

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

それから、衝突判定ですが。
RPGのマップは衝突判定をとる対象が多くなるのは確かですが、工夫次第で判定する対象を減らすことはできます。


例えば街の中を歩いている時は、街を構成する建物や障害物と歩いている人などとだけ衝突判定をとれば済みます。
民家などの中に入った時は、民家の内部にある壁や障害物と家の中にいる人とだけで充分です。家の外にある建物や外を歩いている人と接触しないのは明白なので、衝突を調べるだけ無駄な処理になります。

すると、プレイヤーが今どこにいるのか(街の中や民家・ワールドマップなど)という情報が必要になります。
この情報は、例えば街にいるのなら街に入った時に、民家に入ったらその時にでも、変数に記録しておくといいでしょう。
プレイヤーがいる場所の情報を常に管理しておくと、この情報を元に、場所に応じたマップのムービークリップ内の障害物だけで衝突判定をとることができます。


RPGでなくてもそうですけれど、画面に映らないもの・さしあたって必要のないものに対する処理やデータを省くことが処理・容量を軽くするポイントです。
市販のRPGでも、画面に映らなくなった部分のデータを破棄して空いたところに必要なデータを読み込むことで、広大なマップを実現しています。

Flash では外部から swf ファイルを読み込めるので、不要になったデータを捨てて違うデータを利用するのは簡単です。
ただ、何でもかんでもデータをすげ替えるだけにすると、かえって階層構造が複雑になって分かりにくく、階層が深いと getBounds や hitTest の計算に時間がかかることもありえます。
察するにかなり複雑な階層になっているようですので、もう少し単純な階層になるように構成を整理してみてはいかがでしょうか。

この回答への補足

お返事有難うございます。
お返事頂いてからずっと眺めたり試したりしていますが、どうも上手くいきません。

hitTestをMAPである外部SWFの障害物MC側から
判定を行っていたのですが、
それでは出来ないようなので、訂正してみましたが
なかなか苦戦中です。

mapは_root.main_mc.map_loading_mc
に外部SWFとして読み込まれるのですが、
それを参照するとかなり重たくなってしまい、まったくダメでした。
mapには1000近くのシンボルが存在し、MAP以外でも
キャラクターやMAPなどすべてが擬似3Dなので、
途中から急に自分の頭が追いつかなくなってしまいました^^;

map側のMCからhitTest判定で跳ね返らせる事は
できるのですが、やはりアドヴァイス頂いた方法では
私の勉強不足のために上手く動作させられませんでした。

たぶん最初から設計し直した方が早いと思っておりますが、それでも衝突判定の問題は頭が痛いです。

ですが大変勉強になりした。
これからも頂いた解説を良く読み返し、
理解できるようになるまで勉強していきたいと思っています。

どうも有難う御座いました。

補足日時:2006/03/31 23:57
    • good
    • 0
この回答へのお礼

補足は一度きりと知らずに補足してしまったようです。
お礼の欄では文字数が少なく、また他にはどこにも書き込めないので
また新しく質問し直す事に致しました。
どうぞ宜しくお願い致します。

お礼日時:2006/04/01 16:29

接触時にある決まった数値を単純に加減するのではなく、障害物の上下・左右の端の座標(X・Y座標の最大値と最小値)を求め、その手前にくるようにプレイヤーの座標を調整してはいかがでしょう。


定数を加減する方法ですと、プレイヤーの移動速度と加減する値の大小によっては障害物の前でプレイヤーが跳ね返って見えたり、障害物を突き抜けていってしまったりすることがあります。


ムービークリップの端の座標を取得するには、MovieClip クラスの getBounds メソッドを使います。
Flash Player 8 からは、似たような機能の getRect というメソッドも登場しました。
getBounds と getRect は、シェイプの線を含んだ大きさで計算するかしないかの違いです。
getRect は Flash Player 8 でパブリッシュしないと使えないこともあり、特に問題がなければ、線を含めた大きさで計算する getBounds で構わないと思います。
( getBounds は Flash Player 5 以降で使えます)


プレイヤーの位置は障害物の端の座標から決めるため、障害物とプレイヤーの属する座標系が違っていると位置がズレてしまいます。
getBounds は基準にする座標系を指定できます。
例えば障害物はステージに、プレイヤーはあるムービークリップの子になっている場合は、getBounds の引数にプレイヤーの”親”の参照を渡してください。障害物の端の座標を、プレイヤーと同じ座標系の数値として扱えるようになります。

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

プレイヤーのムービークリップは基準点が中央にあり、回転等の変形が加わっていないものとします。
すると基本的には、障害物の端からプレイヤーの幅または高さの半分だけずらした位置に移動させると、プレイヤーは障害物の手前で止まることになります。


接触後の処理を行う関数を、引数を1つ受け取るように変更してください。
引数は接触した障害物のムービークリップの参照です。

障害物に接触した時にプレイヤーの位置を修正する部分をスクリプトにしますと、大体、次のようになります。

(↓各行頭に全角のスペースが入っています。コピーする際はご注意ください)


 //障害物との接触後の処理
 //引数 obstacle:接触した障害物ムービークリップの参照

 function obje_hit( obstacle:MovieClip )
 {
  var ply:MovieClip , edge:Object , adjust:Number;


  ply = _root.main_mc.player_mc;
  edge = new Object;

  //障害物の手前で止めるための補正値
  adjust = 2;

  //接触した障害物の上下左右端の座標を取得
  //基準はプレイヤーの親の座標系
  edge = obstacle.getBounds( ply._parent );


  //移動方向に応じてプレイヤーの位置を調整
  //連続で接触しないように、障害物の少し手前で止める
  switch( _global.key_code )
  {
   //上に移動していた時:障害物の下端で停止
   case 'w':
    ply._y = edge.yMax + ply._height / 2 + adjust;
    break;

   //下に移動していた時:障害物の上端で停止
   case 's':
    ply._y = edge.yMin - ply._height / 2 - adjust;
    break;

   //左に移動していた時:障害物の右端で停止
   case 'a':
    ply._x = edge.xMax + ply._width / 2 + adjust;
    break;

   //右に移動していた時:障害物の左端で停止
   case 'd':
    ply._x = edge.xMin - ply._width / 2 - adjust;
    break;

   default:
    break;
  }
 }


理論上は、障害物と接触した時に障害物の端でプレイヤーが止まればいいのですが。
しかし実際には、障害物のぴったり端で止めると障害物とプレイヤーは接触したままで、hitTest では接触している(= true )と判定されます。
この状態で別の方向に移動しようとすると、その移動方向に対するプレイヤーの位置の調整が行われるために、プレイヤーが全くあさってのところに行ってしまいます。


例えば、右に移動中に壁にぶつかった時を想定してみますと。
2D(平面)で視点などが回転しないゲームでは、右に移動中であれば壁の左側から接触しますから、壁の左端でプレイヤーが止まるように位置を変更します。
この状態で仮に”W”キーを押して上に移動させるとすると、普通は壁に沿って上に移動していくはずです。

上記の関数では、上に移動中に壁に接触した時は壁の下側から接触したものと見なし、壁の下端にプレイヤーが来るようにY座標を書き換えています。
ぴったり端で止めると壁とプレイヤーは接触していますから、続けて上に移動させるとこの関数が呼び出され、Y座標が書き換えられます。
つまり、壁に接触したまま上に移動させると、壁に沿って上に移動しなければならないはずがなぜか壁の下にワープしてしまうという、妙な動作になります。


こんなことにならないように、先述の関数内では、障害物のちょうど端ではなく少し手前にプレイヤーを移動させています。
障害物との間に1ピクセルでも隙間があれば、hitTest では接触していないと判定されます。
関数内では、adjust というローカル変数で障害物との隙間の大きさを決めています。

先の例で言いますと、右移動中に壁の左端に接触した時、プレイヤーは壁の左端の2ピクセルほど前で止まります。
この状態では壁とプレイヤーはかなり近づいてはいますが hitTest の判定上は接触しておらず、壁の手前で止める処理は行われません。
壁の左側に接触した後に続けて”W”キーが押された場合は、プレイヤーは壁に沿って上に移動します。

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

hitTest と getBounds メソッドは、ムービークリップの絵に外接する四角形として衝突判定や座標の計算を行っています。
例えば長方形の壁のムービークリップを傾けて配置すると、衝突判定や座標の計算もこの絵に外接する大きな四角形と見なして計算されるために判定領域(当たり)が大きくなり、画面では接触していないのに壁のすぐ傍まで近寄れないという現象が起こります。


市販のゲームでも衝突判定(当たり判定)は頭の痛い問題です。
RPGのマップでは地形との判定は対象が多くなりがちで、細かく正確に判定しようとするとどうしても処理が重く、必要なデータも増えてしまいます。

斜めの判定は、直線と平面の接触として数学的に判断し、より正確に当たりをとる方法も考えられます。
ただ、格闘やアクションのように当たり判定の精度の高さが命のゲームならともかく、RPGの地形とキャラクターの判定ではそこまで精密に判定するのは稀です。
RPGではアイテムの拾得やゲームで言うところのイベントの発生・戦闘シーンへの突入など、ゲームの進行に関する処理はマップの移動の他にもたくさんあり、たかだかマップの移動にそこまでの手間ひまをかける余裕も必要性もないからです。
特に2Dのゲームでは3Dより画面に映る範囲が広く障害物も多くなりますので、一般的には当たり判定の精密さよりも処理と容量の軽さを優先します。

実際に市販のRPGでも、地形との当たり判定はかなり省略されていて大雑把です。
障害物を突き抜けたり、キャラクターの間に極端に大きな隙間が目立つなどの明らかに不自然に見える不具合でなければ、多少の誤差には目をつぶっている作品はよくあります。


傾きの大きい斜めの壁や四角く当たりをとって不都合があるデザインの障害物は何かと面倒なので、最初から作らないようにするのも1つの手です。
ハードの性能が貧弱だった頃のRPGのマップが、いかにも四角いパーツを並べて作ったような単純なデザインになっているのは、当たり判定の処理を簡略化し、また、データを少なく済ませて容量を節約するためだったのではないかと思います。

この回答への補足

お返事有難う御座います。
大変分かりやすく、詳しい解説でとても勉強になりました。
障害物のパスなのですが、マップは画面上に複数存在しており、簡単に書きますと
_root.main_map_mc.main_map_load_mc
_root.shop_map_mc.shop_map_load_mc
_root.sub_map_mc.sub_map_load_mc

など複数に外部SWFを読み込んでいます。
その外部Mapに
_root.main_mc.map_base_mc.obje_mc
_root.main_mc.map_event_mc.event_obje_mc
など複数の障害物となるobjeが存在しております。

このような場合、
  edge = obstacle.getBounds( ply._parent );
だけでは参照しきれなくなるのですが、
どうしたら良いのでしょうか。
いろいろ試してみましたが、外部SWFによるmapは
随時追加されていくものなので、
参照する事が上手くいきませんでした。

お手数をおかけしておりますが、
どうぞ宜しくお願い致します。

補足日時:2006/03/30 01:20
    • good
    • 0

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


おすすめ情報