ソラマメブログ
< 2008年08>
S M T W T F S
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Mail

2007年04月27日

瞬間ワープ はまりポイント



この間の1プリム椅子にscriptを組み込んで、
座ったとたんに別の位置へ一瞬でワープする装置に仕立て上げました。


この椅子は、これからたまにギャラリーに湧き出るはずです。
そちらの詳細はまた。

さて、SLでは一瞬で激しい位置の移動はできないはずなのに
(一瞬の移動の最高距離は10mだそうです)
ものすごい遠くへ一気に移動させられたことがあったので
さてどうやるのかなあ、と思っていたのですが、
Makapuさんのエントリーにそのものずばりのコードがあったので、参考にさせてもらいました。

自分が作ったコードはこのエントリーのお尻に。

さてさて、多少ながら、はまるポイントがありました。
まず、椅子が回転していた場合、座る位置調整がかなりややこしいこととなります。
1プリム椅子は90度横に回転しているのですが

その方向を間違いました。
見事にx軸(赤の矢印)が下向きになってます。
座るためのプリム作成の際はローカル座標系を
きちんと確認しながら作ると良いと思います。

さもないと、座る位置が


こうなったり、


こうなったりしますw

もうひとつ、llSetPrimitiveParamsを使ったプリムの位置移動は
ワールドの絶対座標だということです。
今の位置から100m上へ移動する場合などは
vector pos = <0,0,100> + llGetLocalPos();
のように今のポジションの位置を足してやる必要があります。

これをやらないとワープ先が


こうなりますw
びっくりです。(これは海底にでてしまったワケです。)

さて、一瞬移動のソースコードは
MoveUp(){
vector pos = TARGET_POS + llGetLocalPos();//abs pos
integer distance = (integer)(llVecDist(pos, llGetPos()) / 10.0) + 1;
list l = [ PRIM_POSITION, pos ];
integer i = 1;
while ( ( i = i << 1 ) < distance){
l = (l=[]) + l + l;
}
llSetPrimitiveParams( l + llList2List( l, (i - distance) << 1, i) );
}

こんな感じなのですが正直、ワケわかりません!

…でもがんばって調べました。

◆まず

l = (l=[]) + l + l;の部分、これは
lslwikiのListページによると
listに要素を追加する際に無駄にメモリを浪費しない方法のようです。
voodoo magic とよばれていますね。
ぶっちゃけl += l ;とおんなじです。
このコードのように、大きい配列を扱う際は
メモリを無駄にしない事も考慮すべきなのでしょう。
自分はl = l + l;と書いてしまいましたが、きちんと動作しました。


◆また、

一瞬でワープが完了するキモの部分ですが
どうやら裏技っぽい感じで、
通常何ステップにも時間をかけて分けて行われるはずの
llSetPrimitiveParamsを用いた位置移動が、
上記のように妙な形のlistを作成して引数にすると、
1ステップで処理が行われてしまう、という
サーバのバグを利用した方法な模様です。

やはりlslWikiに記述を見つけました。すごいなlslWiki。

原文書きます。
WarpPos is simply a method by which the 10m limit on non-physical movement can be avoided, by exploiting a glitch in llSetPrimitiveParams in which multiple parameters are executed in a single server frame.


と、すると(これは自分の解釈ですが)
いつかは直されてしまうかもしれないので、
デカプリム同様、利用した商品を作って売り物にしたりは
しないほうがよいと思います。
そうなったら大ハマリです。

まあ、この作例は遊びなのでこのまま使ってみます。


という事で一気に移動する椅子が完成したのでした。


移動直後の様子。
スカイボックスに移動するアイテムを作っていたんですね。


◆全ソースはこちら
※このソースを使う際の注意
椅子に座ると一瞬で移動し、そのまま待機になりますが、
椅子から立ち上がると、DISPOSE_TIME秒後に椅子が消えてなくなります
椅子がrezされてからTIMEOUT_SEC秒後にも消えてなくなります
消えてなくしたく無い人は、llDie();をコメントアウトしてください。

TARGET_POS、SIT_POS、V_ROTはそれぞれ
ワープ相対座標、椅子に座る位置(相対座標)、いすに座る角度(相対座標)です。
各自自分の値に書き換えてください。
integer debug = FALSE;
Trace(string s){
if(debug) llOwnerSay(s);
}
integer DISPOSE_TIME = 3;
integer TIMEOUT_SEC = 60;
vector TARGET_POS = <0,0,573>;
vector SIT_POS = <-1.0 ,0.2, -0.6>;
vector V_ROT = <0,180,135>;
key av = NULL_KEY;
Init(){
llSetSitText("warp");
rotation rot = llEuler2Rot(V_ROT*DEG_TO_RAD) * llGetLocalRot();
llSitTarget(SIT_POS, rot);//local pos
}
DisposeMe(){
llSetTimerEvent(0);
llDie();// プリムを消したくない人はこれをコメントアウト(削除)
}
MoveUp(){
vector pos = TARGET_POS + llGetLocalPos();//abs pos
integer distance = (integer)(llVecDist(pos, llGetPos()) / 10.0) + 1;
list l = [ PRIM_POSITION, pos ];
integer i = 1;
while ( ( i = i << 1 ) < distance){
l = l + l;// coding "l = (l=[]) + l +l" is better.
}
llSetPrimitiveParams( l + llList2List( l, (i - distance) << 1, i) );
}
default{
state_entry(){
Init();
}
on_rez(integer num){
if(num==1) Init();//when rez-ed by script,num could be not 0.
}
changed(integer ch){
if(ch & CHANGED_LINK){
av = llAvatarOnSitTarget();
if(av!=NULL_KEY){
state moving;
}
}
}
}
state moving{
state_entry(){
MoveUp();
llSetTimerEvent(TIMEOUT_SEC);
}
changed(integer ch){
if(ch & CHANGED_LINK){
av = llAvatarOnSitTarget();
if(av==NULL_KEY){
llSetTimerEvent(DISPOSE_TIME);
}
}
}
timer(){
DisposeMe();
}
}



この記事へのトラックバックURL