Thymeは初心者やプログラム経験のない方にとってはハードルが高い。思いつきではあるが、ここにThyme講座を書きなぐっていきたいと思う。
尚思いつきかつ、筆者も独学にちかい部分があるため、不明瞭な部分や間違い等があると予想される。
そのような部分を発見した場合、コメントにて指摘いただけるとありがたい。
まずスクリプトがどのようなものなのか、見ていただこう。
物質のテキスト文章部分にシミュレーション開始からの経過時間を表示させるスクリプト
text = { "" + sim.time };
常に物質の色を変え続けるスクリプト
color = { [ sim.time % 1.0 , sim.time * 0.5 % 1.0 , sim.time * 0.3 % 1.0 , 1.0 ] };
このような1処理分の塊を「式」という。
式1つは「○○○ = ○○○」の形をとる。
ただし、スクリプトメニューをよく見ると「text =」や「color =」は既に記述されている。
このため、1つ目を例を実際に使用したい場合は「{ "" + sim.time }」を「text =」項目の内容部分に記述すれば良い。
尚、各例文の最後についてある「;」は「式がここで終わり」という意味の記号である
1つの式のみをスクリプトメニューに記載した場合、決定した時に「;」が消えてしまうが、これはPhunの仕様である。
どうやら、「式の数にかかわらず、最後の;は省略する」というルールが存在しているようである。
この解説においては、式の数にかかわらず;を表記すると、断りを入れておく。
Thymeスクリプトを実行出来る場所は2箇所ある。
スクリプト言語Thymeのページには、onCollide属性内以外への記述については特に述べられていないが
書式さえ守ればどの属性内にも直接スクリプトを記述できる。
onCollide以外の属性へ書き込む場合の注意点としては以下の2つ。
式に用いる数値や文字のことを総称して値(あたい)と言う。値には定数と変数の2種がある。
| 行番号 | 内容 | 説明 |
| 1行目 | x := 3; | xという変数を内容「 3 」で作成 |
| 2行目 | x = x + 4 - 5; | xに『 x + 4 - 5 』の計算結果を入れる |
| 3行目 | y := x + x; | yという変数を内容『 x + x 』で作成 |
| 4行目 | y = x + y; | yに『 x + y 』の計算結果を入れる |
1行目
x := 3;
「xを3という内容で作成します」という意味の式。
変数を始めに作成する演算子「:=」を用いている。
変数には必ず初期値が必要であり、この場合は「3」である。
2行目
x = x + 4 - 5;
「xに『 x + 4 - 5 』の計算結果を入れる」という意味の式。
変数の値を変更する演算子「=」を用いている。
xの値は3であるため『x+4-5』は2となり、xの値が2に変更される。
3行目
y := x + x;
「yという変数を内容『 x + x 』で作成します」という意味の式。
初期値に「すでに作成済みである変数を用いた計算式」を使用しても問題ない。
つまりこの式は「 y := 2 + 2; 」と同義であり、yの初期値は4になる。
4行目
y = x + y;
「yに『 x + y 』の計算結果を入れる」という意味の式。
xは2でありyは4であるため、この式は「y= 2 + 4;」と同義である。
結果としてyの値は6になる。
Scene.my.x := 3; Scene.my.x = Scene.my.x + 4 - 5; Scene.my.y := Scene.my.x + Scene.my.x; Scene.my.y = Scene.my.x + Scene.my.y;
変数の種類として「配列」がある。
変数は1つに対して1つの値しか持てないが、配列は複数個の値を持つことが出来る。
イメージとしては「1つの名前を共有する複数の箱があり、それは番号で区別される」といったものである。
実際に配列を使用している例を以下に示す。
Scene.my.x := [ 1 , 5 , 10 , 999 , 7 ]; Scene.my.y := Scene.my.x(0); Scene.my.z := Scene.my.x(2) + Scene.my.x(3);
順を追って解説していこう。
| scene.my.x(0) | scene.my.x(1) | scene.my.x(2) | scene.my.x(3) | scene.my.x(4) |
| 1 | 5 | 10 | 999 | 7 |
尚、配列の内容を書き換える際には注意が必要である。
scene.my.x := [ 1 , 2 , 3 ]; scene.my.x(2) = 99;
上記のスクリプトは「scene.my.x の2番目の内容を99に書き換える」ことを意図したものであるが
これはその意図通りには動かない。
配列の中身を部分的に書き換える際には、非常に面倒くさい式になるが
scene.my.x := [ 1 , 2 , 3 ]; scene.my.x = [ scene.my.x(0) , scene.my.x(1) , 99 ];
と、このように書くしかない。
面倒な話だが、これはどうしても避けて通れない
スクリプトで扱う値は4つに分類されている。 分類のされ方は以下のとおり
| 型名 | 内容 | 例 |
| 文字列型 | 1文字以上の文字列 | "" "A" "B" "AABB" "あいうえお" |
| 浮動小数点型 | 小数点以下を含む数字 | 0.0 1.5 1.0001 10000.0 |
| 整数型 | 小数点以下がない数字 | 0 1 100 10000 |
| ブール型 | 正か偽を表現 | true false |
以下に物質のスクリプトメニュー内の各項目について型を示す。
| 項目名 | データ型 |
| airFrictionrMult = | 浮動小数点 |
| attraction = | 浮動小数点 |
| collideSet = | 整数 |
| collideWater = | ブール |
| color = | 浮動小数点(配列、要素数4) |
| controllerAcc = | 浮動小数点 |
| controllerInvertX = | ブール |
| controllerInvertY = | ブール |
| controllerReverseXY = | ブール |
| density = | 浮動小数点 |
| drawBorder = | ブール |
| friction = | 浮動小数点 |
| heteroCollide = | ブール |
| immortal = | ブール |
| killer = | ブール |
| onCollide = | 関数 |
| opaqueBorders = | ブール |
| restitution = | 浮動小数点 |
| ruler = | ブール |
| text = | 文字列 |
| textColor = | 浮動小数点(配列、要素数4) |
| textScale | 浮動小数点 |
| texture | 文字列 |
| textureMatrix | 浮動小数点(配列、要素数9) |
式には細かな処理の順番がある。
たとえば「 x = 1 + 2 + 3 + 4 + 5; 」という式は
「 x = (((( 1 + 2) + 3 ) + 4 ) + 5 ); 」この括弧のもっとも内側から順に処理される。
型にも優先順位があり、以下のようになっている。
| 式 | xに入る値 | 結果のデータ型 |
| x = 1 + 2 + 3; | 6 | 整数 |
| x = 1 + 2 + 3.0; | 6.0 | 浮動小数点 |
| 式 | xに入る値 | 結果のデータ型 |
| x = 1 + "A"; | "1A" | 文字列 |
| x = 1.0 + "A"; | "1A" | 文字列 |
| x = "A" + 1.0; | "A1" | 文字列 |
| 式 | xに入る値 | 結果のデータ型 |
| x = 1 + 2 + 3 + "A"; | "6A" | 文字列 |
| x = 1 + "A" + 2 + 3; | "1A23" | 文字列 |
| 式 | xに入る値 | 結果のデータ型 |
| x = 1 + 2.2 + "A" + "B"; | "3.2AB" | 文字列 |
| x = 1 + 2.2 + "A" + true; | "3.2Atrue" | 文字列 |
| 式 | xに入る値 | 結果のデータ型 |
| x = 1 + true; | (演算不可) | - |
| x = 1 + "" + true; | "1ture" | 文字列 |
| x = true + 1.0; | (演算不可) | - |
| x = true + "" + 1.0; | "true1" | 文字列 |
| x = true + true + "" + 1 | (演算不可) | - |
| x = true + "" + true + 1 | "truetrue1" | 文字列 |
演算に使用する記号を総称して「演算子」と呼ぶ。
| 演算子 | 意味 | 例文 | 演算結果 |
| + | 加算 | 3 + 4 | 7 |
| 3 + 4.0 | 7.0 | ||
| - | 減算 | 5 - 2 | 3 |
| 5 - 2.0 | 3.0 | ||
| * | 乗算 | 4 * 5 | 20 |
| 4 * 5.0 | 20.0 | ||
| / | 除算 | 8 / 4 | 2 |
| 8 / 5 | 1 | ||
| 8 / 5.0 | 1.6 | ||
| % | 剰余 | 8 % 5 | 3 |
| 8 % 5.0 | 3.0 | ||
| ^ | 累乗 | 2 ^ 3 | 8 |
| 10 ^ 3 | 1000 |
| 演算子 | 意味 | 例文 | 演算結果 |
| == | 等しい | 1 == 1 | true |
| 1 == 2 | false | ||
| != | 等しくない | 1 != 1 | false |
| 1 != 2 | true | ||
| > | 大なり | 1 > 2 | false |
| 2 > 1 | true | ||
| < | 小なり | 1 < 2 | true |
| 2 < 1 | false | ||
| >= | 以上 | 1 >= 1 | true |
| 1 >= 2 | false | ||
| <= | 以下 | 1 <= 1 | true |
| 2 <= 1 | false |
| 演算子 | 意味 | 例文 | 演算結果 |
| + | 加算 | "ABC" + "DE" | "ABCDE" |
| == | 等しい | "AB" == "AB" | true |
| != | 等しくない | "AB" != "ab" | true |
細かい話は抜きにして「ブール型にのみ用いられる演算でありその結果もすべてブール型である」と覚えておけば良い。
true=真 か false=偽 を判断する際に用いる。
以下の表が、その演算内容のすべてである。
| 演算子 | 意味 | 例文 | 演算結果 |
| && | 論理積(and) | true && true | true |
| true && false | false | ||
| false && true | false | ||
| false && false | false | ||
| || | 論理和(or) | true || true | true |
| true || false | true | ||
| false || true | true | ||
| false||false | false | ||
| ! | 否定(not) | !true | false |
| !false | true |
| 演算子 | 意味 | 例文 | 演算結果 |
| + | 加算 | [1,2,3] + [1,3,5] | [2,5,8] |
| - | 減算 | [4,5,6] - [1,2,3] | [3,3,3] |
| * | 乗算 | [1,2,3] * [2,3,4] | [2,6,12] |
| / | 除算 | [12,12,12] / [2,3,4] | [6,4,3] |
| && | 論理積 | [true,true,false] && [true,false,true] | [true,false,false] |
| || | 論理和 | [true,true,false]||[true,false,false] | [true,true,false] |
| 演算子 | 意味 | 例文 | 演算結果 |
| * | 乗算 | 2 * [1,2,3] | [2,4,6] |
| * | [2,3,4] * 2 | [4,6,8] | |
| / | 除算 | 2 / [1,2,3] | (error) |
| / | [2,4,8] / 2 | [1,2,3] | |
| == | 等しい | [1,2,3] == [1,2,3] | true |
| != | 等しくない | [1,2,3] != [1,2,3] | false |
| ++ | 結合 | [1,2,3] ++ [4,5,6] | [1,2,3,4,5,6] |
スクリプト内で使用できる変数は「そのスクリプトがどこに書かれているものか」によって変わる。
それらを3つに分類し、それぞれについて使用可能な変数をまとめたものが以下。
| 表記 | 意味 |
| decimal | 十進数 |
| integer | 整数 |
| value | 値 |
| positive | 正の(0より大きい) |
| true or false | 真か偽 |
| function | 関数(※後述参照) |
| array of | 配列である |
| string | 文字列 |
| constant | 定数 |
| sub-group | 内部に変数や関数を持つグループ名 |
| Read only | 読み取りのみ可能(値を変更不可) |
これ抜きには複雑なThymeスクリプトなど組めない、と言っても過言ではない。
ある変数Aがあり、Aが1ならば処理1を実行し、Aが2なら処理2を実行する。端的に言うとそういうことである。
何はともあれ実例を見ていただきたい
scene.my.x := 2; scene.my.y := ( scene.my.x == 3 )?( scene.my.x + 3 ):( scene.my.x + 10 );
1行目は特に解説の必要はないと思われる。
2行目はscene.my.y変数を作成しているのだが、その中身に条件分岐を用いている。
2行目の「:=」以降の部分が条件分岐構造になっており
「 『scene.my.x==3』が真ならば『scene.my.x + 3』、そうでなければ『scene.my.x + 10』 」という意味である。
この場合 scene.my.x は 2 なので、『scene.my.x + 10』が選ばれ、scene.my.yの値は12となる。
先ほどの例で条件分岐のために用いた演算子を「三項演算子」と言う。
使用方法は以下のとおりである。
判定条件 ? 条件が真の場合の処理内容 : 条件が偽の場合の処理内容
(scene.my.x == 2) ? scene.my.y = 5; scene.my.z = 3; : scene.my.y = 1; scene.my.z = 10; ; (×エラー)
(scene.my.x == 2) ?{ scene.my.y = 5; scene.my.z = 3 }:{ scene.my.y = 1; scene.my.z = 10 }; (○正常動作)
onCollide = (e) =>{ e.this.density = (( e.other.collideSet == 2 )&&( e.other.density == 100.0 ))?{ 50.0 }:{ 2.0 }; }
条件分岐部分は「『衝突相手の衝突判定がBのみであり、かつ密度が100.0』ならば 50.0 、違うならば 2.0 」という意味である。
さて、だいぶ小難しい話になるところなので、腰を落ち着けてじっくりと読んでいただきたい。
「関数」といきなり言っても通じないであろうから、まずPhun抜きにして以下の事例をごらんいただこう。
「引数(ひきすう)」とは「Aを頼む際には大きな書類2枚と小さな書類1枚を渡すよ」といった場合の、その書類である。
関数を実行する際には「0個以上の引数」が必要である。これは関数を作成する際に取り決める。
「戻り値(もどりち)」とは「仕事が終わったら、その完成品を渡してね」といった場合の、その完成品である。
関数は「必ず1つの戻り値」を持つ。
それでは、実際に関数を作成し、使用する例を見てみよう
Scene.my.func1 := (var) => { var % 2 == 0 ? true : false };
Scene.my.x = Scene.my.func1(2);
1行目で関数を製作し、2行目で使用している。
関数の内容としては「引数が偶数ならばtrue、奇数ならfalseを戻り値とする」である。
つまりは偶数か奇数かを判定するための関数だ。
関数の書式は以下のとおりである
関数名 = ( 引数名 ) => { 処理内容 }
◇関数
scene.my.triangle := ( width , height ) => { width * height * 0.5 };
◇使用例
scene.my.x = scene.my.triangle( 3.0 , 5.0 );
scene.my.x には 3.0 * 5.0 * 0.5 の演算結果 7.5 が入る。
◇関数
scene.my.blink := () => { sim.time % 1.0 >= 0.5 ? true : false };
◇使用例
onCollide = (e) =>{
text = { "" + ( scene.my.blink ? "Yes" : "No" ) };
}
書かれた物質のtext属性値が0.5秒ごとに "Yes" と "No" 交互に変わる。
あらかじめPhunのシステム上に作成されていて、使用可能な関数はいくつもある。
かなりの量であるが、実際に使用する可能性のあるものは限られる。
使用頻度の高い関数をいくつか書き留めておこう。
| 関数名 | 引数 | 戻り値 |
| math.asin(x) | 浮動小数点型 | 逆三角関数 arcsin(x)の値 |
| math.acos(x) | 浮動小数点型 | 逆三角関数 arccos(x)の値 |
| math.atan(x) | 浮動小数点型 | 逆三角関数 arctan(x)の値 |
| math.sin(x) | 浮動小数点型、単位は[rad] | 三角関数 sin(x)の値 |
| math.cos(x) | 浮動小数点型、単位は[rad] | 三角関数 cos(x)の値 |
| math.tan(x) | 浮動小数点型、単位は[rad] | 三角関数 tan(x)の値 |
| 関数名 | 引数 | 戻り値 |
| scene.addBox{ x } | (後述) | "box" |
| scene.addCircle{ x } | (後述) | "circle" |
| scene.addFixjoint{ x } | (後述) | "fixjoint" |
| scene.addHinge{ x } | (後述) | "hinge" |
| scene.addPen{ x } | (後述) | "pen" |
| scene.addPlane{ x } | (後述) | "plane" |
| scene.addPolygon{ x } | (後述) | "polygon" |
| scene.addSpring{ x } | (後述) | "spring" |
| scene.addWater{ x } | (後述) | "water" |
| scene.EraseWater | (なし) | (なし) |
scene.addBox{ pos = [ 10.0 , 25.5 ]; size = [ 15.0 , 20.0 ]; density = 10.0 };
scene.addBox{ pos = [ 0.0 , 0.0 ]; size = [ 6.0 , 2.0 ]; geomID = 100; };
scene.addCircle{ pos = [ 2.0 , -0.5 ]; radius = 0.8; geomID = 101 };
scene.addCircle{ pos = [-2.0 , -0.5 ]; radius = 0.8; geomID = 102 };
scene.addHinge{ geom0 = 100; geom0pos = [ 2.0 , -0.5 ]; geom1 = 101; geom1pos = [ 0.0 , 0.0 ] };
scene.addHinge{ geom0 = 100; geom0pos = [-2.0 , -0.5 ]; geom1 = 102; geom1pos = [ 0.0 , 0.0 ] };
※追記 Thymeで物体を発生させる場合、速度と角速度も指定できる。両方共に「じょうほう」メニューで表示されている単位(速度 m/s, 角速度 rad/s)で指定する。
scene.addBox({vel := [20.0, 10.0]; angVel := 30});
配列の解説部分で作った配列のような1列しかない配列は、1次元配列と言う。
1次元という呼び名があるからには、2次元配列ももちろん存在する。
作成の仕方と使用の仕方を以下に示す。
scene.my.x := [ [1,2,3] , [4,5,6] ];
これが2行3列の2次元配列である。
配列の0番目の値として「要素3の配列」が入っており、1番目の値にも「要素3の配列」が入っている。
これを使用する際には以下のように書く
scene.my.y := scene.my.x(0)(1);
scene.my.xの0行目の1番目を指定している。
この時scene.my.yに入る値は「2」である。
scene.my.xの内容を視覚的にわかりやすく表にまとめると、以下のようになる。
| \ | B=0 | B=1 | B=2 |
| A=0 | 1 | 2 | 3 |
| A=1 | 4 | 5 | 6 |
ちなみに、2次元配列を作る際に、列の値は必ずしも全て揃える必要はない。
更に、データ型はそれぞれの要素ごとに記録されるため、揃える必要はない。(これは1次元配列でも同じく)
つまり、以下のような配列も生成可能である。
scene.my.x := [ [ 11 , 12 , 13 ],[ "welcome" , 2 , "phun"],[ 21 , 22 , 23 , 24 , 25 ] ]; scene.my.y := [ [ "one" , 2 , "three" ],"welcome",[ true , "or" , false ],[ "Let's" , "phun" ] ];
それぞれ内容は以下のようになる。
| \ | B=0 | B=1 | B=2 | B=3 | B=4 |
| A=0 | 11 | 12 | 13 | (error) | (error) |
| A=1 | "welcome" | 2 | "phun" | (error) | (error) |
| A=2 | 21 | 22 | 23 | 24 | 25 |
| \ | B=0 | B=1 | B=2 |
| A=0 | "one" | 2 | "three" |
| A=1 | (error) | (error) | (error) |
| A=2 | true | "or" | false |
| A=3 | "Let's" | "phun" | error |
講座の書き出し時点で「ThymeスクリプトをonCollide属性以外にも書き込み可能だ」と書きましたが間違いであることが分かりました。
書いたそのときは動きはすれど、Phunを終了させたりファイルに保存する際に、onCollide以外の属性に書いたスクリプトは保存されない
ことが多いという事実が判明しました。
紛らわしい文章を載せてしまい、まことに申し訳ありませんでした。(現在は訂正済み) 2010/08/23 08:08 作成主