ソラマメブログ

2007年09月04日

モジュール化

LSLでは巨大なプログラムを作ることができません。
というのも一つのLSLのサイズは16KByteまでという制限があるためです。
この制限は、スクリプトコードの本体のサイズだけでなく、スクリプトが動作したときのメモリを含めたサイズです。

スクリプトを正しく書いていても、サイズが大きくなって16KByteの制限を越えてしまうと、
「Stack-Heap Collision」
などのエラーが発生し、スクリプトは動かなくなってしまいます。

今回はこの問題に対処するための、中級者向けのお話をしておきます。
サイズって?

メモリとかコードサイズと言われても何のことやら、という方もいらっしゃると思いますので、簡単に解説します。
解説なんかいらんからサンプルコードを見せい!という方はこちらまで読み飛ばしちゃって下さい。

スクリプトが動作するときには、当然ながらサーバーのパワーを使うわけですが、一つのスクリプトが動作するときに使えるパワーには限度があるということです。

ここで言う「サーバー側のパワー」というのは、スクリプトが動作するための場所のことです。
たとえば、学校の校庭を思い浮かべて見て下さい。
校庭ではいろいろなスポーツが出来るようになっていますが、面積には限りがありますよね。
テニスならば4面取れるけど、サッカーをするときは1面しか取れないとか。
コンピュータ上で何かプログラムが動くときは、校庭にコートを確保するのと同じように、プログラムが動作できるスペースを確保して動くようになっています。
このスペースのことを「メモリ」と言います。

LSLは、このメモリの大きさが16KByteまでに制限されているのです。
校庭のごく一部だけを自由に使えるようなものです。

16KByteというのがどのくらいのサイズかと言うと、例えば、
"こんにちは"
という文字データは、1文字4Byte、5文字なので20Byteです。
16キロByteというのは約16,000Byteのことですので、
"こんにちは"
に換算すると800個分ですw

「おお、800回も"こんにちは"が言えるのか!」
とは思わないで下さい。
今回の記事のここまでの記述をデータ量に置き換えると、1,700Byteあります。
わずか30行程度の文章でそこまで行きますので、16,000Byte程度ならあっという間に埋まります。

あるいは、皆さんが今使っているかもしれない、インターネットのブラウザ。
私は先ほどインターネットエクスプローラを立ち上げてみましたが、何のページも表示していない状態で、使用メモリは6,000KByteでした。
6,000KByteというのは6,000,000Byteのことです。
16,000Byteと比べると桁違いですね(^^;
「たった16KByteしか使えないのか!」
と思っていただければ幸いです。

スクリプトのサイズを制限しているのは、言うまでもなくサーバー負荷を軽減するためでしょう。
無制限にメモリを使えてしまったら、一本のスクリプトが校庭全面を占拠して、
「今日は俺様のリサイタルだ~!」
などという暴挙が可能になってしまいます。
そんな野望を阻止するため、スクリプトのサイズは16KByteに制限されているわけです。

しかし・・・。

「お、お願いです、うちには相撲取りの息子が5人も居るんです・・・」
「ええい、黙れ!配給は一家につきイモ16個と決まっておる!」
「そ、そんな、それでは息子たちは食べていけません!」
「うるさいヤツめ、ならば食わなければよかろう!」

我々はそんな抑圧された環境下で、黙って耐え忍んでいくしかないのでしょうか。

モジュール化

16KByteの制限はLSLの仕様ですので、これを打ち破ることは不可能です。
一つのスクリプトは必ず16KByte以内で収まるように作らなければいけません。

ですが、複雑なことをしようと思うと、どう頑張ってみたところで16KByteには収まりきらないという事態が起こりえます。
この限界は想像以上にすぐにぶち当たる壁です。
そして、正面からぶつかっていっても、絶対に越えることのできない困難な壁でもあります。

ではどうやったらこの壁を越えることができるでしょうか。
その答えは少年ジャンプあたりを読むと書いてあります。

少年ジャンプのストーリーは「努力」「友情」「勝利」がテーマなんだそうです。
最近のジャンプは知りませんが、ドラゴンボールなどはまさに典型的ですよね。

スクリプトの限界サイズは「努力」しても越えることができません。
こうなると「友情」に頼るしかありません。
一人の小さな手では何もできませんが、皆が集まると何かできてしまうのです。

これがLSLのモジュール化の発想です。
つまり、一つのスクリプトの限界は16KByteですが、複数のスクリプトを組み合わせ、全体として一つの大きなシステムにしてやるのです。
スクリプトの機能を分化し、連携して動くようにすることをモジュール化と言います。
モジュール化してやれば、トータルで見たときには16KByteの制限を越えるシステムを作ることが可能になります。

また、モジュール化には他のメリットもあります。

第一に開発効率が良くなります。
ダイアログモジュールやリッスンモジュール、アニメーション、サウンドなどをモジュール化しておくと、次にそれらの機能を使いたいときにはそのモジュールをほぼそのまま使うことが可能です。
一つ一つのスクリプトにいちいちリッスンやアニメーションのわずらわしいコードを書く必要がなくなります。

メンテナンス性の向上もみこめます。
モジュールごとに機能が分かれていれば、何か修正するときには一部のモジュールだけを更新するだけでOKになります。
例えばゲームの点数やRPGシステムの経験値など、データを保存するようなスクリプトの場合、スクリプトを修正するとデータはリセットされてしまいます。
しかしモジュール化によってデータを管理するスクリプトと、他の機能のスクリプトが分かれていれば、データ管理のスクリプトを修正しない限りはデータは保持されます。

また、拡張性も高くなります。
機能が分割されていますので、新しい機能を追加するときには別のモジュールを作って追加すれば良いのです。
例えば、オブジェクトの色が変わる機能を追加したいと思ったら、色変更用のモジュールを追加するだけです。
モジュール化を上手に実現しておくと、もとからあるスクリプトを一切いじらなくても大丈夫です。

モジュール化の手法

モジュール化を行うには、別に難しいコードを書く必要はありません。
初級スクリプトでも解説しているリンクメッセージ機能を利用すれば良いのです。

リンクメッセージは違うprimのスクリプト同士で通信を行う機能として紹介しましたが、実は同じprim内のスクリプト同士の通信も可能です。

・同一prim内のスクリプトへのリンクメッセージ送信:
llMessageLinked(LINK_THIS, integer ,string, key);


・同一オブジェクト内(全リンクprim)のスクリプトへのリンクメッセージ送信:
llMessageLinked(LINK_SET, integer ,string, key);


この二つを知っていれば十分にモジュール化は可能です。
モジュールのイベントは基本的に全てlink_messageイベントに統一しておきます。
普通のLSLの構造は、「きっかけ」があったら「処理」を行うものだと何度も説明していますが、「きっかけ」をリンクメッセージだけに統一してしまうのです。
そして「処理」のほうは実現したい機能に応じたものを書きます。
つまり、
「リンクメッセージを受信したら、何らかの処理を行うスクリプト」
これがモジュールの基礎スタイルになります。

イベントをリンクメッセージのみに限定することで、考えるべきポイントは「いかに処理を行うか」だけになります。
処理を実現する仕組みのことを「ロジック」と言いますが、このことから、こうしたモジュールを「ロジック・モジュール」と私は勝手に呼んでいます(^^;
要するに「処理」が主体のモジュールのことです。

一方、タッチやリッスンなど、外部からの操作を受け付けるモジュールもまた必要です。
アバターが直接リンクメッセージを送る方法はありませんので、
「タッチされたらリンクメッセージを送る」
「コマンドを聞いたらリンクメッセージを送る」
というような、先ほどの「ロジック・モジュール」とは逆の働きをするモジュールを用意しなければなりません。
これらは様々なイベントを受け取りますが、あくまでも「処理」は「リンクメッセージの送信」です。
私はこれらのモジュールを「イベント・モジュール」と呼んでます。

●ロジック・モジュール
    イベント:リンクメッセージ
    処理:任意

●イベント・モジュール
    イベント:任意
    処理:リンクメッセージ

さてさて。
少し具体的に考えて見ましょう。

例えば、ドア・システムのモジュール群です。
あんまりモジュール化するメリットはないかもしれませんが、説明するのにわかり易いと思うので(^^;

ドアと言っても、いろんな種類のものがありますよね。
初級スクリプトの記事の中でも、回転して開くドアや自動スライドドアなどを作りました。
同じ自動ドアでも、センサーを使ったもの、衝突判定を使ったものなど、作り方を変えることもできました。

そんな風にいろいろな実現方法があるドアを、モジュール化することでひとまとまりの「ドア・システム」にし、どのモジュールを使うかによって回転ドアになったり、スライドドアになったり、はたまた自動ドアにする、手動ドアにするなど、自由自在に組み替えられるようにしてみたいと思います。

まず、ロジック・モジュール。
「処理」を実現する部分です。
今回はドアですから、「ドアの開閉」を実現できればどんなものでも良いでしょう。

ドアの開閉方法はいくつか考えられますね。
・回転
・スライド(横に限らず。上下とかも)
・薄くなって消える
・穴が開く/削れる(ホロウやパスカットを使用した変形)
・開・閉のテクスチャ切り替え(開いた画像のときにはファントム化する)

他にもあるでしょうが、まぁこんなところで。

それからイベント・モジュール。
ドアが開く「きっかけ」となる部分です。
これもいろんなものが考えられます。

・タッチ(誰でもタッチ可能なものから、特定グループ、オーナーのみ等、様々)
・合言葉(リッスンを利用したもの)
・センサー(自動ドア用)
・衝突判定(自動ドア用)
・タイマー(特定時間で開閉)

基本的にはこんなところでしょうか。
やろうと思えばもっと変なのも出来ますが(^^;強い風が吹くと開くとかwww

以上のようなモジュールを用意したとすると、ドアを作る際、使いたいものを組み合わせてオブジェクトに放り込むだけでOKになります。
いちいちスクリプトを書き直す必要がなくなります。

また、「風で開くドア」を作りたいと思ったら、追加するのはイベントモジュール一つだけで済みます。
ロジックモジュール部分はなんら変える必要がありません。

そのように使い勝手が良く、拡張も楽なのがモジュール化のメリットです。

ドア・システム

具体的にコーディングしてみましょう。
ここに載せたスクリプトは自由に改造・再利用していただいて構いません。
組み合わせていろいろドアを作ってみるといいでしょう。

なお、モジュール・スクリプトはオブジェクトの中に直接作るのではなく、インベントリ内に作ったほうが後で使いやすいかと思います。

まずは「ロジック・モジュール」をいくつか作ります。
「ドアの開閉の仕組み」です。
インベントリのお好みの位置に新しいスクリプトを作成し、"slide door module"という名前を付けて下さい。
そして以下のコードを記述します。

slide door module
vector pos;
vector move_to = <0.0, 1.5, 0.0>;
integer opened = FALSE;

default {
  state_entry(){
    pos = llGetLocalPos();
  }
  
  moving_end(){
    if (opened){
      pos = llGetLocalPos() - (move_to * llGetRot());
    }else{
      pos = llGetLocalPos();
    }
  }
  
  link_message(integer send, integer num, string str, key id){
    if (str == "door"){
      if (num){
        // open
        llSetPos(pos + (move_to * llGetRot()));
        opened = TRUE;
      } else {
        // close
        llSetPos(pos);
        opened = FALSE;
      }
    }
  }
}

このモジュールはオブジェクト(prim)をY軸方向に1.5mスライドさせます。
スライドして開くドアの動きを実現したものです。
しかしながら、あくまでも「開閉の動き」だけしか実現していません。
何をしたときにドアが開くかについては一切記述されていませんので、アバターがタッチしたり体当たりしたところで何も起こりません。

もう一つ「ロジック・モジュール」を作っておきましょう。
インベントリのお好みの位置に新しいスクリプトを作成し、"standard door module"という名前を付けて下さい。
そして以下のコードを記述します。

standard door module
rotation rot;
vector rotation_to = <0.0, 0.0, 90.0>;
integer opened = FALSE;

default {
  state_entry(){
    rot = llGetLocalRot();
  }
  
  moving_end(){
    if (opened){
      rot = llGetLocalRot() / llEuler2Rot(rotation_to * DEG_TO_RAD);
    }else{
      rot = llGetLocalRot();
    }
  }
  
  link_message(integer send, integer num, string str, key id){
    if (str == "door"){
      if (num){
        // open
        llSetLocalRot(rot * llEuler2Rot(rotation_to * DEG_TO_RAD));
        opened = TRUE;
      } else {
        // close
        llSetLocalRot(rot);
        opened = FALSE;
      }
    }
  }
}

このモジュールはオブジェクト(prim)をZ軸基準に90度回転させます。
一般的なドアの動きを実現したものです。
しかしながら、先ほどのスライドドアと同様、あくまでも「開閉の動き」だけしか実現していません。

2つの「ロジック・モジュール」を載せましたが、これらのモジュールはどちらも、リンク・メッセージを受信したときに動き出します。
特に、リンクメッセージの文字列が"door"の場合にのみ「開閉動作」を行うようになっています。
リンクメッセージのinteger値がTRUEの場合は「開」、FALSEの場合は「閉」の動作です。

さて、それでは次に、この二つの「ロジック・モジュール」にリンクメッセージを送る部分のLSLを書いてみます。
インベントリのお好みの位置に新しいスクリプトを作成し、"door main module"という名前を付けて下さい。
コードは以下のようになります。

door main module
float auto_close_timer = 60.0;
integer opened = FALSE;

default {
  link_message(integer send, integer num, string str, key id){
    if (str == "action"){
      opened = (!opened) * (num == -1) + (num != FALSE) * (num != -1);
      llMessageLinked(LINK_SET,opened,"door",NULL_KEY);
      llSetTimerEvent(auto_close_timer * opened);
    }
  }
  timer(){
    llSetTimerEvent(0.0);
    llMessageLinked(LINK_SET,FALSE,"action",NULL_KEY);
  }
}

このロジックモジュールは、あらゆるドアに共通した性質・動作を実装したものです。
共通した性質とは「ドアには開・閉の2つの状態がある」という点です。
共通した動作とは「開けてから一定時間が経過すると自動的に閉まる」ことです。
スライドドアであろうと、普通のドアであろうと、開・閉の2状態があることには変わりないし、一定時間経つと自動で閉まる機能があってしかるべきでしょう。
つまりこのモジュールは「ドアの基本的な性質」を実現したものです。
あらゆるドアは全てこのモジュールをコアとして使います。

コードをざっとながめていただくと分かるかと思いますが、このモジュールはリンクメッセージ"action"を受信したときに動き、"door"というリンクメッセージを送信するだけの動きしかしません。
先ほど載せたスライドドア、スタンダードドアはどちらもリンクメッセージ"door"で動き出すようになっていましたから、このメインモジュールからのリンクメッセージを受けて動くということになります。



ドアの動きをスライド式にしたければ、スライド・ドア・モジュールを使い、一般的なドアにしたければスタンダード・ドア・モジュールを使います。
どちらのモジュールを使うにしても、メイン・モジュールは同一のものでOKになります。

さて、これでロジックモジュールができましたので、次に「イベントモジュール」を作ってみましょう。
「ドアの開閉するきっかけ」です。
インベントリのお好みの位置に新しいスクリプトを作成し、"short touch module"という名前を付けて下さい。
そして以下のコードを記述します。

short touch module
float distance = 5.0;

default {
  touch_start(integer detected){
    if (llVecDist(llGetPos(), llDetectedPos(0)) <= distance){
      llMessageLinked(LINK_SET,-1,"action",llDetectedKey(0));
    }else{
      llInstantMessage(llDetectedKey(0), "There is out of your reach. You can't touch. ");
    }
  }
}

このモジュールは基本的にタッチイベントに反応しますが、距離の制限が付いています。
先頭に定義している変数distanceがタッチが有効になる距離です。
ここに記載した例(distance = 5.0)であれば、オブジェクトから5m以内ならタッチできますが、それより距離があるとタッチしたことになりません。
適切な距離からオブジェクトにタッチすると、リンクメッセージ"action"が送信されます。
このリンクメッセージはドアのメインモジュールで受信され、最終的にドアの開閉が行われます。
遠い位置からのタッチを無効にすることで、ドア開閉の動きはより自然になるはずです(ドアの側にいないのにタッチして開けられるのは不自然ですのでw)。

さて。

もう一つイベントモジュールを作りましょう。
インベントリのお好みの位置に新しいスクリプトを作成し、"group touch module"という名前を付けて下さい。

group touch module
float distance = 5.0;

default {
  touch_start(integer detected){
    if (llVecDist(llGetPos(), llDetectedPos(0)) <= distance ){
      if (llSameGroup(llDetectedKey(0))){
        llMessageLinked(LINK_SET,-1,"action",llDetectedKey(0));
      }else{
        llInstantMessage(llDetectedKey(0), "Group member only.");
      }
    }else{
      llInstantMessage(llDetectedKey(0), "There is out of your reach. You can't touch. ");
    }
  }
}

ほとんどショート・タッチと一緒ですが、グループ判定を付け加えてみました。
オブジェクトと同一グループをアクティブにしていないと反応しません。
グループメンバーが適切な距離からオブジェクトにタッチすると、リンクメッセージ"action"が送信されます。
そしてドアメインモジュールを経由し、ドアの開閉が行われることになります。

2つのイベントモジュールを載せましたが、どちらを使うかは用途に応じて選択すればOKです。
さらには、もっと他のモジュールを用意しても構いません。

必要なことは、
1、イベントモジュールはリンクメッセージ"action"を送信する
2、ロジックモジュールはリンクメッセージ"door"を受信して動く
この2点です。

さらに詳しく書くなら、リンクメッセージに指定する整数値と文字列は以下のような意味になります。
●イベントモジュールから送信するリンクメッセージ
整数値文字列意味
TRUE"action"ドアを開く
FALSE"action"ドアを閉じる
-1"action"ドアが開いてれば閉じる、閉じていれば開く


●ロジックモジュールで受信するリンクメッセージ
整数値文字列意味
TRUE"door"ドアを開く
FALSE"door"ドアを閉じる


以上のルールを逸脱しなければ、どのようなモジュールを追加することも可能です。

拡張モジュール

では拡張してみましょう。

自動ドアに対応するため、センサーイベントを使ったイベントモジュールを追加してみます。
インベントリのお好みの位置に新しいスクリプトを作成し、"sensor module"という名前を付けて下さい。
せっかくですので、以前すくりぷたXさんがおっしゃっていた段階的な探知を実現してみましょう。

sensor module
default {
  state_entry(){
    llSensorRepeat("", "", AGENT, 15, PI, 10.0);
  }
  
  sensor(integer detected){
    state wait_level2;
  }
}

state wait_level2 {
  state_entry(){
    llSensorRepeat("", "", AGENT, 10, PI, 3.0);
  }
  
  sensor(integer detected){
    state wait_level3;
  }
  
  no_sensor(){
    state default;
  }
}  

state wait_level3 {
  state_entry(){
    llSensorRepeat("", "", AGENT, 5, PI, 0.25);
  }
  
  sensor(integer detected){
    state activate;
  }
  
  no_sensor(){
    state wait_level2;
  }
}  

state activate {
  state_entry(){
    llMessageLinked(LINK_SET,TRUE,"action",llDetectedKey(0));
    llSensorRepeat("", "", AGENT, 5, PI, 5.0);
  }
  
  no_sensor(){
    llMessageLinked(LINK_SET,FALSE,"action",llDetectedKey(0));
    state wait_level3;
  }
}

遠距離・長間隔の探知から近距離・短間隔の探知へと遷移していき、至近距離に入ったときにリンクメッセージTRUE,"action"を送信し、ドアを開きます。
逆に、至近距離に誰もいなくなったときにはリンクメッセージFALSE,"action"を送り、ドアを閉じます。

これで自動ドアも作れるようになりました。
ショートタッチやグループタッチの代わりにセンサーモジュールを使えば、そのまま自動ドアになります。

ロジックモジュールも拡張してみましょう。
バリアのように、薄れて消えるタイプのドアを作ってみます。
インベントリのお好みの位置に新しいスクリプトを作成し、"phantom door module"という名前を付けて下さい。

phantom door module
float alpha_max = 0.5;
integer opened = FALSE;

default {
  state_entry(){
    llSetStatus(STATUS_PHANTOM, FALSE);
  }
  
  link_message(integer send, integer num, string str, key id){
    if (str == "door"){
      if (num){
        if (!opened){
          float a;
          // open
          for (a = alpha_max; a > 0.0; a -= 0.05){
            llSetAlpha(a, ALL_SIDES);
            llSleep(0.05);
          }
          llSetAlpha(0.0, ALL_SIDES);
          llSetStatus(STATUS_PHANTOM, TRUE);
          opened = TRUE;
        }
      } else {
        if (opened){
          float a;
          // close
          for (a = 0.0; a < alpha_max; a += 0.05){
            llSetAlpha(a, ALL_SIDES);
            llSleep(0.05);
          }
          llSetAlpha(alpha_max, ALL_SIDES);
          llSetStatus(STATUS_PHANTOM, FALSE);
          opened = FALSE;
        }
      }
    }
  }
}

このモジュールはドアを透明にし、ファントム化(幻影)にします。
閉じるときは半透明(先頭の変数alpha_maxに定義した透明度)になります。
開閉のきっかけはリンクメッセージ"door"ですので、スライドドアやスタンダードドアの代わりとしてそのまま使えます。

さて。

以上でスクリプトを合計7本、載せました。
今回載せたスクリプトによって、何種類のドアが作れるでしょうか?

イベントモジュール、メインモジュール、ロジックモジュールの3つを組み合わせて使いますが、組み合わせは以下の通りです。
Noイベントメインロジックドアの機能
1short touchmainslideタッチするとスライドして開くドア
2short touchmainstandardタッチすると回転して開くドア
3short touchmainphantomタッチすると透明になるドア
4group touchmainslideスライドして開くグループ専用ドア
5group touchmainstandard回転して開くグループ専用ドア
6group touchmainphantom透明になるグループ専用ドア
7sensormainslideスライドして開く自動ドア
8sensormainstandard回転して開く自動ドア
9sensormainphantom透明になる自動ドア


全部で9種類のドアが実現可能であることがおわかりいただけるかと思います。
スクリプトは7種類しか書いていないのに、9種類の機能が実現できる、これがモジュール化の利点です。
イベントモジュールやロジックモジュールを追加するたびに実現可能なドアは増えます。
例えば、イベント・ロジックともにもう一つずつ追加すると、スクリプトの数は9個で、作れるドアは4×4の16種類になります。かなりのお得感♪

まぁ、今回取り上げたのはドアですから、わざわざモジュール化しなくてもどれも簡単に作れるだろうとは思います。
しかし、より複雑なものを作るにあたり、モジュール化を念頭にして作っていくのと、ひたすら一つのスクリプトとして組み上げるのでは、後々の効率が大きく異なってきます。
例えば、今回作ったイベントモジュールなどは他のものを作るときにも流用可能なはずです。

仲間と一緒に複雑なシステムを組み上げるなんていうときにも便利です。
リンクメッセージでやり取りする内容さえ決めておけば、あとはそれぞれに分業が可能になりますので。

一つのスクリプトのサイズ上限を克服するための小細工が、ここまでくると実に有用な開発手法であることがお分かりいただけるかと思います。
なんでもかんでもモジュール化すれば良いとは言いませんけども(^^;

モジュール化のデメリット

良いところばかり挙げて問題点に触れないわけにもいきませんので補足しておきます。

一つのLSLモジュールは16kのサイズであると、最初に書きました。
逆説的に言うなら、モジュールを1つ作ると16kのサーバーリソースを消費する、とも言えます。

モジュール化が便利だからといって何でもかんでも分割していたら、トータルのサイズはどんどん大きくなっていきますので、一概にメリットばかりではなくなってきます。

また、モジュール間のやりとりにはリンクメッセージを使っていますが、同一prim内のスクリプトが増加すると、一度のリンクメッセージでそれらが一斉に反応することになります。
listenなどに比べれば負荷は軽いとは言え、数が増せばそれなりに重くなっていくのは確かです。

最も良いのは、各モジュールを16k単位に分割することです。
ぴったり分けるのは困難ですから、可能な範囲でモジュールを一つにまとめ、なるべく無駄のない形に仕上げることが最良の道になります。

例えば、一つのスクリプトで済むところを4つも5つものモジュールにするというのは少々安易です。
バランスの問題になりますので、難しいところではありますが。




同じカテゴリー(スクリプト小技)の記事画像
リモートロード
同じカテゴリー(スクリプト小技)の記事
 高度なカメラ制御 (2007-07-19 12:15)
 リモートロード (2007-05-29 18:02)
 Emailの送受信 (2007-05-23 15:18)
 鍵をかける (2007-05-10 16:24)
 パーティクル (2007-04-09 17:07)
 lslで日本語を使う (2007-04-06 14:21)
この記事へのコメント
ちょうどモジュール化の必要性を感じて、試行錯誤してたところでした
ありがとうございます!

Mizさんみたいに影響力のある人が
こうやって系統立てて説明してくださると
デファクトスタンダードが出来上って
誰でも共有できるようになったりして^^
Posted by Jvn Writer at 2007年09月04日 14:29
>Jvn Writerさん

そうですねぇ、リンクメッセージの使い方が共有化されると、いろんな人がいろんな部品を作れるようになって、LSL拡張ライブラリみたいなものが出来るかもしれませんね。

そうなると1からスクリプトを覚えなくても、部品の組み合わせだけで基本的なものは作れるようになったりするので、スクリプトの敷居は下がるかもしれません。
Posted by MizMiz at 2007年09月08日 13:18
1KB=1000Bなのか、1024Bなのかは議論の余地があると思いますが、
プリムのDescriptionを使って戻り値を返すとか、モジュール化を助ける手段はいくつかありますね(^^)
Posted by march at 2007年09月13日 20:06
こんにちは!すごく参考になりました。今、ソフトバンクのシムにあるような、チャットに反応して開く扉を作っているのですが、スクリプト自体SLが初めてなので、うまくできません。どんなスクリプトを使えばいいんでしょうか?
Posted by suzuki at 2007年09月14日 19:22
>suzukiさん

すみません、コメント見落としておりました(><;

チャットに反応する仕組み自体はlistenという機能を使います。
「初級スクリプト」カテゴリの「聞き耳をたてる」の記事を参考にしてみて下さい。

扉の仕組みはこの記事の中にいくつかサンプルがありますので、ご参考になればと思います。

プログラミングの経験がないということなら、「基礎知識」カテゴリにごく基本的なところから説明を載せていますのでどうぞご利用下さい。
Posted by MizMiz at 2007年09月21日 11:42
いつも一方的にお世話になっております。
phantom door moduleを試してみたのですが、戻った時に半透明になってしまい、元の姿に戻らないようです。原因を教えていただければたすかります。
Posted by nyagos kidd at 2007年09月30日 21:37
>nyagos kiddさん

あ~、そうですね。
バリアみたいなものをイメージしていたので、閉じたときには半透明になるようなコードになってます。

ファントムドアモジュールの先頭行、
 float alpha_max = 0.5;
これが閉じたときの透明度ですので、ここを1.0にすると完全不透明になります。
Posted by MizMiz at 2007年10月02日 10:00
通りすがりで失礼します。
スクリプトど素人でコピペするだけしか脳がないのですが、
思い通りのドア(グループ専用で上方にスライド)を作ることができました。

いや、もう感動です...。
他にもいろいろと参考にさせていただきます。
本当にありがとうございました。
Posted by 感動 at 2007年11月15日 00:07
 ドアが閉まるまで、ドアの所へ居座ると、反応しなくなってしまいますが、
なにか打開策ないでしょうか?
Posted by Backard Wylie at 2008年03月14日 06:04
>Backard Wylieさん

えーと、どのコードのことでしょうか。
記事中のコードを見直してみましたが、怪しそうな個所を見つけられませんでした。
どのモジュールをお使いですか?
Posted by Miz at 2008年03月14日 09:17
 使用させて頂いてるのは、

1.door main module ・・・ドアセットの上部に設置。

2.sensor module ・・・中空にしたオブジェクトにしてドアの外枠として使用。

3.slide door module ・・・2個使用して、両開きのスライドドアとして使用。

 私が作りたいドアは、両開きのスライドドアで、ドアに近ずくと自動で開閉する物が欲しいのです~^^


PS: よくよく考えると、苦情の様な投稿になっていて、ごめんなさい^^;
スクリプト初心者でして、どう書いて良いものかと、、、こんなんなっちゃいました>w<;;;
Posted by Backard Wylie at 2008年03月14日 09:56
>Backard Wylieさん

別に苦情だとは思ってませんので大丈夫です(^^

ドアの近くにいる場合、時間が経ってもドアは閉じないはずですが、それが閉じてしまうというところからして何か問題がありそうですね。

ちょいと調べてみますね。
Posted by Miz at 2008年03月14日 15:50
こんにちは

standard door moduleを使わせて頂いてますが
乗り物のような常に開く角度が変わるものには
このままじゃ無理でしょうか?

ドアの角度変わってもが乗り物の後方へ開閉する方法はあるのでしょうか?

よろしくお願いします
Posted by まい at 2008年03月26日 17:46
>まいさん

この記事のサンプルコードではllSet/GetLocalRotを使っているので、乗り物本体(ルートプリム)に対しての回転になります。
従ってまいさんの意図しているところは問題なく動作するんじゃないかと思いますが・・・質問の意図を取り違えていたらごめんなさい(^^;

例えば、90度の角度で跳ね上がる車のボンネットがあるとして、車が右を向いていようが左を向いていようが、はたまたひっくり返っていようが、車の本体に対するボンネットの角度は常に90度のはずですよね?

試してみて、意図していることと違うようでしたらまたご質問下さい。
Posted by Miz at 2008年03月27日 14:24
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。