2009年01月08日
リスト変数を使おう
LSLのとても便利な機能にダイアログがある。
選択をボタンで選べるこいつは、海外のフリーでよくあるチャット入力より扱いが簡単で早い。
特に日本人のようなマルチバイト文字を扱う人種は、いちいち入力を切り替えなければならないので、ボタン一つで機能を切り替えられるのは助かるやね。
普段からアルファベットを打つのが早いとか、そもそもいつもアルファベットで会話してるっスよなんていう人は、まぁ。。。羨ましいですね。。。
それはさておき、ダイアログを使う時に必須なのがリスト変数だ。
変数というあまりに基本的なことのためか、リスト変数の使い方を説明してくれるところは多くない。
私も、文字列や整数や小数の変数はすぐに解ったが、リスト変数は何となく面倒な気がして、初めは使いたがらなかった。
でも慣れると便利なのがこのリスト変数なんだな。
リスト変数の基本的な書き方は list 変数名 = [内容, 内容, 内容, 内容]; って感じ。
[]で囲むのがルール。
一つの変数に何個も中身を入れられるのが特徴で、その種類も問わない。
ただ一つだけ、リストの中にリストを入れることはできない。
例としてはこうなる。
------------------------------
list fruit = ["apple", "banana", "mellon", "peach"];
list price = [150, 100, 1000, 350];
-----------------------------
まぁつまり、文字列型なら""で囲むとか、普通の変数の扱いと同じ。
リスト変数は、中に内容を代入する方法と、取り出す方法がちょっと他の変数と違う。
まず中に代入する方法は、 x = x + [100]; または、 x += [100]; となる。
右の方がちょっとだけ書くのが楽、やってることは同じ。
[]で囲んだものを、こうやって次々と中に突っ込んでいける。
ただ、取り出すためには関数が必要。
-----------------------------
内容を文字列型として取り出す
string llList2String(list src, integer index)
内容を整数型として取り出す
integer llList2Integer(list src, integer index)
内容を小数型として取り出す
float llList2Float(list src, integer index)
内容をキー型として取り出す
key llList2Key(list src, integer index)
内容をベクター型として取り出す
vector llList2Vector(list src, integer index)
内容をローテーション型として取り出す
rotation llList2Rot(list src, integer index)
内容をリスト型として取り出す
list llList2List(list src, integer start, integer end)
--------------------------------
list src は取り出し元のリスト変数、integer index は0から始まる取り出し内容の番号。
llList2List はリスト型として複数の内容を取り出すので、 index がstart に変わり、取り出し終わり番号の integer end が追加される。
このうち、llList2String は文字列として、llList2List はリストとして取り出すので、中身が何だろうと自由に取り出せる。
また、整数型を llList2Float で取り出すと、自動的に最後に.00000が付く。
その他のものは取り出し先と同じ型でなければいけない。
まぁ「その型」として出したいのだから、当たり前っちゃ当たり前。
-追記-
この、リストから各型で取り出す方法であるが、元々のリストに文字列型で入っていた場合(ノートから読み込むとかチャットで聞き取るとか)、それは文字列型のままなことに注意が必要である。
例えば["<150, 120, 140>"] というリストからllList2Vetor で取り出しても、答えは<0, 0, 0>になってしまう。
これは文字列型を強引にベクター型に変換したためだ。
この場合は、llList2String としていったん文字列型として取り出し、その後にベクター型に変換する。
vector x = (vector)llList2String(data, 0); って具合。
LSLの型はかなり融通が利かないので注意が必要だ。
前置きはこのくらいにして、実際にダイアログで使う方法といこう。
ダイアログでは選択ボタンをリストとして用意する。
これ、利用しない手はない。
さっきの果物の種類と値段を使って例を書いてみよう。
----------------------------------------------------------
list fruit = ["apple", "banana", "mellon", "peach"];
list price = [150, 100, 1000, 350];
integer ch;
integer handle;
end()
{
llSetTimerEvent(0.0);
llListenRemove(handle);
}
default
{
touch_start(integer total_number)
{
ch = llFloor(llFrand(6851) + 235);
handle = llListen(ch, "", NULL_KEY, "");
llDialog(llDetectedKey(0), "果物を選んでください", fruit, ch);
llSetTimerEvent(10.0);
}
listen(integer channel, string name, key id, string message)
{
integer list_num = llListFindList(fruit, [message]);
string fruit_name = llList2String(fruit, list_num);
integer fruit_price = llList2Integer(price, list_num);
llSay(0, fruit_name + "は" + (string)fruit_price + "円です");
end();
}
timer()
{
llSay(0, "時間切れです");
end();
}
}
------------------------------------------------------
結構プログラムっぽいだろう。
と言うか、例がWEBプログラム入門書みたいだな。。イマイチだ。
ダイアログで選んだ内容をリッスンで聞いているのだが、if文がないことに気付いただろうか。
普通は、リッスンで聞いたmessageの内容でifで分岐するんだよね。
鍵を握っているのがinteger llListFindList(list src, list test) という関数。
これはlist src というリストの中にlist test というリストが入っているかを調べて、入っていたらその番号を返す。
え、なんでリスト同士じゃないとダメなん?と思うだろうが、私も思ったが、とりあえず決まりらしい。
だから調べるものをリストに変換してやればいい。
上のでは[]でmessageを囲む事で、ダイアログの答えをリストに変換しているが、もちろん(list)message と書いても構わない。
番号が返ってきたら、それを変数fruit と変数price で調べてやるわけだ。
これはifでダラダラ長ったらしく書くよりもスクリプトが短く済むし、変更場所が一番上のリスト変数の中だけなんで書き換えも楽だ。
もちろんリスト処理の部分をキッチリ書いておけば、他のスクリプトにそのままコピーできる(変数名は直すようにw)。
特に触れていないが、end()というユーザー関数は不要になったリッスンとタイマーを終わらせるものだ。
ダイアログでは、この「終わらせる」処理は忘れないように。
細かいことだけど、大事なクセとして身に付けておこう。
ちょっと面白い例を思いついたけど長くなるから分ける。
選択をボタンで選べるこいつは、海外のフリーでよくあるチャット入力より扱いが簡単で早い。
特に日本人のようなマルチバイト文字を扱う人種は、いちいち入力を切り替えなければならないので、ボタン一つで機能を切り替えられるのは助かるやね。
普段からアルファベットを打つのが早いとか、そもそもいつもアルファベットで会話してるっスよなんていう人は、まぁ。。。羨ましいですね。。。
それはさておき、ダイアログを使う時に必須なのがリスト変数だ。
変数というあまりに基本的なことのためか、リスト変数の使い方を説明してくれるところは多くない。
私も、文字列や整数や小数の変数はすぐに解ったが、リスト変数は何となく面倒な気がして、初めは使いたがらなかった。
でも慣れると便利なのがこのリスト変数なんだな。
リスト変数の基本的な書き方は list 変数名 = [内容, 内容, 内容, 内容]; って感じ。
[]で囲むのがルール。
一つの変数に何個も中身を入れられるのが特徴で、その種類も問わない。
ただ一つだけ、リストの中にリストを入れることはできない。
例としてはこうなる。
------------------------------
list fruit = ["apple", "banana", "mellon", "peach"];
list price = [150, 100, 1000, 350];
-----------------------------
まぁつまり、文字列型なら""で囲むとか、普通の変数の扱いと同じ。
リスト変数は、中に内容を代入する方法と、取り出す方法がちょっと他の変数と違う。
まず中に代入する方法は、 x = x + [100]; または、 x += [100]; となる。
右の方がちょっとだけ書くのが楽、やってることは同じ。
[]で囲んだものを、こうやって次々と中に突っ込んでいける。
ただ、取り出すためには関数が必要。
-----------------------------
内容を文字列型として取り出す
string llList2String(list src, integer index)
内容を整数型として取り出す
integer llList2Integer(list src, integer index)
内容を小数型として取り出す
float llList2Float(list src, integer index)
内容をキー型として取り出す
key llList2Key(list src, integer index)
内容をベクター型として取り出す
vector llList2Vector(list src, integer index)
内容をローテーション型として取り出す
rotation llList2Rot(list src, integer index)
内容をリスト型として取り出す
list llList2List(list src, integer start, integer end)
--------------------------------
list src は取り出し元のリスト変数、integer index は0から始まる取り出し内容の番号。
llList2List はリスト型として複数の内容を取り出すので、 index がstart に変わり、取り出し終わり番号の integer end が追加される。
このうち、llList2String は文字列として、llList2List はリストとして取り出すので、中身が何だろうと自由に取り出せる。
また、整数型を llList2Float で取り出すと、自動的に最後に.00000が付く。
その他のものは取り出し先と同じ型でなければいけない。
まぁ「その型」として出したいのだから、当たり前っちゃ当たり前。
-追記-
この、リストから各型で取り出す方法であるが、元々のリストに文字列型で入っていた場合(ノートから読み込むとかチャットで聞き取るとか)、それは文字列型のままなことに注意が必要である。
例えば["<150, 120, 140>"] というリストからllList2Vetor で取り出しても、答えは<0, 0, 0>になってしまう。
これは文字列型を強引にベクター型に変換したためだ。
この場合は、llList2String としていったん文字列型として取り出し、その後にベクター型に変換する。
vector x = (vector)llList2String(data, 0); って具合。
LSLの型はかなり融通が利かないので注意が必要だ。
前置きはこのくらいにして、実際にダイアログで使う方法といこう。
ダイアログでは選択ボタンをリストとして用意する。
これ、利用しない手はない。
さっきの果物の種類と値段を使って例を書いてみよう。
----------------------------------------------------------
list fruit = ["apple", "banana", "mellon", "peach"];
list price = [150, 100, 1000, 350];
integer ch;
integer handle;
end()
{
llSetTimerEvent(0.0);
llListenRemove(handle);
}
default
{
touch_start(integer total_number)
{
ch = llFloor(llFrand(6851) + 235);
handle = llListen(ch, "", NULL_KEY, "");
llDialog(llDetectedKey(0), "果物を選んでください", fruit, ch);
llSetTimerEvent(10.0);
}
listen(integer channel, string name, key id, string message)
{
integer list_num = llListFindList(fruit, [message]);
string fruit_name = llList2String(fruit, list_num);
integer fruit_price = llList2Integer(price, list_num);
llSay(0, fruit_name + "は" + (string)fruit_price + "円です");
end();
}
timer()
{
llSay(0, "時間切れです");
end();
}
}
------------------------------------------------------
結構プログラムっぽいだろう。
と言うか、例がWEBプログラム入門書みたいだな。。イマイチだ。
ダイアログで選んだ内容をリッスンで聞いているのだが、if文がないことに気付いただろうか。
普通は、リッスンで聞いたmessageの内容でifで分岐するんだよね。
鍵を握っているのがinteger llListFindList(list src, list test) という関数。
これはlist src というリストの中にlist test というリストが入っているかを調べて、入っていたらその番号を返す。
え、なんでリスト同士じゃないとダメなん?と思うだろうが、私も思ったが、とりあえず決まりらしい。
だから調べるものをリストに変換してやればいい。
上のでは[]でmessageを囲む事で、ダイアログの答えをリストに変換しているが、もちろん(list)message と書いても構わない。
番号が返ってきたら、それを変数fruit と変数price で調べてやるわけだ。
これはifでダラダラ長ったらしく書くよりもスクリプトが短く済むし、変更場所が一番上のリスト変数の中だけなんで書き換えも楽だ。
もちろんリスト処理の部分をキッチリ書いておけば、他のスクリプトにそのままコピーできる(変数名は直すようにw)。
特に触れていないが、end()というユーザー関数は不要になったリッスンとタイマーを終わらせるものだ。
ダイアログでは、この「終わらせる」処理は忘れないように。
細かいことだけど、大事なクセとして身に付けておこう。
ちょっと面白い例を思いついたけど長くなるから分ける。


