日本でハリウッドVFXを制作! 「経産省アイディアボックス」 結果:  
●まとめエントリはこちら ●FAQ ●お問い合わせは左のメールフォームから

2010年10月28日木曜日

迷路作成を簡単にするためのMelスクリプト


仕事で迷路を作ることになったのですが、ちょうど良い機会と思いMelで作ってみることにしました。
といっても迷路を自動生成するアルゴリズムなど実装できる実力はないので、迷路を作る作業を助けてくれるヘルパーです。
(機能)
●支柱と壁を自動作成
●壁をランダムに配置。
●壁を全体に配置する機能
●後から自由に壁を付け足せる。

(入力値)
●高さ
●壁の幅
●迷路全体のサイズ(柱の数で指定)
●壁をX方向のみ配置
●壁をXとZ方向に配置
●上記においてランダムのモードが選択できる。
(制限)
●壁の厚みは入力不可。
●グリッド数で迷路のサイズを指定不可。

(説明)
[Place Pillars]というボタンをクリックすると指定したサイズ、方法で自動的に柱と壁を配置します。
壁がほしいところへ追加するには、柱を選択(複数選択可)し、[-Zwall (North)] [+Zwall (South)][-Xwall (left)][+Xwall (right)]のいずれかをクリックします。



結果的には一日かけてもまだエラーがあり、自宅作業で朝4時半までかけて完成させました。
結論から言うと、ここまで時間をかけただけの意味があるのかというと、個人的にはいろいろと学べましたが、企業的にはほとんどないかもしれません。
ただ、これから先迷路が変更になった場合は、簡単に作成できるという潜在的メリットはあります。
(今回勉強になったこと)
いろいろと新しいことを勉強しました。
1)move コマンドでpivotを移動する方法

2)同(move)コマンドの中で変数と文字列を組み合わせるために( )を使う方法
例) move 0 -2.5 0 ($wall[0]+".scalePivot") ($wall[0]+".rotatePivot") ;

3)If文で二つ以上の条件式を論理演算する方法

4)四捨五入のやり方(ランダムに1か0の値を得る為に使用、0.5を加算するのがポイント)
 $rand = floor(rand(0,1)+0.5);

5)$distが8のとき、float $wAdjust = ($dist+1)/2 では4になってしまう、これを補正するにはいくつかの方法がある。自分で思いついたのは、float $wAdjust = ($dist+1)*0.5;
Twitterで質問した所いくつかの方法があることを教えて頂いた。
(助けてくださった方々、大変ありがとうございました。)
質問用につくったのが float $int =(8+1)/2; という混乱を招きやすい奇妙な変数名を使っていた。
 そのためここでは変数名は$numと変更させて頂き紹介します。
基本的には右辺では整数計算がされ、代入時に浮動小数点になるらしく、Pythonなど他の言語でも同様のことが起きるということらしい。解決するには以下のようにする。
  float $num =(8+1)/2.0;
float $num =(8.0+1)/2;
  float $num =(float)(8+1)/2;
  float $num =float(8+1)/2;
 float $num =(8+1)/float(2);
このいずれかの方法で4.5が返ってくる。 ちなみにfloat()もしくは(float)を使う方法を「型キャスト」と呼ぶらしく、元々C言語で使われていた物らしい。

6)Xformでベクトル値から値を使うには
xform -ws -t $position.x $position.y $position.z -2.5; ではエラーになる。
xform -ws -t ($position.x) ($position.y) ($position.z -2.5); としなくてはいけない。

7)ラジオボタンを使ってみた。すっかり忘れていたが-valueフラグはないので、どのボタンを選択しているかは、-selectを使用する。
int $wWall = `radioButtonGrp -q -select withWall`;
8)トグルボタンも使ってみた。こちらは-valueでOK

9)出来るだけグローバル変数を使わないようにするために、それぞれのプロシージャー内でコントロールからの値を取得するようにした。

他に、できた柱と壁をグループ化したかったのだが、グローバル変数を使う必要もあり、今回は省略した。

{
if(`window -exists mazeBuildingHelper`)
deleteUI mazeBuildingHelper;
window -title "Maze Buliding Helper" -widthHeight 500 700 mazeBuildingHelper;
columnLayout;
//set distance betweern pillars
text -label "Disntace between pillars. (ie: 4 :Pillar is placed at each 5 unit.)";
intFieldGrp -numberOfFields 1 -label "distance" -value1 4 -extraLabel "Unit" -enable1 true distanceNum;
//set hight of the wall.
text -label "Hight of the wall. ";
intFieldGrp -numberOfFields 1 -label "hight" -value1 5 -extraLabel "Unit" hightNum;
//size of the Maze
text -label "Entire size of the Maze. (Number of pillars) ";
intFieldGrp -numberOfFields 2 -label "sizeX (pillars)" -value1 10 -value2 10 -extraLabel "sizeZ (pillars)" sizeNum;
//wall with pillars.
radioButtonGrp -numberOfRadioButtons 3 -label1 "Pillars only" -label2 "Pillars + wallX" -label3 "Pillars +WallX,Z" -select 3 withWall ;
// checkBox -label "with Wall" -value false withWall;
checkBox -label "randomize" -value true randomize;
// button
button -label "Place Pillars" -command "placePillars";
// individual wall placement.
text -label "----------------------------------------------------";
text -label "place a wall for pillar";
button -label "-Zwall (north)" -command "zWall1" zBtn1;
button -label "+Zwall (south)" -command "zWall2" zBtn2;
text -label" ";
button -label "-Xwall (left)" -command "xWall1" xBtn1;
button -label "+Xwall (right)" -command "xWall2" xBtn2;
text -label " ";
showWindow mazeBuildingHelper;
global proc zWall1() {
$name =`ls -sl`;
int $size = `size($name)`;
for($k=0; $k<$size; $k++) {
int $dist =`intFieldGrp -q -value1 distanceNum`;
int $hight =`intFieldGrp -q -value1 hightNum`;
float $adjust =($dist+1)/2.0;
select $name[$k];
vector $position =`xform -q -ws -t`;
$wall = `polyCube -w $dist -h $hight -d 1 -n wall`;
move 0 -2.5 0 ($wall[0]+".scalePivot") ($wall[0]+".rotatePivot");
rotate -r -y 90;
xform -ws -t ($position.x) ($position.y) ($position.z -$adjust);
select -r $name;
};
}
global proc zWall2() {
$name =`ls -sl`;
int $size = `size($name)`;
for($k=0; $k<$size; $k++) {
int $dist =`intFieldGrp -q -value1 distanceNum`;
int $hight =`intFieldGrp -q -value1 hightNum`;
float $adjust =($dist+1)/2.0;
select $name[$k];
vector $position =`xform -q -ws -t` ;
$wall = `polyCube -w $dist -h $hight -d 1 -n wall`;
move 0 -2.5 0 ($wall[0]+".scalePivot") ($wall[0]+".rotatePivot");
rotate -r -y 90;
xform -ws -t ($position.x) ($position.y) ($position.z +$adjust);
select -r $name;
};
}
global proc xWall1() {
$name =`ls -sl`;
int $size = `size($name)`;
for($k=0; $k<$size; $k++) {
int $dist =`intFieldGrp -q -value1 distanceNum`;
int $hight =`intFieldGrp -q -value1 hightNum`;
float $adjust =($dist+1)/2.0;
select $name[$k];
vector $position =`xform -q -ws -t`;
$wall = `polyCube -w $dist -h $hight -d 1 -n wall`;
move 0 -2.5 0 ($wall[0]+".scalePivot") ($wall[0]+".rotatePivot");
xform -ws -t ($position.x-$adjust) ($position.y) ($position.z);
select -r $name;
};
}
global proc xWall2() {
$name =`ls -sl`;
int $size = `size($name)`;
for($k=0; $k<$size; $k++) {
int $dist =`intFieldGrp -q -value1 distanceNum`;
int $hight =`intFieldGrp -q -value1 hightNum`;
float $adjust =($dist+1)/2.0;
select $name[$k];
vector $position =`xform -q -ws -t`;
$wall = `polyCube -w $dist -h $hight -d 1 -n wall`;
move 0 -2.5 0 ($wall[0]+".scalePivot") ($wall[0]+".rotatePivot");
xform -ws -t ($position.x+$adjust) ($position.y) ($position.z);
select $name;
};
}
//-------global proc "generate maze"-----------
global proc placePillars() {
int $dist =`intFieldGrp -q -value1 distanceNum`;
int $hight =`intFieldGrp -q -value1 hightNum`;
int $sizeX = `intFieldGrp -q -value1 sizeNum`;
int $sizeZ = `intFieldGrp -q -value2 sizeNum`;
int $wWall = `radioButtonGrp -q -select withWall`;
int $randOn = `checkBox -q -v randomize`;
for ($j=0; $j<$sizeZ; $j++) {
float $placeZ = $j*($dist+1);
float $adjust =($dist+1)/2.0;
float $wallPlaceZ = $placeZ-$adjust;
for ($i=0; $i<$sizeX; $i++) {
float $placeX = $i*($dist+1);
float $wallPlaceX = $placeX+$adjust;
//create a Pillar
$pillar = `polyCube -w 1 -h $hight -d 1 -n pillar` ;
move 0 -2.5 0 ($pillar[0]+".scalePivot") ($pillar[0]+".rotatePivot") ;
move -x $placeX -y 2.5 -z $placeZ;
select -cl;
//create a wall_X
if ((($wWall == 2)&&($i <$sizeX-1))||(($wWall == 3)&&($i <$sizeX-1))) {
$rand = floor(rand(0,1)+0.5);
if (($randOn == true)&&($rand ==1)){
$wall = `polyCube -w $dist -h $hight -d 1 -n wall` ;
move 0 -2.5 0 ($wall[0]+".scalePivot") ($wall[0]+".rotatePivot") ;
move -x $wallPlaceX -y 2.5 -z $placeZ;
select -cl;
} else if ($randOn == false) {
$wall = `polyCube -w $dist -h $hight -d 1 -n wall` ;
move 0 -2.5 0 ($wall[0]+".scalePivot") ($wall[0]+".rotatePivot") ;
move -x $wallPlaceX -y 2.5 -z $placeZ;
select -cl;
};
}; //end "if" Wall_X
//create a wall_Z
if (($wWall == 3)&&($j > 0)) {
$rand = floor(rand(0,1)+0.5);
if (($randOn == true)&&($rand ==1)){
// $wallPlaceX= $wallPlaceX -$adjust;
$wall = `polyCube -w $dist -h $hight -d 1 -n wall` ;
move 0 -2.5 0 ($wall[0]+".scalePivot") ($wall[0]+".rotatePivot") ;
rotate -r -y 90;
move -x ($wallPlaceX-$adjust) -y 2.5 -z $wallPlaceZ;
select -cl;
} else if ($randOn == false) {
$wall2 = `polyCube -w $dist -h $hight -d 1 -n wall` ;
move 0 -2.5 0 ($wall2[0]+".scalePivot") ($wall2[0]+".rotatePivot") ;
rotate -r -y 90;
move -x ($wallPlaceX-$adjust) -y 2.5 -z $wallPlaceZ;
select -cl;
};
}; //end "if" Wall_Z
}; //end "for" loop PlaceX
}; //end "for" loop PlaceZ
} // end global proc placePillars()
}

0 件のコメント:

コメントを投稿