気ままな一言
2008年04月01日
LSL汎用関数 その2
数学っぽい関数です
//============================================================================== // 角度(度数法)からrotation型に変換します // degree 角度 // 戻り値 rotation型の回転値を返します。 //============================================================================== rotation deg2rot(vector degree) { return llEuler2Rot(degree * DEG_TO_RAD); } 【使用方法】 rotation rot = deg2rot(<45.0, 0, 0>); // X軸45度
//============================================================================== // rotation型から角度(度数法)に変換します // rot 回転値 // 戻り値 角度をを返します。 //============================================================================== vector rot2deg(rotation rot) { return llRot2Euler(rot) * RAD_TO_DEG; } 【使用方法】 vector vec = rot2deg(<1, 0, 0, 1>); // X軸180度
//============================================================================== // 整数値の乱数を生成します // min 返す値の最小値 // max 返す値の最大値 // 戻り値 minからmaxまでの間の乱数値を返します。 (min <= value <= max) //============================================================================== integer rand(integer min,integer max) { return llFloor(llFrand(max - min + 1)) + min; } 【使用方法】 integer n = rand(3, 5); // 3 <= n <= 5 integer n = rand(-3, 5); // -3 <= n <= 5
//============================================================================== // 最大値を返します // values 比較する値(数値のみ有効) // 戻り値 valuesに含む値から最大値を返します。 //============================================================================== float max(list values) { return llList2Float(llListSort(values, 1, FALSE), 0); } 【使用方法】 float n = max([3, 5, 10, 4, 1]); // n = 10
//============================================================================== // 最小値を返します // values 比較する値(数値のみ有効) // 戻り値 valuesに含む値から最小値を返します。 //============================================================================== float min(list values) { return llList2Float(llListSort(values, 1, TRUE), 0); } 【使用方法】 float n = min([5, 7, 1, 9, 3]); // n = 1
//============================================================================== // 16進数を10進数に変換します。 // 16進文字列以外はすべて無視されます。 // hex 16進文字列 // 戻り値 10進に変換した値を返します。 //============================================================================== float hex2dec(string hex) { integer i = -llStringLength(hex); integer j; float n = 0; hex = llToLower(hex); while (i) { j = llSubStringIndex("0123456789abcdef", llGetSubString(hex, i, i)); i = -(~i); if (j >= 0) { n = (n * 16) + j; } } return n; } 【使用方法】 float value = hex2dec("ff"); // value = 255.0 float value = hex2dec("ffffffffff"); // value = 1099511627776.0
//============================================================================== // 10進数を16進数に変換します。 // number 数値 // 戻り値 16進に変換した文字列を返します。 //============================================================================== string dec2hex(integer number) { integer n; string hex; string top = ""; if (number & 0x80000000) { // number < 0 number = 0x0fffffff & number; top = "f"; } do { hex = llGetSubString("0123456789abcdef", (n = number % 16), n) + hex; } while (number /= 16); return top + hex; } 【使用方法】 string hex = dec2hex(30); // hex = "1e" string hex = dec2hex(-30); // hex = "ffffffe2"
2008年03月28日
LSL汎用関数 その1
文字列関連です。
//============================================================================== // 文字列を置換します。 // source 対象の文字列 // search 置換される文字列 // replace 置換する文字列 // 戻り値 置換されたを返します。 //============================================================================== string str_replace(string source, string search, string replace) { integer len = llStringLength(search); integer index = llSubStringIndex(source, search); while (index >= 0) { source = llDeleteSubString(source, index, -1) + replace + llDeleteSubString(source, 0, index + len - 1); index = llSubStringIndex(source, search); } return source; } 【使用方法】 string str = str_replace("0123456789", "123", "zzz"); // str = "0zzz456789" string str = str_replace("0123401234", "123", "zzz"); // str = "0zzz40zzz4"
//============================================================================== // 文字列を反復します。 // str 繰り返す文字列 // count 繰り返す回数 // 戻り値 繰り返した文字列を返します。 //============================================================================== string str_repeat(string str, integer count) { string s = ""; integer i; for (i = 0; i < count; i=-(~i)) { s += str; } return s; } // 件数が増えても高速 string str_repeat(string str, integer count) { string s1; string s2 = ""; integer i; while (count) { s1 = str; i = 0; while (count >> (i=-(~i))) { s1 += s1; } count -= (1 << (i - 1)); s2 += s1; } return s2; } 【使用方法】 string str = str_repeat(" ", "5"); // str = " " string str = str_repeat("12", "5"); // str = "1212121212"
//============================================================================== // 文字列の末尾を指定の長さまで他の文字列で埋めます。 // padに""(空文字)を指定した場合は" "(スペース)で埋められます。 // str 文字列 // length 埋めた後の長さ // pad 埋める文字列 // 戻り値 埋めた後の文字列を返します。 //============================================================================== string str_pad(string str, integer length, string pad) { if (pad == "") { pad = " "; // default space } while (llStringLength(str) < length) { str += pad; } return llGetSubString(str, 0, length - 1); } 【使用方法】 string str = str_pad("01234", "10", " "); // str = "01234 " string str = str_pad("0123456789", "5", " "); // str = "01234" string str = str_pad("01234", "10", "abc"); // str = "01234abcab"
//============================================================================== // 文字列の先頭を指定の長さまで他の文字列で埋めます。 // padに""(空文字)を指定した場合は" "(スペース)で埋められます。 // str 文字列 // length 埋めた後の長さ // pad 埋める文字列 // 戻り値 埋めた後の文字列を返します。 //============================================================================== string str_lpad(string str, integer length, string pad) { if (pad == "") { pad = " "; // default space } integer n; while ((n = llStringLength(str) - length) < 0) { str = pad + str; } return llGetSubString(str, n, n + length - 1); } 【使用方法】 string str = str_lpad("01234", "10", " "); // str = " 01234" string str = str_lpad("0123456789", "5", " "); // str = "56789" string str = str_lpad("01234", "10", "abc"); // str = "bcabc01234"
//============================================================================== // 文字列を逆順にします。 // str 逆順にする文字列 // 戻り値 逆順にした文字列を返します。 //============================================================================== string str_reverse(string str) { string s = ""; integer len = llStringLength(str); integer i; for (i = len - 1; i >= 0; i=~(-i)) { s += llGetSubString(str, i, i); } return s; } // メモリ節約版 string str_reverse(string str) { integer len = llStringLength(str); integer i; for (i = len - 2; i >= 0; i=~(-i)) { str = llDeleteSubString(str, i, i) + llGetSubString(str, i, i); } return str; } 【使用方法】 string str = str_reverse("01234"); // str = "43210"
//============================================================================== // 大文字小文字を区別しない文字列比較を行います。 // str1 文字列1 // str2 文字列2 // 戻り値 等しい場合はTRUEを返します。 //============================================================================== integer str_case_equal(string str1, string str2) { return llToLower(str1) == llToLower(str2); } 【使用方法】 integer result = str_case_equal("abc", "abc"); // result = TRUE integer result = str_case_equal("aBC", "AbC"); // result = TRUE
2008年03月26日
スクリプトの書き方
スクリプトの書き方、いわゆるコーディングスタイルについて少しだけ触れてみようと思います。
公式ページにも書いてあります。
SLはプログラムをするところではないので、プログラム未経験者が殆どだと思います。
なので、LSLの文法はもとより、こういうことも知らないのではないかと思う訳です。
実に些細なことですが、意外と重要なことです。
途中でわけがわからなくなる状況を事前に防ぐことができるかもしれません。
これらはLSLに限らず、他のプログラミング言語でも概ね言えることです
まぁ少しだけでも頭の隅においてもらえればと思います。
なお、この手の話に異論はつきものです。
これが正しいというわけではありませんので参考までにと留めておいて下さい。
インデント
まずはこれです。インデントをつけるだけで読み易さは格段に変わります。
基本的には中括弧( { } )の度にタブで段落を変えるだけです。
SLビューア標準のエディタではタブはスペース4つに置き換わります。
これが意外と厄介で、修正時にタブなら1つ削除で済むところをスペースでは4つ消さないといけません。
消す個数を間違えるとせっかくのレイアウトも崩れてしまいます。
外部のエディタを使えばそういう心配はありませんし、手元にスクリプトを保存しておくことができます。
時々スクリプトの添削などを頼まれることもあるのですが、まず最初にすることがインデントを揃えるということも少なくありません。
なお、タブの設定はスペース4つ分にしておきましょう。
タブは環境依存するので嫌う人もいるのですが、スペースでの調整は手間ですし、おすすめしません。
中括弧( { } )の位置
if文などでブロック(範囲)を決めるときの括弧です。主に下記の2つの書き方があると思います。
私も最初は[B]でしたが、今は[A]のスタイルをとっています。
理由は単純で行数が増えるからです。行数が増えるということは一度にみられる量も減ってしまうからです。
また、両方のスタイルを混ぜることは、なるべくしないで下さい。
美しくないです。
ただし、[A]のスタイルでも関数の場合のみ[B]の形をとることが多いです。
私も人のソースを編集するときは基本的にそのスタイルに合わせるようにしています。
ちなみに、ifやforなどの制御構文で、処理が1行で済む場合は括弧を省略できるのですが、
そんなことはしないほうが身のためです。
また、中括弧のあとは改行すべきです。
特別な場合を除いて使わないほうが誤解を招くことも少なくなります。
変数の命名
基本的にわかりやすければ良いと思います。
変数の先頭を小文字で始めて、意味の区切りで大文字に変えるかアンダーバー( _ )で区切れば問題ありません。
定数というからには、初期化以外でこの変数の内容は変更すべきではありません。
また、変数の型や種類によってプレフィックスをつける手法もあります。
先に示したページでは
グローバル変数には先頭に g 、関数やイベントの引数には _
をつけることを推奨しています。
この範囲のプレフィックスは確かにわかり易いソースにはなるのですが、意外と使われないことが多いです。
まぁ理由は面倒臭いとかみためが美しくないとかだったりするのですが。
関数の命名
こちらもわかり易ければ何でも良いと思います。
ただし、LSLの関数はすべて ll から始まる形で構成されていますので、
ll から始まる名前だけは避けた方が無難です。
LSLのイベントについては周知の通り、小文字+_ 区切りを採用しています。
最後に
コメントはできるだけ多くつけておきましょう。
コーディングスタイルなんてものはある意味、宗教のようなものですので細かいことを気にする必要はありません。
(細かいこといい始めると、スペースの入れ方など色々とあります)
ですが、時間が経つと自分のソースも他人のソースのようなものです。
最初から他人がみてもわかり易い書き方であれば、自分のソースで無駄に悩む必要もなくなります。
要するに美しいということは素晴らしいということなのです。
続きを読む
公式ページにも書いてあります。
SLはプログラムをするところではないので、プログラム未経験者が殆どだと思います。
なので、LSLの文法はもとより、こういうことも知らないのではないかと思う訳です。
実に些細なことですが、意外と重要なことです。
途中でわけがわからなくなる状況を事前に防ぐことができるかもしれません。
これらはLSLに限らず、他のプログラミング言語でも概ね言えることです
まぁ少しだけでも頭の隅においてもらえればと思います。
なお、この手の話に異論はつきものです。
これが正しいというわけではありませんので参考までにと留めておいて下さい。
インデント
まずはこれです。インデントをつけるだけで読み易さは格段に変わります。
基本的には中括弧( { } )の度にタブで段落を変えるだけです。
SLビューア標準のエディタではタブはスペース4つに置き換わります。
これが意外と厄介で、修正時にタブなら1つ削除で済むところをスペースでは4つ消さないといけません。
消す個数を間違えるとせっかくのレイアウトも崩れてしまいます。
外部のエディタを使えばそういう心配はありませんし、手元にスクリプトを保存しておくことができます。
時々スクリプトの添削などを頼まれることもあるのですが、まず最初にすることがインデントを揃えるということも少なくありません。
なお、タブの設定はスペース4つ分にしておきましょう。
タブは環境依存するので嫌う人もいるのですが、スペースでの調整は手間ですし、おすすめしません。
中括弧( { } )の位置
if文などでブロック(範囲)を決めるときの括弧です。主に下記の2つの書き方があると思います。
[A] state_entry() { } [B] tate_entry() { }慣れるまでは括弧の位置が対応している[B]のスタイルで書くほうがわかり易いと思います。
私も最初は[B]でしたが、今は[A]のスタイルをとっています。
理由は単純で行数が増えるからです。行数が増えるということは一度にみられる量も減ってしまうからです。
また、両方のスタイルを混ぜることは、なるべくしないで下さい。
美しくないです。
ただし、[A]のスタイルでも関数の場合のみ[B]の形をとることが多いです。
私も人のソースを編集するときは基本的にそのスタイルに合わせるようにしています。
ちなみに、ifやforなどの制御構文で、処理が1行で済む場合は括弧を省略できるのですが、
そんなことはしないほうが身のためです。
また、中括弧のあとは改行すべきです。
○ if (i == 0) { val = 10; } △ if (i == 0) val = 10;否定はしませんが、少なくとも初心者にはおすすめできません。
特別な場合を除いて使わないほうが誤解を招くことも少なくなります。
変数の命名
基本的にわかりやすければ良いと思います。
変数の先頭を小文字で始めて、意味の区切りで大文字に変えるかアンダーバー( _ )で区切れば問題ありません。
string avatarName; string avatar_name;そして、定数値はすべて大文字で書き、意味の区切りでは _ を使用します。
定数というからには、初期化以外でこの変数の内容は変更すべきではありません。
key OWNER_KEY = llGetOwner();
また、変数の型や種類によってプレフィックスをつける手法もあります。
先に示したページでは
グローバル変数には先頭に g 、関数やイベントの引数には _
をつけることを推奨しています。
この範囲のプレフィックスは確かにわかり易いソースにはなるのですが、意外と使われないことが多いです。
まぁ理由は面倒臭いとかみためが美しくないとかだったりするのですが。
関数の命名
こちらもわかり易ければ何でも良いと思います。
ただし、LSLの関数はすべて ll から始まる形で構成されていますので、
ll から始まる名前だけは避けた方が無難です。
LSLのイベントについては周知の通り、小文字+_ 区切りを採用しています。
最後に
コメントはできるだけ多くつけておきましょう。
コーディングスタイルなんてものはある意味、宗教のようなものですので細かいことを気にする必要はありません。
(細かいこといい始めると、スペースの入れ方など色々とあります)
ですが、時間が経つと自分のソースも他人のソースのようなものです。
最初から他人がみてもわかり易い書き方であれば、自分のソースで無駄に悩む必要もなくなります。
要するに美しいということは素晴らしいということなのです。
続きを読む