鍵をかける

Miz

2007年05月10日 16:24


やもさんより質問いただいたスクリプトについて解説です。

やもさんからの質問
最近自分で服を作るようになり試着の為の更衣室を用意したのですが
ドアに鍵をかけるか、自分にしか開けられないドアするにはどのようにしたら良いのでしょうか?

これって結構ニーズのある話だと思います。
着替えの最中は裸になることも多く、やはり人に見られたくない場合がありますので・・・。

また、Kirさんからも関連のある質問をいただきました。

Kirさんからの質問
なんとか、オーナー限定にて動作するように改良したいのですが、

if (llDetectedKey(0) == llGetOwner()){
handle=llListen(channel, "", llGetOwner(), "");
これでしょうか?

あわせて見ていきましょう。
しかしながら・・・実態

実際には「人に見られることのない場所」を作るのは結構大変だったりします。
というのも、SLではかなり自由なカメラのコントロールが利きますので、建物をALT押しながら左クリックしてドラッグすると、簡単に内部を覗けてしまうんですね(^^;
たとえドアに鍵をかけたとしても、これを防ぐことはできません。

覗き見だけでなく、内部に侵入することも可能です。
カメラを動かして建物内部を見て、中の家具などにsitすると、強引に室内に押し入ることができたりします。
これを防ぐにはsitしたときの強制排除の仕組みを建物や家具に組み込んでおくしかありません。
あるいはllSitTaegetでsit位置を屋外に設定してしまうとかですね(^^;

完璧なセキュリティを考え始めると、かなり頭を使うことになります。
どこかのSIMに、セキュリティを売りにしているラブホテルがあるとか聞きましたが、そこも相当工夫をしているはずです。
現物を見てないのでどこまでセキュリティを実現しているのかはわかりませんが・・・。

以上のようなことを前提とした上で、他の人には開けられないドア及び鍵のかかるドアについて見てみましょう。

操作できる人を限定する方法

自分にしか開けられないドアを作るのは簡単です。
前にタッチして開くドアを作りましたが、そのスクリプトのタッチイベントにコードを追加し、オーナーがタッチしたときだけ反応するようにすればOKです。

※Konp Kobaさんから指摘ありました2行目の;を修正しました。
rotation rot;
vector open_rot = <0.0, 0.0, 90.0>;

default {
  state_entry()
  {
    rot = llGetRot();
    state close;
  }
}

state open {
  state_entry()
  {
    llSetRot(rot * llEuler2Rot(open_rot * DEG_TO_RAD));
    llSetTimerEvent(30.0);
  }
  
  touch_start(integer total_number){
    if (llDetectedKey(0) == llGetOwner()) { // タッチしたのがオーナーの場合のみ
      state close;
    }
  }

  timer(){
    llSetTimerEvent(0);
    state close;
  }
}

state close {
  state_entry(){
    llSetRot(rot);
  }

  touch_start(integer total_number){
    if (llDetectedKey(0) == llGetOwner()) { // タッチしたのがオーナーの場合のみ
      state open;
    }
  }
}

llDetectedKey(0)は「タッチした人のUUID」を得る関数でした。
llGetOwner()のほうは「オーナーのUUID」を得る関数ですので、これが等しい場合だけ反応するようにしておけば、オーナー以外には操作ができません。

ドアに限らず、「オーナーがタッチしたときにだけ動作するスクリプト」は、

touch_start(integer total_number){
  if (llDetectedKey(0) == llGetOwner()) {
    // オーナーがタッチしたときの処理
  } else {
    // オーナー以外がタッチしたときの処理
  }
}

このような書き方になります。
しばしば使う表現ですので、これはもう丸暗記でもいいかと思います。

この手法をもうちょい応用してみましょう。
オーナーだけでなく、同じグループの人が操作できるようにするには?

touch_start(integer total_number){
  if (llDetectedGroup(0) ) {
    // オブジェクトと同じグループの人がタッチした場合の処理
  } else {
    // オブジェクトと同じグループ以外の人がタッチした場合の処理
  }
}

llDetectedGroup関数は、オブジェクトのグループと同じアクティブグループかどうかを調べる関数です。

さらに応用して、スクリプトに操作を許可する人の名前を定義しておいて、その人以外には使えないようにするには、

list agents=["Miz Cremorne", "Hoge Hogera", "Honya Honyara"];
rotation rot;
vector open_rot = <0.0, 0.0, 90.0>;

(中略)

state open {
(中略)
  touch_start(integer total_number){
    if (llListFindList(agents, [llDetectedName(0)]) != -1) { // リストagentsに名前のある人のみ
      state close;
    }
  }
(以下略)

list型変数agentsに、タッチを許可する人の名前を列挙しておきます。
llListFindList関数はリストの中から指定した要素を探してそのインデックスを返す関数ですが、リストに無かった場合は-1を返します。
つまりリストに名前があるなら、-1以外の数字が返ってきます。
-1以外が返ってきた場合だけ、動作させればOKですね。

ここのところを逆に-1のときだけ動作するようにすると、

  if (llListFindList(agents, [llDetectedName(0)]) == -1) { // リストagentsに名前のない人のみ
    // 処理
  }

BANのように、リストに名前のある人には動かすことのできないスクリプトになります。

ロックをかける

鍵をかける仕組みは「操作できる人を限定する方法」の応用に過ぎません。
上で紹介したものはどれも「操作できる人」をあらかじめ限定していましたが、ロックしていないときは誰でも操作できて、ロックしたときだけ「操作できる人」が限定されれば良いですね。

rotation rot;
vector open_rot = <0.0, 0.0, 90.0>;
key lock=NULL_KEY;
integer counter=0;

default {
  state_entry()
  {
    rot = llGetRot();
    state close;
  }
}

state open {
  state_entry()
  {
    llSetRot(rot * llEuler2Rot(open_rot * DEG_TO_RAD));
    llSetTimerEvent(30.0);
    lock = NULL_KEY; // ロック解除
  }
  
  touch_start(integer total_number){
    state close;
  }

  timer(){
    llSetTimerEvent(0);
    state close;
  }
}

state close {
  state_entry(){
    llSetRot(rot);
  }

  touch_start(integer detected){
    counter=0;
  }


  touch(integer detected){
    if (llDetectedKey(0) == llGetOwner()){ // ロックできるのはオーナーだけ
      if (counter < 50){
        counter ++;
      }else if (counter == 50){
        counter ++;
        if (lock == NULL_KEY){
          lock = llDetectedKey(0); // ロック
        } else {
          lock = NULL_KEY; // アンロック
        }
      }
    }
  }


  touch_end(integer total_number){
    if (lock == NULL_KEY){ // ロックがかかっていない場合
      state open;
    } else if (llDetectedKey(0) == lock) { // ロックをかけた人がタッチした場合
      if (counter < 50){
        state open;
      }
    }
  }

}

ステートopenのときには誰もが操作可能です。開いてるのですから、閉じるのはいくらでもできるわけです。
ステートcloseのときにロックの仕組みを追加しました。

しばらくドアをクリックしっ放しにするとロックがかかります。
touchイベントを使って「しばらくマウスボタンを押し続けたとき」の処理の仕方は色の変わるカツラを作ったときに使いました。
今回は「しばらくマウスボタンを押し続けたとき」に、ロックがかかっていなければロックし、ロックがかかっていればアンロックしています。

ロックがかかっているかどうかはkey型変数lockの中身で判断します。
lockがNULL_KEYの場合はロックがかかっていない状態です。
ロックがかかったときには、ロックした人のUUIDが変数lockに入ります。

ドアを開けることができるのは、
(1)ロックがかかっていない場合=lockがNULL_KEY
(2)ロックした人がタッチした場合=lockがllDetectedKey(0)と同じ
の2通りですので、touch_endイベントの中でそのように判断しています。

このスクリプトではロックできるのはオーナーだけにしていますが、touchイベントの中の最初のif文に手を加えてやれば、グループメンバーが自由にロック/アンロックできるドアなども出来ます。
スクリプト小技