ソラマメブログ

2007年05月10日

鍵をかける

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

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

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

また、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文に手を加えてやれば、グループメンバーが自由にロック/アンロックできるドアなども出来ます。


同じカテゴリー(スクリプト小技)の記事画像
リモートロード
同じカテゴリー(スクリプト小技)の記事
 モジュール化 (2007-09-04 12:15)
 高度なカメラ制御 (2007-07-19 12:15)
 リモートロード (2007-05-29 18:02)
 Emailの送受信 (2007-05-23 15:18)
 パーティクル (2007-04-09 17:07)
 lslで日本語を使う (2007-04-06 14:21)
この記事へのトラックバック
【ドアとスライドする窓を作る】の続き(?) 今度はドアは私(オーナー)だけ、開けられるように鍵をかけたりしようかぁ。それともこの間「朱雀 01マーケット&ガレージセール」でチ...
ドアに鍵をかける【Konp KobaのSecond Life 雑記帳】at 2007年05月11日 00:36
この記事へのコメント
こんばんは。^^

さっそくの応答ありがとうございます。

すぐには理解できないのでじっくりと取り組んでみたいと思います。

それにしてもこんなに丁寧に応答して頂けるとうれしいです。

ありがとうございました。

では失礼します。
Posted by やも at 2007年05月10日 21:50
こんばんは

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


偶然他の方が私と同じように更衣室を使っていたので、「ALT押しながら左クリックしてドラッグする」を試してみました。

壁にわずかでも隙間があればほんとですね見えてしまいますねー。^^;

壁のつなぎ目を重複させれば覗かれないってことなのかな?<試してから書き込めばよかったと後悔してます。


では、失礼します。
Posted by や at 2007年05月10日 23:00
カメラの稼動範囲はおおよそ50M
つまり四方八方50M以上空けるか埋めた中に部屋を作ればいいかな?
Posted by 通りすがり at 2007年05月10日 23:07
コメントは初めてですが、lslを組む時こちらのブログを参考にさせていただいております。
個人的には「いつもお世話になっています!」という感じです。
先日こちらのブログを参考にドアを作ったので、今日は鍵のかかるドアや更衣室のスクリプトを研究してみようかなぁと思っていたら、答えが載っていました^^
また参考にさせていただきます。
Posted by Konp Koba at 2007年05月10日 23:07
>やもさん

ご参考になれば幸いです(^^
つなぎ目を重ねても、ぐりぐり回すと見えちゃいますね(^^;

>通りすがりさん

前に公式フォーラムで、「完璧なプライバシーを得るには?」という話題で、
「立ち入り禁止に設定した広大な土地の真ん中に家を作れ」なんて話が冗談っぽく語られましたが、まさにそんな感じですよね(^^;
セキュリティに自信があるというラブホテルではどんな手法を用いているのか・・・気になります。

>Konp Kobaさん

ちょうど良かったようで(^^
やっぱり鍵のかかるドアって需要あるんですねぇ。
Posted by Miz at 2007年05月11日 09:51
> やっぱり鍵のかかるドアって需要あるんですねぇ。
「更衣室」に関して言えば、先のコメントで書いたチャットでは、「服屋はいっぱいあるのに、それに比べて着替えられる場所が少ない・・・」という感じでした。
「人前で裸になっちゃいかん」というのもありますしね。
Posted by Konp Koba at 2007年05月12日 00:38
こんばんは。

オーナーだけが開けるスクリプトをコピーして張り付けたら保存時に
(3,0) : ERROR : Syntax error
と表示されます。

default {

の所のようですが特に問題になるとは思えないのですが一応下記の様にしてみました。

default
{

これでもだめでした。

なにが悪さしているんでしょう?

ご教授のほど、よろしくお願いします。
Posted by やも at 2007年05月12日 02:18
>やもさん

それはもしかしたらSLのスクリプトエディタがバグってるかもしれません。
時々コードに問題ないのにエラーと判断されることがあります。
どうも「目に見えない変な文字」が混入されている状況のようですが、たまに発生しますね。

その場合は新しいスクリプトを作り、コードを書き直すと無事に動いたりします。
Posted by Miz at 2007年05月14日 10:39
>Mizさん&やもさん
横レス失礼します。

「操作できる人を限定する方法」と「ロックをかける」の2行目
vector open_rot = <0.0, 0.0, 90.0> の部分
最後に「;」セミコロンがぬけてますよ。
2行目の最後の「;」がぬけているので、「(3,0) : ERROR : Syntax error」のエラーが出ていると思われます。
Posted by Konp Koba at 2007年05月14日 11:51
こんばんは。^^

Mizさん、Konp Kobaさんレスありがとうございます。

おかげさまで動いてくれました。

いやー、どうしてかなーと数日悩んでしまいましたが意外な所に記述漏れが
あったんですね。^^;

それにしてもスクリプトって本当にエラーの出ている行以外でエラーが出ることがあるんですね。

また一つ勉強になりました、もう一度「ありがとうございます」といわせていただきます。

では、失礼します。
Posted by やも at 2007年05月14日 22:22
>Konp Kobaさん

あれ?昨日コメントしたつもりだったのですが・・・すみません、うまくできていなかったようです。
ご指摘ありがとうございます。
昨日の時点で修正させていただきました。

>やもさん

行末の「;」が無いということは、行がまだ終わってないということになるので、

vector open_rot = <0.0, 0.0, 90.0>
default {

この二行は、

vector open_rot = <0.0, 0.0, 90.0> default {

こう書いてあるのと同じだと解釈されます。

すると、「なんだ?defaultなんてのがいきなり出てきたぞ?」というわけで、「defaultのとこ、文法的に変だよ」というエラーのメッセージが出るのです。

ご迷惑をおかけしました。
Posted by Miz at 2007年05月15日 09:51
こんばんは。

なるほど、改行されていてもスクリプト的には一行として認識されるわけですね。

ご教授、ありがとうございます。

今後ともよろしくお願いします。
Posted by やも at 2007年05月15日 11:10
Miz さん、こんばんは
ASCII から出版された「セカンドライフの作り方」という本を買いました。
Miz さんが紹介されているのを見ました。

下のようなオーナーしか座れない椅子をこちらのサイトを参考にスクリプトを作りました。今、このスクリプトを変更してグループだけしか座れない椅子を作ろうとしているのですができません。1週間ほど悩んでいます。

llDetectedGroup関数が座った時のchanged イベントで反応しないのでどうしたらよいかと......
逆にtouch_startイベントで座らせる方法がないかと調べてもみました。
それもだめです。touch_startイベントならllDetectedGroup関数が使用できますもんね。

座った時にグループユーザかどうか判別する方法がもしあればお教え下さい。よろしくお願いします。^^


// -------------------------------------------
default
{
state_entry()
{
llSitTarget(<0.0, 0.0, 0.5>, ZERO_ROTATION);
}

changed(integer change)
{
if (change & CHANGED_LINK)
{
key avatar = llAvatarOnSitTarget();
if (avatar != NULL_KEY && avatar != llGetOwner())
{
llSay(0,"You are not Owner");
llUnSit(avatar);
}
else
{
llSay(0,"You are Owner");
}
}
}
}
// -------------------------------------------
Posted by サトル at 2007年07月31日 19:00
>サトルさん

llSameGroup関数というのがあります。
UUIDで指定した対象がオブジェクトと同じグループかどうかを判定する関数です。

if ( llSameGroup(avatar) == FALSE )

のようにしてやれば、avatarがオブジェクトと同一グループではないときの判定になります。

使ってみて下さい。
Posted by Miz at 2007年07月31日 20:08
Miz さん、ありがとうございます。
てっきり llSameGroup もタッチ系のイベントでしか動作しないものかと思っていました。 僕バカですね。 この1週間、何をやっていたのやら(笑)
ほんと、ありがとうございました ^^
Posted by サトル at 2007年07月31日 21:06
はじめまして。
最近SLをはじめたばかりの初心者です。
スクリプトを勉強しようと思い入門本を買いました。

その後、ここのページに来てビックリです。
自分の持ってる本より、ずっとわかりやすく丁寧に解説されているので・・。
さらにリファレンスまで・・。
すばらしいサイトですね。ささやかながら応援させてください。

まだ初心者なのですが、素朴な質問をさせてもらってもいいでしょうか。

この鍵をかけるスクリプトのように、動作をチェックするのに
2人以上のアバターが必要なものを作るときは一体どーやってるんでしょうか?

アカウントを2つ用意しようかと思ったんですが
セカンドライフは同時にひとつしか起動しないので・・

あまりスクリプトとは関係がないですけど
よろしければ教えていただけると嬉しいです。
Posted by joju at 2007年08月24日 12:36
>jojuさん

通常、テストの際はお友達などに手を貸してもらうのが良いと思います。

セカンドライフは複数同時起動も可能ではありますが(ひょっとしたら今は出来ないかもしれません(^^;)、アカウントを二つ作るとなると、追加アカウントには料金がかかったと思います。
料金を払わずに複数アカウントを所持することは、規約違反になるはずですのでオススメできません。
Posted by MizMiz at 2007年08月24日 14:56
迅速なお返事ありがとうございます。

複数起動可能なら非常に嬉しいです。
もちろん追加アカウントを作るときは料金を払います^^

ただ、自分のマシンではセカンドライフが立ち上がってる状態で
もうひとつ実行しようとするとエラーがでます。
なにかオプション設定をしなければいけないということなんでしょうか?
Posted by joju at 2007年08月25日 04:24
はじめまして。

こちらのロックをかけることのできるドアスクリプトを参考にドアをつくってみました。ドア自体は問題ないのですがドアと周りの建物をリンクしてドアを開けるとドアが最初の設定値からずれてしまいます。
リンクの仕方が悪いんでしょうか?

お時間のあるときでよろしいのでぜひ教えてください。
よろしくお願いします。
Posted by hsr at 2007年08月27日 01:06
>jojuさん

はい、オプション設定が必要です。
私はWindowsしかわかりませんが、セカンドライフを起動するためのショートカットを右クリックし、「プロパティ」を開きます。
そして「リンク先」の欄の最後に、"-multiple"を付け足します。
「"C:\ProgramFiles\SecondLife\SecondLife.exe" -multiple」
のようになります(インストールした位置によって前半は異なります)。
「OK」を押してプロパティを保存すれば、以後そのショートカットから起動したセカンドライフクライアントは複数立ち上げられるようになります。

ただし、最新のクライアントで複数起動できるかどうかは確認してません。

>hsrさん

ドアを開けるときに使っているllSetRotという関数は、リンクされたオブジェクトの子プリム/親プリムによって動作が変わってきます。
ドアをリンクせずに使うのが最も解りやすいと思いますが、どうしてもリンクが必要でしたら、llSetRot/llGetRotではなくllSetLocalRot/llGetLocalRotを使わないといけません。
Posted by MizMiz at 2007年08月27日 12:06
おお!できました。
ありがとうございます!!
Posted by joju at 2007年08月28日 14:16
>jojuさん

クライアントの複数起動は激重になると思いますので、あまり使えないとは思いますが、ひとまず起動できたようでなによりです。
Posted by MizMiz at 2007年08月29日 09:06
スクリプト以外もサポートしてるのかw
すごいな、Miz!
Posted by もここ at 2007年08月29日 11:23
>もここさん

わかることだったので答えましたが、わからないことは答えられません(^^;
そして、わからないことのほうが多いですw
Posted by MizMiz at 2007年08月29日 11:47
mizさん。教えていただいたとおりにやってみたらできました。
ありがとうございました。
お返事遅れてすみませんー
Posted by hsr at 2007年08月31日 00:22
家の鍵をつけたい方ありまして、second lifeでも鍵ってつけられるのかな?と思ってさがしていました。たすかりました。私の次にたてる家にもつ
けてみたいとおもいます。貴重な記事でした。
Posted by kotorin little at 2007年09月13日 09:47
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。