ドア用スクリプト
「ステート(状態)」、「イベント(きっかけ)」、「反応」の三つがあります。
ステート「open」とステート「close」です。
イベントは、素直に「タッチ」にします。
なお、defaultステートは必ず書かなければいけないステートですが、あくまでも「初期状態」ということで考えて、スクリプトの初期設定を行うステートにします。
スクリプトが動きだした後は、ドアを「閉じた状態」にしたいので、defaultステートの処理は、ステート「default」が「開始されたとき」には「初期設定を行い、閉じた状態にする」ようにします。
肝心のドアの回転については何もまだ出来ていませんので、これだけでは見た目何も起こらないスクリプトです。
オブジェクトを回転させるための命令は、
llSetRot(rotation rot);
です。
ドアが「閉じているときの角度」と「開いているときの角度」をそれぞれ数字で指定してもいいのですが、それですとドアを作るたびに、いちいち角度を調べてスクリプトの数字を直さなければなりません。
例えば西向きのドアと、南向きのドアでは、「閉じているとき」「開いているとき」の角度が異なりますよね。
どちらのドアでも同じスクリプトが動くようにしたいところです。
そこで、
「初期状態のドアの角度」=「閉じているときの角度」
として、
「開いたときの角度」は「閉じているときの角度+90度」としたらどうでしょうか。
これならば、ドアが西向きであろうが、南向きであろうが、開いたときには+90度されるだけです。
これを実現するには以下のような処理を追加すれば良いでしょう。
・defaultステートのstate_entry()イベントの中で「初期状態の角度」を設定する
・閉じたとき(=closeステートのstate_entry()イベント)にはドアを「初期状態の角度」にする
・開いたとき(=openステートのstate_entry()イベント)にはドアを「初期状態の角度+90度」にする
コードはこのようになります。
rotation rot;
default
{
state_entry()
{
rot = llGetRot();
state close;
}
}
state open {
state_entry()
{
llSetRot(rot * llEuler2Rot(<0.0, 0.0, 90.0> * DEG_TO_RAD));
}
touch_start(integer total_number)
{
state close;
}
}
state close {
state_entry()
{
llSetRot(rot);
}
touch_start(integer total_number)
{
state open;
}
}
見慣れない表現が出てきました。
1行目に書いてある「rotation rot;」です。
これはドアの初期角度を保持しておくための「変数」です。
変数とは、数字や文字、位置や角度などのデータを扱うためのものです。
しばしば初心者さん向けのプログラミング解説書では「データを入れておく箱のようなもの」と説明されます。
変数を使うときには、
変数の型 変数名;
のように書きます。
ここでは「回転角度」のデータを扱いますので、データの型はrotation型です。
変数名は自由につけられますが、何のための変数かわかりやすい名前にすべきでしょう。今回はrotという名前にしました。
7行目に、
rot = llGetRot();
とあります。
llGetRot()という関数はオブジェクトの回転角度を教えてくれる関数です。
これが
・「初期状態の角度」を設定
の処理になります。
つまり「変数rotにオブジェクトの現在の角度を設定する」ということです。
15行目は「開いたとき」すなわち「ドアを初期状態の角度+90度にする」処理です。
llSetRot(rot * llEuler2Rot(<0.0, 0.0, 90.0> * DEG_TO_RAD));
ごちゃごちゃ書いてありますが、分割して見て行けば全て今までに出てきた内容です。
まずllSetRot()はオブジェクトの角度を設定する命令ですね。
この命令に「rot * llEuler2Rot(<0.0, 0.0, 90.0> * DEG_TO_RAD)」のように角度を指定しています。
この部分は、「rot」と「llEuler2Rot(<0.0, 0.0, 90.0> * DEG_TO_RAD)」に分けれます。
「rot」は先ほど設定したドアの初期角度、「llEuler2Rot・・・」は例のオマジナイでZ軸回りに90度回転することを意味しています。
注意して見て頂きたいのは、「rot」と「llEuler2Rot・・・」が「*」でつながっているところです。
「*」は掛け算、つまり「×」のことです。
「あれ?初期角度+90度だから、×じゃなくて+じゃないの?」
素直に考えるとそのような疑問が出てきますが、四元数を使った3D座標系の回転は、掛け算をすることによって二つの回転を合計するのです。
あまり数学的なことを書くのもアレですので、「角度+角度」をしたいときには「角度×角度」と書くのだということを覚えてしまいましょう。
要するに15行目の
llSetRot(rot * llEuler2Rot(<0.0, 0.0, 90.0> * DEG_TO_RAD));
これで「ドアを初期状態の角度+90度にする」ことになります。
27行目は簡単ですね。
閉じたときにドアを「初期状態の角度」にする処理です。
rotには初期角度を設定してありますから、そのまま、
llSetRot(rot);
これでドアは初期角度になるわけです。
ここまででドアの動きとしては必要なところを実装できました。
「開いているとき」「しばらく経つと」「閉じる」
つまり、
「ステートopen」のとき「一定時間が経過」すると「ステートcloseになる」
これが出来れば良いわけです。
「一定時間が経過」というイベントは初めて登場します。
timerイベントと言います。
このイベントはllSetTimerEvent()という命令とセットで使います。
どのように使うかと言うと、まず、
llSetTimerEvent(10.0);
こう書くとタイマーの発動が10秒ごとに設定されます。
llSetTimerEvent(5.0);
これなら5秒ごとです。
タイマーを切るときには、
llSetTimerEvent(0.0);
このように0.0を指定します。
llSetTimerEvent()を実行したあと、指定された秒数が経過すると、timerイベントが起こります。
timerイベントは単純に、
timer(){
}
このように書きます。
ドアスクリプトに組み込んでみましょう。
rotation rot;
default
{
state_entry()
{
rot = llGetRot();
state close;
}
}
state open {
state_entry()
{
llSetRot(rot * llEuler2Rot(<0.0, 0.0, 90.0> * DEG_TO_RAD));
llSetTimerEvent(30.0);
}
touch_start(integer total_number)
{
state close;
}
timer(){
llSetTimerEvent(0);
state close;
}
}
state close {
state_entry()
{
llSetRot(rot);
}
touch_start(integer total_number)
{
state open;
}
}
16行目で、ドアが開いたときに30秒のタイマーをセットしています。
24行目から27行目がタイマーが発動したときの処理です。
まず25行目でタイマーを切り、26行目でステートをcloseに変更しています。
これで、ドアが開いてから30秒経つと自動的に閉じるようになります。
なお、ドアによっては、内開き・外開きを変更したい場合もあるでしょう。
その場合は15行目の回転角度を、-90度にしてやれば開く向きが変わります。
2007/08/2

