そこで、リンク番号の取得ですが、プリム同士のリンクであれば、それぞれのプリムにスクリプトを入れ、リセット後のタイミングなどで llMessageLinked を使って子プリムのリンク番号をルートのスクリプトに渡すことで、リンク番号管理をしたりします。
llGetLinkNumber() を使って自分のリンク番号をとるわけです。
ここで問題になるのが、プリムにアバタ―が座った時のリンク番号です。ん?と思われるかもしれませんが、アバタ―がプリムに「座る」という行為は、アバタ―がルートプリムにリンクされた、というイベントで管理されるのです。
スクリプトでは CHANGE イベントの CHANGED_LINK を使って、アバタ―が座ったかどうかを管理しているのですね。
アバタ―には他の子プリムのようにスクリプトを入れることができません。座った後のアバタ―の位置や回転を操作するのは、リンクされた子プリムの位置と回転を操作するのと同様ですが、リンク番号の取得がプリムのようにできないのです。今回はその対応方法と、椅子に座ったアバタ―の位置や向きを変えるスクリプトを考えてみます。
5. アバタ―にスクリプトはいれられない
まぁ、、、既知、既出といえる比較的有名な話題になります。wiki にも紹介されていますし、過去にも多くの先輩諸氏がブログなどで紹介しているのですが、ポイントをまとめると
a) 多くの場合は CHANGE イベント発生時のリンク番号の最大値がアバタ―のリンク番号
b) 複数のアバタ―が座ったり立ったりする場合は、アバタ―のリンク番号は CHANGE イベントのたびに変わる可能性がある
上記の2つに注意してリンク番号を取得するサンプル スクリプトを書くと以下のようなものになります。
なお、一人しか座らせない場合は、llSitTarget と llAvatorOnSitTarget を使って、アバタ―の key の取得、llGetNumberOfPrims をリンク番号として扱うのが一番簡単です。このスクリプトはオブジェクトに複数のアバタ―が Sit する、という前提で、key や リンク番号などの情報を取得するサンプルになっています。
//--------------------------------------------------------------------------------
// Sit した複数のアバタ―のリンク番号や Key, 名前、ポジション、ローテーションを
// それぞれのリストに取得するサンプルスクリプト
//--------------------------------------------------------------------------------
list keyList; //Sit しているアバタ―の key をいれます
list nameList; //Sit しているアバタ―の名前をいれます
list posList; //Sit しているアバタ―のグローバルポジションを入れます
list rotList; //Sit しているアバタ―のグローバルローテーションを入れます
list numList; //Sit しているアバタ―のリンク番号をいれます
default{
state_entry(){
llSay(0, "Hello, Avatar!");
}
changed(integer change){
if(change & CHANGED_LINK){
integer max = llGetNumberOfPrims();
integer i = max;
keyList = nameList = posList = rotList = numList = [];
for(;i>0;--i){
list tmp = llGetLinkPrimitiveParams(i,[PRIM_NAME,PRIM_POSITION,PRIM_ROTATION]);
key tKey= llGetLinkKey(i);
list objDetails = llGetObjectDetails(tKey,[OBJECT_CREATOR]);
//OBJECT_CREATOR が NULL_KEY の場合はプリムではなくアバタ―です
key cKey = llList2Key(objDetails,0);
if(cKey==NULL_KEY){ //リンクされたものがアバタ―かどうかのチェック
//アバタ―だったら各情報をリストに格納します
tmp = llGetLinkPrimitiveParams(i,[PRIM_NAME,PRIM_POSITION,PRIM_ROTATION]);
keyList += tKey;
nameList+= llList2String(tmp,0);
posList += llList2Vector(tmp,1);
rotList += llList2Rot(tmp,2);
numList += [i];
}else{
i=0; //アバタ―じゃなくなったら、あとはリンクされたプリムなので終了
}
}
}
//アバタ―が座っていれば、その情報を確認用に表示
integer len = llGetListLength(keyList);
if(len>0){
integer i = 0;
for(;i<len;++i){
llOwnerSay(llList2String(numList,i)+","+
llList2String(nameList,i)+","+
llList2String(keyList,i)+","+
llList2String(posList,i)+","+
llList2String(rotList,i));
}
}else{
llOwnerSay("誰も座っていません。");
}
}
}
//------------------------------------------------------------------------
上記スクリプトの入った直方体に2人のアバターが Sit すると llOwnerSay で以下のようなメッセージをオーナーは受け取ることができます。
[00:28] Object: 2,Snuma Whitfield,d19d8aef-530a-41cc-bc1c-xxxxxxxxxxxx,<210.193100, 234.464900, 2498.686000>,<0.000000, 0.000000, 0.477574, 0.878592>
[00:28] Object: 3,Alt Beck,a45ad906-fa8e-4fe2-bb3d-xxxxxxxxxxxx,<210.193100, 236.036500, 2498.686000>,<0.000000, 0.000000, -0.934414, 0.356190>
リンク番号3番の Alt さんは一番最後に Sit したアバタ―なのですが、ここでリンク番号 2 番の私が立ち上がったとき、Alt さんのリンク番号がどうなるか。。。答えは 3番ではなく即座に2番になるのです。そのため、changed イベントが発生する毎に、アバタ―のリンク番号の再設定をしなくてはいけません。
リンク番号さえわかっていれば、あとはこれまでお話ししてきた設定方法を使って llSetLinkPrimitiveParams によるアバタ―の位置や回転の指定を行えばいいのです。
llSitTarget で指定するような初期の座る場所を指定したい、、などは上記の考えを拡張する(座った直後に移動させる)か、wiki の llSitTarget にある「着座ポイントを更新」などの応用をためしてみるといいでしょうね。
それでは複数のプリムからなる台座(オブジェクト)に、複数のアバターが座り、台座にタッチすることで表示されるダイアログで自分の位置を変える(前後、左右、上下、回転)、というスクリプトのサンプルが以下です。
ポイントは、
1) CHANGE イベント毎にアバターのリンク番号を更新する
2) ダイアログで移動させるときに、その時点での位置情報を取得し、使用する
3) グローバル座標による差をローカル座標上の差に変換する
4) アバターを回すときは、ルートのローテーションで2回除算する(または PRIM_ROT_LOCAL を使う)
5) llSitTarget と llAvatarOnSitTarget を使わず、座りたい場所にアバターを座らせ、微調整を可能にする
といったところでしょう。サンプル スクリプトとしてわかりやすくするために一部冗長なコードがあったり、情報確認用の llOwnerSay があったり、ダイアログの扱いについてもあまり汎用的にしていませんので、その辺は臨機応変に変更してみてください。