ThymeはPhunやAlgodooで使用されているスクリプト言語です。
目次
Thyme.cfgの内容
以下の文章は、Phunβ5.25に同梱されている、Thyme.cfgの内容を訳したものです(読みやすさのために、訳者の補足説明も地の文として表示しています)。 |
ThymeはAlgodooとPhunにおいて実装されている独自のスクリプト言語です。
基本となる型は4種類あります。Int型、Float型、Bool型、String型です。これらの型を組み合わせて、配列(リスト)や関数を作成することが可能です。
識別子は演算子 := を用いて宣言します。代入には = を使用してください。識別子は型付けされません。
hoge := 7; // 新しい識別子 'hoge' を初期値3で宣言します。
hoge = [hoge, "hello", true]; // 宣言済みの変数 'hoge' をリストとして再定義します。 このリストはヘテロジニアス(Heterogeneous:異種混合)です。
print hoge(1); // このコードは "hello" を返します。()で配列の要素にアクセスしています。
print hoge([0,2]); // このコードは [7, true] を返します。
isEven := (n)=>{ n%2==0 }; // 関数 "isEven" を宣言します。 1つの引数を受取、もし、その値が偶数ならtrueを返す関数です。
for関数が実装されています。
for関数は、Thymeにおけるシンプルなループ構造です。「再帰の上限」が存在する影響で、約50回以上ループさせると警告・もしくはエラーが出ます。
次のように使われます: for(n, (i)->{ ... }); ここで n は関数を呼ぶ回数です。 i は 0, 1, ..., n-2, n-1 受け取ります。
例:
for(4, (n)=>{print ((n+1) + " bottles of beer on the wall.")})
出力:
1 bottles of beer on the wall.
2 bottles of beer on the wall.
3 bottles of beer on the wall.
4 bottles of beer on the wall.
for関数は以下のように実装されています。
for = (n, what)=>{
n < 0 ? true : {
for(n - 1, what);
what(n-1)
}
};
他にも関数の定義例があります。
inclusive_range = (min, max)=>{min > max ? [] : {[min] ++ inclusive_range(min + 1, max)}};
infix 2 left: _ .. _ => inclusive_range; // Usage: 1..5 == [1,2,3,4,5]
infix は 演算子を定義します。これを定義しておくと、1..5 が [1,2,3,4,5]と同値になります。
infix 2 left は、結合の優先順位が2で、左結合という意味です。数が大きいほど優先順位が高く、演算子は強く結合します。
<- Thyme.cfgの内容ここまで。
Scene.my.~
シーンデータで使う独自の変数には
Scene.my.test := 1;
という具合に、先頭にScene.my.を付けて宣言します。
使用する際も、Scene.my.を付けます。
変数や関数を宣言する際に、Scene.my.を付けず、
test := 1;
などと定義してしまうと、testの定義がシーンファイルには保存されず、config.cfgに保存されてしまいます。
これには欠点が2つあります。
(欠点1)... 他人にシーンデータを渡しても上手く動作しない。
シーンデータに宣言した変数の情報がないため、Phunがシーンファイルを上手く解釈することができません。
(欠点2)... 管理が面倒。
config.cfgはPhunを起動する度に読み込まれる設定ファイルなので、config.cfgファイルを削除するかconfig.cfgを編集して該当箇所を取り除かない限り、宣言した変数の定義が残り続けてしまいます。逆に、config.cfgを消してしまうと、たとえシーンデータが残っていても、変数を宣言しなおす必要があります。
また、scene1.phz というシーンデータとscene2.phzで、同じ変数 test を使用していると、scene1.phzでtestの変数の値を迂闊に変更できないということになります。scene2.phzの挙動に影響するためです。
特に(欠点1)は忘れてはならない欠点です。
これらの欠点を理解し、通常は、シーンの変数にScene.my.~という識別子を使用するようにしましょう。
関数の宣言
関数は、
関数名 = (引数 [,引数2, 引数3, ...]) => {処理内容}
という形式で定義することができます。
絶対値を返す関数:
Scene.my.abs = (x) => {x > 0 ? x : -x};
使用例:
Scene.my.abs(-4)
出力
4
値を整数に丸める関数(Int型に型変換を行うわけではありません)
Scene.my.floor = (x) => {x >= 0 ? x - math.mod(x, 1) : (math.mod(x, 1) == 0 ? x : x - math.mod(x, 1) - 1)};
使用例:
Scene.my.floor(3.14)
出力
3
距離を返す関数:
Scene.my.dist = (a, b)=>{((a(0) - b(0)) ^ 2 + (a(1) - b(1)) ^ 2)^0.5};
使用例:
Scene.my.dist([0, 0], [3, 4])
出力:
5
rand関数の実装例:
Scene.my.next_rand = 1;
Scene.my.rand = () => {Scene.my.next_rand = Scene.my.next_rand * 1103515245 + 12345; (Scene.my.next_rand / 65536) % 32768;};
Scene.my.srand = (rand_seed) => {Scene.my.next_rand = Scene.my.rand_seed};
(このrand関数は、RAND_MAX := 32767 です。)
使用例:
Scene.my.rand;
Scene.my.rand;
出力
16838
-27009
衝突時に呼び出す関数の宣言(onCollide)
図形の衝突時に関数を呼び出すことも可能です。onCollideという属性を利用します。
onCollide = (e)=>{処理したい内容}
という記述方法で、この処理内容の中では、衝突された図形および衝突した図形の属性の値を、
e.this.collideSet や e.other.color
で手に入れることができます。thisはスクリプトの書かれている図形、otherは衝突した図形です。
その他、e.posで衝突した位置を、e.normalで衝突した面の向きを得ることができます。
例えば、
Scene.addBox{
onCollide = (e)=>{Scene.addCircle{ radius := 0.1; collideSet := e.this.collideSet; pos := e.pos}};
}
という図形(この場合はボックス)をPhunで作成すると、衝突する度に、衝突した位置に半径が0.1メートルで衝突グループが図形と同じ円(まる)が出る図形の完成です。※このスクリプトのままだと、物体が出続けてしまいます。
衝突した相手の物質のタイプを得る
公式フォーラムより。Iggyhopper氏の投稿内容です。 |
(e.other + "") で衝突した物体のタイプを判断することができます。
四角形→box
まる→circle
平面→plane
ポリゴン→polygon
使用例
(e) => { e.this.text = e.other + "" }
使用例2
(e) => { e.other + "" == "box" ? {e.this.color = [0.5, 1, 0.5, 1]} : {e.this.color = [1, 1, 0.5, 1]} }
e.normalの解説
e.normalは衝突面の角度に対応したcosとsinを組み合わせた配列である。
以下のコードを利用することで角度(ラジアン)に変換することができる。
Scene.my.atan2 = (y, x)=>{ x == 0 ? { y > 0 ? {math.pi/2} : {-math.pi/2}} : { x > 0 ? {math.atan(y/x)} : { y > 0 ? {math.atan(y/x) + math.pi} : {math.atan(y/x) - math.pi}}}}
Scene.my.atan2(e.normal(1), e.normal(0))
リファレンス
Gradyが使用できるコマンドをリストアップしてくれました(英語での説明付き)。
その他リファレンス
最終更新:2012年04月07日 10:38