Blog written that Gonzo acts in Second Life, which is a 3D virtual space.
はい、こんにちは。わたくしです。今回も自分のための忘備録です。
こんなことがよくあります。タッチしたらある処理が始まる。
しかしその処理の途中で違う人がタッチしたら困る。 それが以下の例です。
===========================================
touch_start(integer x){
key id = llDetected(0);
string your_name = llKey2Name(id);
//処理
llSay(0,"お前の名前を当ててやろう");
llSleep(3.0);
llSay(0, "お前の名前はズバリ! 「" + your_name + "」でしょう~~");
}
===========================================
これはタッチした人のアバタ名を当てるスクリプトです。
ここで困ったことに//処理以下をしているときに違う人がオブジェクトにタッチしたら、
llDetectedKey(0)が違う人のUUIDになってしまいます。
なので最初にタッチした人の名前が返ってこなくなります。
これをどうにか防ぎたい。
後からタッチした人は無視できるようにしたい。
それが以下のやり方です。
後からタッチした人を無視する方法
===========================================
state_entry(){
list idlist = [];//idlistというのを作って最初は中身カラッポ
}
touch_start(integer x){
integer i;
for(i = 0; i>x; i++){//i>xの間、iを1づつ増やす。つまり永遠に増やし続ける
idlist += llDetectedKey(i);//タッチした人のUUIDリストを作りまくる
}
if(llDetectedKey(i) != llDetectedKey(0)){//タッチした人が最初の人(llDetectedKey(0))じゃなかったとき return;//以下の処理はしない
}
else if(llDetectedKey(i) == llDetectedKey(0)){//タッチした人が最初の人だったとき
key id = llDetected(0);//最初にタッチした人のUUIDを取得
string your_name = llKey2Name(id);//UUIDをstring型に変換
//処理
llSay(0,"お前の名前を当ててやろう");
llSleep(3.0);
llSay(0, "お前の名前はズバリ! 「" + your_name + "」でしょう~~");
llResetScript();//タッチした人が複数人いたらinteger iに数値が入っているので全てリセットする
}
}
===========================================
以上です。
つまりはタッチした人のリストを作って、
その人が0番目にタッチした人(=最初にタッチした人)じゃなかったらガン無視。
0番目にタッチした人(=最初にタッチした人)だったら
以下の処理を続けるというあんばいです。
これ、結構使えます。
こちらのブログもよろしくお願いします。 ブロガーの方のやつ
はい、こんにちは。わたくしです。
今回もわたくしによるわたくしのためだけの忘備録です。
llSetTimerEvent(float)という命令があります。
この命令が実行されるとtimer(){処理}イベントに突入します。
例えばllSetTimerEvent(10.0);と書くと10秒ごとにtimer(){処理}イベントが実行されます。
最初わたくしはこれはllSetTimerEventがすぐに発動されてその後10秒毎に timer(){処理}イベントが実行されるものだと思っていました。
しかしどうやら10秒経ってから発動されるようです。
10秒数えた後timer(){処理}が処理されるようです。
これがよく分かっていないポイントでした。
つまり、
====================
llSetTimerEvent(10.0);
timer(){ llOwnerSay(”あべし”);
}
====================
とあるとすると、まず10秒経たないと「あべし」と言ってくれません。
プログラムがllSetTimerEvent(10.0);に到達した時点では「あべし」とは言ってくれないのです。
10秒経って「あべし」、その後また10秒経って「あべし」と10秒毎に延々と「あべし」と言います。
またタイマーを切るにはllSetTimerEvent(0.0);のようにfloatの部分を0.0にすればOK。
だから以下のように書くと、
====================
llSetTimerEvent(10.0);
timer(){
llSetTimerEvent(0.0);
llOwnerSay(”あべし”);
} ====================
10秒後に「あべし」発言。
timer(){}に入るなりllSetTimerEvent(0.0);でタイマーを切るので一回のみの「あべし」発言でおしまい。
この1回きり発言を生かしたわたくしがよく使う例は ダイアログが出て10秒間何もボタンが押されなかったら「時間切れ~」というやつです。
以下に簡単な例を。
======================================================
touch_start(integer x){//タッチしたら以下の処理発動
integer handle = llListen(~);//聞き耳を立てさせて(もちろんチャンネルはダイアログのと同じにしとく)
llDialog(~);//ダイアログを出す
llSetTimerEvent(10.0);//10秒後に時間切れを知らせる発言をするためにタイマーセット
}
listen(~){//ダイアログのボタンが押されたときの処理
llSetTimerEvent(0.0);//負荷がかからないようにtimerを閉じる
llRemoveListen(handle);//負荷がかからないようにllListenを閉じる
処理
}
timer(){
llSetTimerEvent(0.0);//発言を1回だけにするためにタイマーを切る
llRemoveListen(handle);//負荷がかからないようにllListenを閉じる
llOwnerSay(”時間切れ~”);//時間切れを知らせる
}
======================================================
以上です。間違ってるかもしれないのでアテにしないでください。
こちらのブログもよろしくお願いします。 ブロガーの方のやつ
はい、こんにちは。わたくしです。
今回も例によって例のごとく、自分が忘れないようにするためのスクリプトの忘備録です。
ダイアログとリッスンについて書きます。
ダイアログとリッスンは同時に使われます。
最初、ダイアログになんでリッスンがくっついてくるのか分かりませんでした。
でも分かったことは、ダイアログのボタンを押すとオブジェクトがその内容を発言している、ということです。
発言したものを聞くのがllListen命令であり、それが実行されるとlistenイベントが起こるということです。
ダイアログの命令を見てみると、
llDialog(key id, string message, list buttons, integer chat_channel)となっています。
ダイアログを使うとこの()の中身をダイアログが発言します。
()の中身をそれぞれ見て見ましょう。
・key id 誰のSLビューアの画面上にダイアログを表示されるか
・string message ダイアログに表示される言葉
・list buttons ダイアログに表示されるボタンの名前
・integer chat_channel どのチャンネルでダイアログが発言するか 以上のような感じになります。
key idの部分はアバタのUUIDを書くことになりますが、そのアバタそれぞれのUUIDなんかどこにも表示されません。
ではどうするか?便利な命令が用意されています。
例えばタッチしたアバタのUUIDならllDetectedKey(0)と書けばOKです。
オブジェクトのオーナーならllGetOwner()と書けばOKです。
これでいちいちUUIDを打ち込まなくてもよくなります。
string messageの部分はダイアログに表示される文章、例えば「色を選んでくだされ。」などと書きます。
ここの部分には文字であるstring型を入れないといけないのでそのお約束として文章を""ではさみます。
list buttonsにはダイアログのボタンに表示される名前を書きます。
integer chat_channelにはダイアログがどのチャンネルでしゃべるかを自分で好きなのを勝手に選んで入れます。
integer型なので整数の数字を入れます。
125とか9813とかなんでもいいです。
TVとかラジオのチャンネルと同じ感覚です。
周りの他の人との混線を防ぐためにその都度乱数を発生させるという方法があります。
乱数発生にはllFrand()という命令を使います。
llFrand()はfloat型(小数点付きの数字)なのでそれを防ぐために整数(integer型)になおすといいです。
これにはllFloor()という命令を使います。
実際のやり方は llFloor(llFrand(512))などと書きます。
混線を防ぐためには llFloor(llFrand(512) + 6541)などと書きます。
これをすると0から512の範囲内の数字(整数)がランダムに決定されてそのランダムな数に6541が足されます。
こうすると0から512までの合計513個のランダムな数字にさらに6541なんていう数が足されることになるので混線するのをかなりの確立で防ぐことができると思います。
ちなみにチャンネル0は公共電波です。
すべての人が自動的に聞いているチャンネルが0なのです。
だからよく使うllSayはllSay(integer channel, string message)というつくりなのですが、
みんなに発言が聞こえるようにチャンネルの部分を0にして
llSay(0, "こにゃにゃちは")と書くことが多いのです。
ちなみに上に書いたようにllFloor(llFrand(512) + 6541)と書いたのは
公共チャンネルの0を使わないようにした工夫です。
llFloor(llFrand(512) )だけだと0から512までの数字をランダムで拾います。
0を避けるために後ろに+6541などという0以上の数値を足しているのです。
こうすればllFloor(llFrand(512) )の値が0だとしても後ろに正の数を足してるので
決して0チャンネルになることはありません。
さて次に聞くという命令のllListenを見ましょう。
llListen(integer channel, string name, key id, string msg)
・integer channel 聞き取るチャンネルです。
・string name 誰の発言を聞くかです。
・key id これも誰の発言を聞くかですが、こちらはUUID指定です。
・string msg 何という文章を聞くかです。
integer channnelですが、ダイアログの命令を聞きたければllDialogで指定したのと同じチャンネルを書けばOK。
string nameは誰の発言を聞くかなのでアバタとかオブジェクトの名前を書きます。
全てのアバタ、オブジェクトの発言を聞いてもいいっていう場合は""と書きます。
しかし全てのアバタ、オブジェクトの発言と言っても上のchannelでチャンネルを指定してるので、そのチャンネル以外のアバタ、オブジェクトの発言は聞こえないので安心です。
key idも誰の発言を聞くかを書きます。
string nameと違ってこっちはUUIDでの指定になります。
全てのアバタ、オブジェクトの発言を聞くにはNULL_KEYというのを書いとけばOKです。
これもチャンネル指定されてるのでstring nameのときと同じようにそのチャンネル以外のアバタ、オブジェクトの発言は聞こえないので安心です。
オブジェクトのオーナーのみの発言を聞くときはこれまた便利なllGetOwner()を書けばOKです。
string msgは何という文章を聞くかを書きます。
これもまた全ての発言を聞くには""を書けばOKです。
すべての発言を聞くといってもまたまたチャンネル指定されてるのでそのチャンネル以外の発言は聞かないので安心です。
さて、llListen命令がされたらlistenイベントが発生します。
listenイベントは以下のようになってます。
listen(integer ch, string name, key id, string msg){ 処理 }
意味はinteger chのチャンネルでstring nameさんまたはkey idさんのstring msgという発言を聞いたら {}内の処理をするということです。
「ダイアログのあるボタンを押したら」というのはstring msgの部分に入ってきます。
これが最初はよく分かりませんでした。
ダイアログのボタンを押したらっていう命令はなんなのかというのを以前は悩んでました。
ちなみにllListenは負荷が強いらしいのでどっかでllListenRemoveという命令を使って切らないといけないらしいです。
切り方はダイアログが出て30秒後に切るという方法などがいいようです。
簡単に書くと、
=======================================
touch(integer x){
integer handle = llListen(~);//リッスン開始
llDialog(~);//ダイアログの表示
llSetTimerEvent(30.0);//30秒ごとにタイマー発動
}
timer(){//タイマーが発動したら、
llSetTimerEvent(0.0);//タイマーを切る
llListenRemove(handle);//リッスンを切る
llSay(0, "時間切れじゃ!");//時間切れだと発言して知らせる
} =======================================
みたいな感じです。
こちらのブログもよろしくお願いします。 ブロガーの方のやつ
はい、こんにちは。わたくしです。
今回は自分がスクリプトを書く際によく使うものを忘れないように記述しとこうと思います。
ちなみにわたくしはプラグラムなんぞSL以外ではまったく使わないので一般の方がすでに知ってるだろうことしか書けません。あくまでの自分のための忘備録として書きます。
今回は2つの座標系についてです。
SLでは座標系が2つあります。
1.ワールド座標
これはsimの東西南北がxyz座標に対応しているものです。
2.ローカル座標
これはアバタやオブジェクトの上下左右がxyz座標に対応しているものです。
やっかいなのがこのローカル座標です。
ローカル座標ではアバタ(オブジェクト)の正面がx、左がy、上方がzです。
アバタやオブジェクトは向きを変えることで上下左右の方向も変わります。
ある位置のアバタが右へ向けばさっきまでの正面の方向も右に変わります。
だからややこしい。
しかし便利な命令が用意されています。
それが以下の3つ。
llRot2Fwd
llRot2Left
llRot2Up の3つです。
それぞれ上から順にアバタ(オブジェクト)の正面(x座標)の値を左側(y座標)の値を上方(z座標)の値の単位ベクトルを取得してくれます。
単位ベクトルは長さが1mのベクトルです。
つまりllRot2Fwd(llGetRot());と書けばいつでもアバタ(オブジェクト)の正面(x座標)の向きを取得してくれます。
単位ベクトルなので=<1,0,0>ですね。
llRot2Fwd(llGetRot());を書くことでアバタ(オブジェクト)がどの向きを向こうが、その正面がx座標になってくれるのです。
同様にllRot2Left(llGetRot());を書くことでアバタ(オブジェクト)がどの向きを向こうが、その左がy座標になってくれるのです。
便利だ。
これはわたくしが多用する命令llRezObjectを使うときにとても役に立ちます。
llRezObjectはオブジェクトからさらにオブジェクトを出す命令です。
llRezObject(string inventory, vector pos, vector vel, rotation rot, integer param)
・string inventory 出されるオブジェクトの名前
・vector pos どの位置に出すかの場所
・vector vel 出されるオブジェクトのスピード
・rotation rot 出されるオブジェクトの角度
・integer param なぜか分からないけど1にしとけばいいらしいとなりますね。
ここで問題なのがvector posです。
これはワールド座標系での位置です。
このままだとオブジェクトを右に回転したときなど違う方向に回転したときでもこれをローカル座標にしてない限り、同じ方向にREZされてしまいます。
なのでここで上記のllRot2Fwdなどを使います。
llGetPos() + llRot2Fwd(llGetRot())としておけば、オブジェクトの今の位置プラスその正面方向の<1,0,0>の位置にREZしてくれます。
例として
タッチしたときにオブジェクトがどんな方向に向こうが必ず正面にREZされるスクリプト
を書きます。
============================================
default{
touch_start(integer x){
llRezObject("hana",
llGetPos() + llRot2Fwd(llGetRot()),
llRot2Fwd(llGetRot())*30,
ZERO_VECTOR,
1);
}
}
============================================
【追記】 vector velは出されるオブジェクトの速度で物理オブジェクトのときのみ有効。
ベクター値なのでllRot2Fwd(llGetRot())*30のように書く。
この場合、向きはアバタ(オブジェクト)の正面方向で大きさは<30,0,0>となる。
30の部分をいじって速度を変化させるといい。
こちらのブログもよろしくお願いします。 ブロガーの方のやつ
はい、こんにちは。わたくしです。
ものづくりをしているとよく攻撃されるので上空1000mで制作活動をすればいいのではないかと
SL始めて2年ほど経った今頃になり思いつきました。
で、プリムに座ったら上空1000mに瞬時に上れるようなスクリプトを考えました。
が、これってもしかして10mずつしか上れないのかな?
どんだけ数値いじっても10mまでしか上らない。
10m以下の数値ならその数値どおりに上ってくれる。
ネットで調べたら1000mまで上れるスクリプトを見つけたんだけど、
それ使ってみたらやっぱり10mずつ上っていく感じでした。
手っ取り早く、広さ10m四方のプリム作ってそれに座って、
ものづくりのタブの位置という欄のZの数値を1000mにしたらいいのかなとも思ったり;;
はい、こんにちは。わたくしです。
以前に誰かから聞いていた赤さんの売っているシムを偶然見つけました。
他のブログなどでは結構ここが紹介されていたようなのですが、わたくしは全く知りませんでした。
え~と右下の白い赤さん。。。
ドラキュラの赤さんなのでしょうか?
こうやって見ると同じ地球上でもいろんな人種がいますねぇ。
わたくしはアジア人なのですが、街で見かける外人さんってすごく大きいんですよね。
手足のパーツがでかくて体の構造がすでに違うっていう感じ。
赤さんのときってすでにこうした体格差って現れてるんでしょうか?
そういえば外人の赤さんを見たことないので分かりません。
この赤さんの場所は以下です。