ソラマメブログ
[PR]Information






読者登録
メールアドレスを入力して登録する事で、このブログの新着エントリーをメールでお届けいたします。 解除は→こちら
現在の読者数 1人
オーナーへメッセージ

2007年07月30日

ペット


あひゃひゃひゃひゃ(≧∀≦*) 2週間ぶりの更新〜
最近ちょとスクリプト書く時間が取れたのでへろへろと書いてました。
SLでは需要がありそうでなさそうなペットのスクリプトです〜

ペットって言ってもいろいろありますが、
attach するだけして動かないのはスクリプト関係ないので却下〜。

今回作ったのは…
 ・空中に浮いてて
 ・特定の人物を追いかけたり
 ・ある程度の範囲を自由に動き回って
 ・その場に止まっていることもできて
 ・タイマーで勝手に消えてくれて
 ・そのペットに乗ることもできる
です〜。

というわけでまずはオブジェ作り


うん ハチです。足4つしかないけど。
やる気ないわけじゃないですよ。
センスが無いだけです ≧(´▽`)≦アハハハ


んで このハチの Content の中に…
 ・pet (←スクリプト)
 ・timeout (←スクリプト)
 ・pickup (←アニメーション)
の3つを用意します。

アニメーションはどんなのでもいいです。
座ったときに発動させるアニメーションなだけ〜。


スクリプトがかなり長くなってますが先に載せますね。(400 lineぐらい)
後ろの方に一応解説入れてます。スクリプト好きな方はどうぞ〜^^

これ流し込めば30プリム以下のオブジェだったら
それっぽく動きます〜。(向きの微調整が必要ですが…)
30プリム以下なのは物理属性じゃないと動いてくれないからです。
31プリム以上だと物理属性になってくれないのね〜。


petの中身


// -------------------------------------------------------------
//     Variable Declaration
// -------------------------------------------------------------
key      _OWNER;
string   _STATE;

list     _COMMANDS          = [  "come"    // follow owner
                               , "stay"    // stay at the place
                               , "free"    // move about freely
                               , "follow"  // follow someone
                               , "timeout" // set timeout
                              ];

integer  _COMMAND_HANDLE;
integer  _COMMAND_CHANNEL   = -9522;
float    _COMMAND_TIMEOUT   =  20.0;
string   _COMMAND_MESSAGE   = "Did you call?";

float    _SENSOR_RANGE      =  30.0;
float    _SENSOR_INTERVAL   =   2.0;
float    _VELOCITY          =   3.0;

integer  _TARGET_ID;
vector   _TARGET_POS;
float    _TARGET_MARGIN     =   0.1;
float    _TARGET_Z_ADJUST   =   2.5;

float    _FREE_RANGE        =  10.0;

string   _SIT_TEXT          = "Ride";
string   _SIT_ANIMATION     = "pickup";
vector   _SIT_POS           = <  0.7,  0.1, -0.7>;
vector   _SIT_ROT           = <  0.0,-90.0,  0.0>;
key      _SIT_KEY           = NULL_KEY; 

list     _FOLLOW_KEY;
list     _FOLLOW_NAME;
integer  _FOLLOW_HANDLE;
integer  _FOLLOW_CHANNEL    = -4579;
float    _FOLLOW_TIMEOUT    =  20.0;      // second
string   _FOLLOW_MESSAGE    = "Who should I follow?";

integer  _SEARCH_AV         = FALSE;
key      _SEARCH_KEY;

integer  _TIMEOUT_HANDLE;
integer  _TIMEOUT_CHANNEL   = -1039;
float    _TIMEOUT_TIMEOUT   =  20.0;
string   _TIMEOUT_MESSAGE   = "Please select the time.";

list     _TIMEOUT           = [    60      //  1 minuite
                               ,  300      //  5 minuite
                               ,  600      // 10 minuite
                               , 1800      // 30 minuite
                               , 3600      //  1 hour
                               ,    0      //  no limit
                              ];
list     _TIMEOUT_SELECT    = [  "1 min"
                               , "5 min"
                               , "10 min"
                               , "30 min"
                               , "1 hour"
                               , "no limit"
                              ];
string   _DEFAULT_TIMEOUT   = "10 min";



// -------------------------------------------------------------
//     Functions
// -------------------------------------------------------------
setTarget(key av, vector pos)
{
    _TARGET_POS = pos;
    if (_SIT_KEY == NULL_KEY) {
        if (av != NULL_KEY) {
            vector av_size = llGetAgentSize(av);
            _TARGET_POS -= < 0.0, 0.0, av_size.z / 2.0>;
        }
        _TARGET_POS += < 0.0, 0.0, _TARGET_Z_ADJUST>;
        _TARGET_POS += <  llFrand(2) * _TARGET_MARGIN - _TARGET_MARGIN
                        , llFrand(2) * _TARGET_MARGIN - _TARGET_MARGIN
                        , llFrand(2) * _TARGET_MARGIN - _TARGET_MARGIN
                       >;
    } else {
        vector root_pos = llGetRootPosition();
        float  root_z   = root_pos.z;
        _TARGET_POS     = <  _TARGET_POS.x
                           , _TARGET_POS.y
                           , root_z
                          >;
    }
        
}


move()
{
    vector current_pos = llGetPos();
    float  distance    = llVecDist(_TARGET_POS, current_pos);
    float  time        = distance / _VELOCITY;
    _TARGET_ID = llTarget(_TARGET_POS, _TARGET_MARGIN);
    llLookAt(_TARGET_POS, 0.5, 0.5);
    llMoveToTarget(_TARGET_POS, time);
}


setTimeout(string time)
{
    integer lim;
    if (time == "") {
        lim = llList2Integer(  _TIMEOUT
                             , llListFindList(  _TIMEOUT_SELECT
                                              , [_DEFAULT_TIMEOUT]
                                             )
                            );
    } else {
        lim = llList2Integer(  _TIMEOUT
                             , llListFindList(  _TIMEOUT_SELECT
                                              , [time]
                                             )
                            );
    }
    llMessageLinked(LINK_THIS, lim, "timeout", NULL_KEY);
}



init()
{
    llSetPrimitiveParams([PRIM_PHYSICS, FALSE]);
    llSitTarget(_SIT_POS, llEuler2Rot(_SIT_ROT * DEG_TO_RAD));
    llSetSitText(_SIT_TEXT);
    llSetBuoyancy(1.0);
    _OWNER       = llGetOwnerKey(llGetKey());
    _FOLLOW_KEY  = [];
    _FOLLOW_NAME = [];
    _STATE       = "";
    setTimeout("");
}



// -------------------------------------------------------------
//     Main Statement
// -------------------------------------------------------------
default
{
    on_rez(integer param)
    {
        llResetScript();
    }
    
    state_entry()
    {
        init();
    }
    
    touch_start(integer num_detected)
    {
        if (_OWNER == llDetectedKey(0)) {
            _COMMAND_HANDLE = llListen(  _COMMAND_CHANNEL
                                       , ""
                                       , _OWNER
                                       , ""
                                      );
                                     
            llDialog(  _OWNER
                     , _COMMAND_MESSAGE
                     , _COMMANDS
                     , _COMMAND_CHANNEL
                    );
            llSetTimerEvent(_COMMAND_TIMEOUT);
        }
    }
    
    listen(integer channel, string name, key id, string msg)
    {
        if (id == _OWNER && channel == _COMMAND_CHANNEL) {
        
            llSetPrimitiveParams([PRIM_PHYSICS, TRUE]);
            llListenRemove(_COMMAND_HANDLE);
            llSetTimerEvent(FALSE);
            llSensorRemove();
            
            _STATE = msg;
            
            if (_STATE == "come") {
                llSensorRepeat(  ""
                               , _OWNER
                               , AGENT
                               , _SENSOR_RANGE
                               , PI * 2
                               , _SENSOR_INTERVAL
                              );
            }
            
            if (_STATE == "stay") {
                llSetPrimitiveParams([PRIM_PHYSICS, FALSE]);
            }
            
            if (_STATE == "free") {
                llSensorRepeat(  ""
                               , _OWNER
                               , AGENT
                               , _SENSOR_RANGE
                               , PI * 2
                               , _SENSOR_INTERVAL
                              );
            }
            
            if (_STATE == "follow") {
                _SEARCH_AV = TRUE;
                llSensor(  ""
                         , NULL_KEY
                         , AGENT
                         , _SENSOR_RANGE
                         , PI * 2
                        );
            }
            
            if (_STATE == "timeout") {
                
                llSetPrimitiveParams([PRIM_PHYSICS, FALSE]);
                
                _TIMEOUT_HANDLE = llListen(  _TIMEOUT_CHANNEL
                                           , ""
                                           , _OWNER
                                           , ""
                                          );
                llDialog(  _OWNER
                         , _TIMEOUT_MESSAGE
                         , _TIMEOUT_SELECT
                         , _TIMEOUT_CHANNEL
                        );
                llSetTimerEvent(_TIMEOUT_TIMEOUT);
                        
            }
                
        }
        
        if (id == _OWNER && channel == _FOLLOW_CHANNEL) {
            
            _SEARCH_AV  = FALSE;
            
            _SEARCH_KEY = llList2Key(  _FOLLOW_KEY
                                     , llListFindList(_FOLLOW_NAME, [msg])
                                    );

            llSensorRepeat(  ""
                           , _SEARCH_KEY
                           , AGENT
                           , _SENSOR_RANGE
                           , PI * 2
                           , _SENSOR_INTERVAL
                          );  
        }
        
        if (id == _OWNER && channel == _TIMEOUT_CHANNEL) {
            setTimeout(msg);
        }
        
    }
    
    sensor(integer num_detected)
    {
        if (_STATE == "come") {
            setTarget(_OWNER, llDetectedPos(0));
            move();
        }
        
        if (_STATE == "free") {
            vector pos = llDetectedPos(0);
            float  omg = llFrand(1) * PI * 2;
            float  t_r = llFrand(1) * _FREE_RANGE;
            float  t_x = t_r * llCos(omg);
            float  t_y = t_r * llSin(omg);
            setTarget(NULL_KEY, pos + <t_x, t_y, 0.0>);
            move();
        }
        
        if (_STATE == "follow" && _SEARCH_AV) {
            
            integer i;
            string  str;
            
            _FOLLOW_KEY  = [];
            _FOLLOW_NAME = [];
            
            for (i = 0 ; i < num_detected ; i++) {
                
                _FOLLOW_KEY  += [llDetectedKey(i)];
                str           = llDetectedName(i);
                
                if (llStringLength(str) > 24) {
                    str = llGetSubString(str, 0, 23);
                }
                
                _FOLLOW_NAME += [str];
            }
            
            _FOLLOW_HANDLE = llListen(  _FOLLOW_CHANNEL
                                      , ""
                                      , _OWNER
                                      , ""
                                     );
                                     
            llDialog(  _OWNER
                     , _FOLLOW_MESSAGE
                     , _FOLLOW_NAME
                     , _FOLLOW_CHANNEL
                    );
                    
            llSetTimerEvent(_FOLLOW_TIMEOUT);
    
        }
        
        if (_STATE == "follow" && !_SEARCH_AV) {
            setTarget(_SEARCH_KEY, llDetectedPos(0));
            move();
        }
        
    }
    
    no_sensor()
    {
    }
    
    at_target(integer number, vector targetpos, vector ourpos)
    {
        
        llTargetRemove(_TARGET_ID);
        llStopMoveToTarget();
        
    }
    
    not_at_target()
    {
    }
    
    changed(integer change)
    {
        if (change & CHANGED_LINK) {
            key av = llAvatarOnSitTarget();
            if (_SIT_KEY != NULL_KEY) {
                if (av == NULL_KEY) {
                    llStopAnimation(_SIT_ANIMATION);
                    _SIT_KEY = NULL_KEY;
                }
            } else {
                if (av != NULL_KEY) {
                    _SIT_KEY = av;
                    llRequestPermissions(  _SIT_KEY
                                         , PERMISSION_TRIGGER_ANIMATION
                                        );
                }
            }
        }
    }

    run_time_permissions(integer perm) 
    {
        key perm_key = llGetPermissionsKey();
        if (perm_key == _SIT_KEY) {
            if (perm & PERMISSION_TRIGGER_ANIMATION) {
                list anms = llGetAnimationList(_SIT_KEY);
                integer i;
                for (i = 0 ; i < llGetListLength(anms) ; i++) {
                    llStopAnimation(llList2Key(anms, i));
                }
                llStartAnimation(_SIT_ANIMATION);
            }
        }
    }
    
    timer()
    {
        llListenRemove(_COMMAND_HANDLE);
        
        if (_STATE == "follow") {
            llListenRemove(_FOLLOW_HANDLE);
        }
        
        if (_STATE == "timeout") {
            llListenRemove(_TIMEOUT_HANDLE);
        }
        
        llSetTimerEvent(FALSE);
    }

}





timeout の中身



default
{
    on_rez(integer param)
    {
        llResetScript();
    }
    
    link_message(integer sender, integer num, string str, key id)
    {
        llSetTimerEvent(num);
    }
    
    timer()
    {
        llDie();
    }
}





んじゃ解説〜


簡単な timeout の中身から…



default
{
    on_rez(integer param)
    {
        llResetScript();
    }
    
    link_message(integer sender, integer num, string str, key id)
    {
        llSetTimerEvent(num);
    }
    
    timer()
    {
        llDie();
    }
}



見てお分かりの通りリンクメッセージを受け取って初めて発動することにしています。
発信するのは pet スクリプトからでして、num に秒数を入れて発信してます。
受け取った秒数をllSetTimerEventにあげて
その指定秒数後にllDieしちゃいます。
llDieは自分の Inventory に残らない削除の仕方なので
no copy のオブジェクトだと完全に消えちゃいますのでご注意を〜。



ほい 次は長ったらしい pet のスクリプト見てきます。
変数宣言(Variable Declaration)のところはどうでもいいですね。
いっぱいありますが、フィーリングでカバーしてください。

関数群(Functions)はでてきたら解説入れます〜。

というわけで本体(Main Statement)から…


// -------------------------------------------------------------
//     Main Statement
// -------------------------------------------------------------
default
{
    on_rez(integer param)
    {
        llResetScript();
    }
    
    state_entry()
    {
        init();
    }
    
...


on_rezはどうでもいいですね。リセットしてます。
state_entryは初期化する自作関数(init)を呼び出してます。


init()
{
    llSetPrimitiveParams([PRIM_PHYSICS, FALSE]);
    llSitTarget(_SIT_POS, llEuler2Rot(_SIT_ROT * DEG_TO_RAD));
    llSetSitText(_SIT_TEXT);
    llSetBuoyancy(1.0);
    _OWNER       = llGetOwnerKey(llGetKey());
    _FOLLOW_KEY  = [];
    _FOLLOW_NAME = [];
    _STATE       = "";
    setTimeout("");
}


いきなり物理属性にしてるとフラフラと動き回ってしまうので
llSetPrimitiveParamsで最初は非物理にしちゃいます。

あとは座る位置やらリストを初期化してますが、見慣れないllSetBuoyancyてのも入れてます。
こいつは浮力を設定する奴でして、引数を 0 にすると何も起きずに重力をそのまま受けます。
1 にすることで重力を相殺する力をオブジェクトに与え続けるもので、1 より大きくすると
どんどん上に昇って行っちゃいます。こいつは当然、物理属性のオブジェクトにしか効果ありませぬ。

で、最終行の setTimeout ですが、こいつも自作関数です。


setTimeout(string time)
{
    integer lim;
    if (time == "") {
        lim = llList2Integer(  _TIMEOUT
                             , llListFindList(  _TIMEOUT_SELECT
                                              , [_DEFAULT_TIMEOUT]
                                             )
                            );
    } else {
        lim = llList2Integer(  _TIMEOUT
                             , llListFindList(  _TIMEOUT_SELECT
                                              , [time]
                                             )
                            );
    }
    llMessageLinked(LINK_THIS, lim, "timeout", NULL_KEY);
}


タイマーをセットするのに引数が string なのは気にしないで〜。
引数が""のときにはデフォルトの時間(今回は10分)をセットしてます。
引数が""以外だと _TIMEOUT と _TIMEOUT_SELECT のリストから目的の
秒数を探してきます。SLにはハッシュ配列が無いのでこの辺の処理がだるだる〜 (-_-;ウーン

とまぁ、指定秒数を最後にllMessageLinkedを使って自分自身に投げています。
受け取れるのは pet スクリプトではなくて timeout スクリプトですね。
pet スクリプトは link_messageイベントを書いてませんので〜。



ほい んじゃ次


    touch_start(integer num_detected)
    {
        if (_OWNER == llDetectedKey(0)) {
            _COMMAND_HANDLE = llListen(  _COMMAND_CHANNEL
                                       , ""
                                       , _OWNER
                                       , ""
                                      );
                                     
            llDialog(  _OWNER
                     , _COMMAND_MESSAGE
                     , _COMMANDS
                     , _COMMAND_CHANNEL
                    );
            llSetTimerEvent(_COMMAND_TIMEOUT);
        }
    }


えと、オーナーがオブジェにタッチしたときにダイアログを出すだけです。
こんな感じですね。

・come
  オーナーに向かって飛んでくる
・stay
  その場でピタッと止まる
・free
  オーナーを中心にある一定距離(今回は10m)をフラフラ飛び回る
・follow
  近くに居る人(今回は30m以内)を探して、オーナーにダイアログで
  誰に向かって飛んで行けばいいかを選択する。んで、その人を追尾。
・timeout
  自分自身を削除する時間設定のダイアログを出す。

ダイアログから選択するとllDialogの第4引数のチャンネルで発言がされるので
その発言をlistenできるように事前にllListenでチャンネルを開いておきます。


というわけでlistenは…


    listen(integer channel, string name, key id, string msg)
    {
        if (id == _OWNER && channel == _COMMAND_CHANNEL) {
        
            llSetPrimitiveParams([PRIM_PHYSICS, TRUE]);
            llListenRemove(_COMMAND_HANDLE);
            llSetTimerEvent(FALSE);
            llSensorRemove();
            
            _STATE = msg;
            
            if (_STATE == "come") {
                llSensorRepeat(  ""
                               , _OWNER
                               , AGENT
                               , _SENSOR_RANGE
                               , PI * 2
                               , _SENSOR_INTERVAL
                              );
            }
            
            if (_STATE == "stay") {
                llSetPrimitiveParams([PRIM_PHYSICS, FALSE]);
            }
            
            if (_STATE == "free") {
                llSensorRepeat(  ""
                               , _OWNER
                               , AGENT
                               , _SENSOR_RANGE
                               , PI * 2
                               , _SENSOR_INTERVAL
                              );
            }
            
            if (_STATE == "follow") {
                _SEARCH_AV = TRUE;
                llSensor(  ""
                         , NULL_KEY
                         , AGENT
                         , _SENSOR_RANGE
                         , PI * 2
                        );
            }
            
            if (_STATE == "timeout") {
                
                llSetPrimitiveParams([PRIM_PHYSICS, FALSE]);
                
                _TIMEOUT_HANDLE = llListen(  _TIMEOUT_CHANNEL
                                           , ""
                                           , _OWNER
                                           , ""
                                          );
                llDialog(  _OWNER
                         , _TIMEOUT_MESSAGE
                         , _TIMEOUT_SELECT
                         , _TIMEOUT_CHANNEL
                        );
                llSetTimerEvent(_TIMEOUT_TIMEOUT);
                        
            }
                
        }
        
        if (id == _OWNER && channel == _FOLLOW_CHANNEL) {
            
            _SEARCH_AV  = FALSE;
            
            _SEARCH_KEY = llList2Key(  _FOLLOW_KEY
                                     , llListFindList(_FOLLOW_NAME, [msg])
                                    );

            llSensorRepeat(  ""
                           , _SEARCH_KEY
                           , AGENT
                           , _SENSOR_RANGE
                           , PI * 2
                           , _SENSOR_INTERVAL
                          );  
        }
        
        if (id == _OWNER && channel == _TIMEOUT_CHANNEL) {
            setTimeout(msg);
        }
        
    }


うん ぐだぐだ。( ̄~ ̄;)
選ばれた各行動によって処理を延々とifで振り分けてます。
注意が必要なのは follow と timeout のときで、こいつらは
行動選択のダイアログの次にさらにダイアログを出す必要があるので
sensorイベントとlistenイベントを行ったり来たりします。
なので変なフラグ立てを余儀なくされてます。
(stateを使ってもう少しきれいに書けばよかったかも〜(T-T)

followが選ばれたときの次のダイアログ
(自分1人しか居なかったのでボタンは一つ…だって引きこもりだもん)

まわりに人がいると、その人たちのNameとKeyを取得して
Nameをダイアログボタンに表示します。
(24文字より長いNameはエラーにならないように文字列処理が必要)

こっちは timeout が選ばれたときのダイアログ




ほぃ sensorイベントの中身もぐだぐだでっす。


    sensor(integer num_detected)
    {
        if (_STATE == "come") {
            setTarget(_OWNER, llDetectedPos(0));
            move();
        }
        
        if (_STATE == "free") {
            vector pos = llDetectedPos(0);
            float  omg = llFrand(1) * PI * 2;
            float  t_r = llFrand(1) * _FREE_RANGE;
            float  t_x = t_r * llCos(omg);
            float  t_y = t_r * llSin(omg);
            setTarget(NULL_KEY, pos + <t_x, t_y, 0.0>);
            move();
        }
        
        if (_STATE == "follow" && _SEARCH_AV) {
            
            integer i;
            string  str;
            
            _FOLLOW_KEY  = [];
            _FOLLOW_NAME = [];
            
            for (i = 0 ; i < num_detected ; i++) {
                
                _FOLLOW_KEY  += [llDetectedKey(i)];
                str           = llDetectedName(i);
                
                if (llStringLength(str) > 24) {
                    str = llGetSubString(str, 0, 23);
                }
                
                _FOLLOW_NAME += [str];
            }
            
            _FOLLOW_HANDLE = llListen(  _FOLLOW_CHANNEL
                                      , ""
                                      , _OWNER
                                      , ""
                                     );
                                     
            llDialog(  _OWNER
                     , _FOLLOW_MESSAGE
                     , _FOLLOW_NAME
                     , _FOLLOW_CHANNEL
                    );
                    
            llSetTimerEvent(_FOLLOW_TIMEOUT);
    
        }
        
        if (_STATE == "follow" && !_SEARCH_AV) {
            setTarget(_SEARCH_KEY, llDetectedPos(0));
            move();
        }
        
    }
    
    no_sensor()
    {
    }


llSensorRepeatで見つかった対象のKeyと位置を使って
自分自身が移動する先を決めて動きます。移動する先を決めるのは自作関数の setTarget で、
実際に動かすのはこれまた自作関数の move の中でやってます。


setTarget の中は…


setTarget(key av, vector pos)
{
    _TARGET_POS = pos;
    if (_SIT_KEY == NULL_KEY) {
        if (av != NULL_KEY) {
            vector av_size = llGetAgentSize(av);
            _TARGET_POS -= < 0.0, 0.0, av_size.z / 2.0>;
        }
        _TARGET_POS += < 0.0, 0.0, _TARGET_Z_ADJUST>;
        _TARGET_POS += <  llFrand(2) * _TARGET_MARGIN - _TARGET_MARGIN
                        , llFrand(2) * _TARGET_MARGIN - _TARGET_MARGIN
                        , llFrand(2) * _TARGET_MARGIN - _TARGET_MARGIN
                       >;
    } else {
        vector root_pos = llGetRootPosition();
        float  root_z   = root_pos.z;
        _TARGET_POS     = <  _TARGET_POS.x
                           , _TARGET_POS.y
                           , root_z
                          >;
    }
        
}


setTargetの第1引数は追尾対象のUUIDが入ります。
本当は第2引数の位置情報だけでハチは動かせるのですが
Z軸の調整のためにアバターのサイズを取得する必要があったからです。

最初のifはハチにSitしているかどうかで分岐してます。
これがないと対象がハチにSitしていると延々と上に昇ってしまうから
それを防ぐためにですね。対象がSitしているとZ値(=高度)を維持して
動きます。



move関数は…


move()
{
    vector current_pos = llGetPos();
    float  distance    = llVecDist(_TARGET_POS, current_pos);
    float  time        = distance / _VELOCITY;
    _TARGET_ID = llTarget(_TARGET_POS, _TARGET_MARGIN);
    llLookAt(_TARGET_POS, 0.5, 0.5);
    llMoveToTarget(_TARGET_POS, time);
}


llMoveToTargetで動かすだけです〜。
その前にllLookAtでハチの正面を対象に向けてます。



    at_target(integer number, vector targetpos, vector ourpos)
    {
        
        llTargetRemove(_TARGET_ID);
        llStopMoveToTarget();
        
    }
    
    not_at_target()
    {
    }


で、移動終了後の処理。止めてるだけ〜。


ほぃ、これでハチ自体の移動関係のところはしゅ〜りょ〜。
あとはハチそのものにSitしたときの処理です。
パーミッションのやり取りやらアニメーションのStart/Stopの
タイミングを工夫しないと変なことになります〜。
というわけで、Mizさんのとこのポーズボール(スクリプト初級第十四回)から
拝借させてもらいました。(^▽^)/お借りします〜


    changed(integer change)
    {
        if (change & CHANGED_LINK) {
            key av = llAvatarOnSitTarget();
            if (_SIT_KEY != NULL_KEY) {
                if (av == NULL_KEY) {
                    llStopAnimation(_SIT_ANIMATION);
                    _SIT_KEY = NULL_KEY;
                }
            } else {
                if (av != NULL_KEY) {
                    _SIT_KEY = av;
                    llRequestPermissions(  _SIT_KEY
                                         , PERMISSION_TRIGGER_ANIMATION
                                        );
                }
            }
        }
    }

    run_time_permissions(integer perm) 
    {
        key perm_key = llGetPermissionsKey();
        if (perm_key == _SIT_KEY) {
            if (perm & PERMISSION_TRIGGER_ANIMATION) {
                list anms = llGetAnimationList(_SIT_KEY);
                integer i;
                for (i = 0 ; i < llGetListLength(anms) ; i++) {
                    llStopAnimation(llList2Key(anms, i));
                }
                llStartAnimation(_SIT_ANIMATION);
            }
        }
    }


これで追尾もSitもできるペットの出来上がり〜 °゜°。。ヾ( ~▽~)ツ ワーイ♪


timerイベントはダイアログのチャンネルを
開けっ放しにしないようのストッパーです〜。
(SIMやら環境やら周りの人のことを考えてちゃんと閉じておきましょう〜)


    timer()
    {
        llListenRemove(_COMMAND_HANDLE);
        
        if (_STATE == "follow") {
            llListenRemove(_FOLLOW_HANDLE);
        }
        
        if (_STATE == "timeout") {
            llListenRemove(_TIMEOUT_HANDLE);
        }
        
        llSetTimerEvent(FALSE);
    }





そんなこんなで完成〜〜


で、ハチにSitしたときにアニメーション発動〜

ハチに連れ去られる河童 ((o(T^T)o))バタバタ

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

この記事へのコメント
をを。これはすごい。

スクリプトは勝手に使っていいんです?
ペットスクリプト欲しくて公式の掲示板とかも見てたんですけど、ここまでのはなかなかなくてー。
Posted by やぶ at 2007年07月30日 13:30
> やぶさん

コメントありがとございます〜
どうぞどうぞ〜ご自由に〜

オブジェのルートプリムの向きで微調整が
必要になると思いますが、適当にいじって
調整してくださ〜い。

近いうちに japan 01 のかっぱ池に
フル権限でフリーで置いときますので
それをお持ち帰り頂いても大ジョブです。

再販される場合もご連絡頂かなくても
大ジョブです。
著作権は放棄します ( 。・・)/⌒□ポイ
自己責任でお願いします〜〜。

って放棄できるものなのかな?
≧(´▽`)≦アハハハ
Posted by かっぱ at 2007年07月30日 13:57
いよっ、太っ腹
あたしも挑戦してみよっと
ありがとうございまーす
Posted by Hahik at 2007年07月31日 07:19
いや〜 責任が発生しないっていいですね〜
なんて自由な世界なんだ〜
あひゃひゃひゃひゃ(≧∀≦*)
Posted by かっぱ at 2007年07月31日 23:39
こんにちは☆
あしあとからお邪魔しました。

スクリプトすごいですね。
私はクリエイターではないので
こういうのをみるだけで頭が痛くなりそうです><
Posted by キララ at 2007年08月01日 00:58
使用報告デース
このスクリプト、すごいですw
なんでも飛行体にできてー
おまけに装着すれば、上昇ターボになりましたー(^o^)
天空が自由自在でーす
感謝、感謝 って、ペットの領域から離れていますけどw
こんど、あたしの作った「ぱぴっ(蝶々)」連れてかっぱ池に遊びに行きますねー
Posted by Hahik at 2007年08月02日 06:23
> キララてんちょーさん
こんにちわー^^
スクリプト慣れてないと確かにうねうねした
文字が並んでるだけですよね〜o(*^▽^*)oあはっ♪

かっぱはてんちょーさんみたいにマネジメントが
できないので逆に羨ましぃw


> Hahikさん
Σ( ̄ロ ̄|||)なんと!?
そうかぁ〜attachすると上昇し続けますね〜
試したこと無かったw ご報告ありがとございます〜
ぱぴっちゃんぜひぜひー
Posted by かっぱ at 2007年08月02日 13:20
早速スクリプト入れましたー。
ばっちり動作しました。
本当に感謝です!
Posted by やぶ at 2007年08月03日 11:10
> やぶさん

無事に組み込めたみたいですね〜
おめでとうございます〜!

さてさて次は何作ろ〜
(ΦωΦ)ふふふ・・・・
Posted by かっぱ at 2007年08月04日 00:04
素敵なスクリプトありがとうございます^^
このスクリプト、うまく作動しないものがあるんです(30プリム以内で)。

オブジェのリンクなどの関係があるのでしょうか・・・。

ダイアログはでるのですが、followにしても微妙に動くだけでついてきてくれません><
Posted by はちみつ at 2007年08月04日 01:16
素敵なスクリプトありがとうございます^^
このスクリプト、うまく作動しないものがあるんです(30プリム以内で)。

オブジェのリンクなどの関係があるのでしょうか・・・。

ダイアログはでるのですが、followにしても微妙に動くだけでついてきてくれません><
Posted by はちみつ at 2007年08月04日 01:29
> はちみつさん

こんばんわ〜
(○ ̄ 〜  ̄○;)ウーン・・・
なんだろ〜

微妙に動くということは多分その人をサーチはできていそうですね。
ということは…
 移動ができない=物理属性になってない
かな…。

そのペットの0.1m以内に違うオブジェクト/アバターがいると
物理になってくれませんが、それかも??

もしだめでしたら今ちょうど河童池に
いるのでどうぞ〜
http://slurl.com/secondlife/japan 01/190/21/30
見せて頂いて差し支えなければですが〜

今日はずっと朝まで作業してますので
ご遠慮なく〜^^
Posted by かっぱ at 2007年08月04日 01:36
ありがとうございました。
作り直したら、多分大丈夫そうです。

あの現象はいったい何なのかが不明なので気持ち悪いですが・・・^^;

INでお会いできた時は、出来上がりみてくださいね^^
Posted by はちみつ at 2007年08月04日 19:35
新作のホッピング頂きました。
もうピョンピョンです。
Posted by 玉光 at 2007年08月04日 21:52
> はちみつさん

おめでとうございます〜
°゜°。。ヾ( ~▽~)ツ ワーイ♪

昨日の現象なんとなくわかりました〜
変な球はlightのRadiusでした。
どうもlightをonにしてるプリムがあるとeditしたときにかっぱのPCでは球で表現されてる…。

球の正体はそれだったんですが、それとは別に
どうもlightをonにしているオブジェクトだと
うまく物理になってくれない模様…
(物理になってからlightをonにする分には大丈夫みたい)
いろいろ文献探したけどなかったんですが
かっぱの実験で再現性があったので多分これが原因かと〜

今度、例のもの見せてだくさーい。


> 玉光さん

≧(´▽`)≦アハハハ
ぴょんぴょんしてますか〜
あれ、なかなか止まれないのが欠点w
Posted by かっぱ at 2007年08月04日 23:02
かっぱさん、はじめまして!

ハチさんめちゃかわいいですね~^^

SLでも犬を飼いたいと思っているのですが

このスクリプトをお借りしたら、

もしや超従順なわんこができるのではw

諸事情でINできないので、すぐに試せなくて残念です。

でも、わんこを試す前に

私もハチさんに追いかけられたいです^^
Posted by Ilha.McMillanIlha.McMillan at 2007年08月15日 00:58
> イーリャさん
コメントありがとございます〜^^
ブログ拝見させてもらいました。
なにやらinできないそうで…はやく戻って来れるといいですね〜。

ハチは追い掛けられるを通り越して拉致されるのでお気をつけて〜w
Posted by かっぱかっぱ at 2007年08月16日 06:08
ハチさん、拉致しちゃうんですか!

かっぱさんが連れ去られてる写真は

フィクションじゃなかったんですね!!

うわ~ますます楽しみです^^

>なにやらinできないそうで…はやく戻って来れるといいですね〜。

やさしいお言葉ありがとうございます。

たまぁ~に中毒症状が出てネットカフェからINしていますw
Posted by Ilha.McMillanIlha.McMillan at 2007年08月19日 11:48
こんにちは、
風船を作ろうとして、この記事を参考にさせていただきました。

まだまだ力不足なので、とても全部を理解できているわけではありませんが、とりあえずわかった範囲でスクリプトが完成しました。

とても丁寧な解説ありがとうございました。
Posted by jinkojinko at 2007年09月20日 20:45
> jinkoさん
風船うまくいったみたいですね^^
おめでとおございます〜!
こんなコードでも参考になったみたいで
ちょと嬉し〜ヽ( ´¬`)ノ ワ〜イ !!
Posted by かっぱかっぱ at 2007年09月20日 21:49
スクリプトとても参考になりました。クマノミの水槽で一部修正して使わせて頂いています。でも、時々横になって死んだようになっていたり、3匹放しているのですが、数時間たつとお互いにくっついて動かなくなったりして困っています(T_T)
これからも参考になる記事を楽しみにしています。ありがとうございました。
Posted by クマノミクマノミ at 2007年10月09日 23:40
> クマノミさん
あ〜!その現象、自分もよく遭遇します〜。
物理にしているオブジェクトをず〜っと放っておくと
ピタっと止まっていたり、お互いぶつかってSIMを
出ちゃう(勝手に消えてる)ことが…
ただでさえ扱いにくい物理なのにこういう問題もあると
つくづく面倒くさいですよね〜…
商品にするとなるとこの辺もクリアにしておかないとですか…
大変ですが頑張ってください〜!
Posted by かっぱかっぱ at 2007年10月10日 10:30
コメントありがとうございます。
やっぱりそうですか。。。
たまにMath Errorとかいって止まってるし。。。
物理は環境の影響を受けるんでしょうね。10分おきにリセットを呼び出しているのですが、だめでした。エラーハンドリングができるといいのですが。。。
あきらめずに調整していきます。
今後ともよろしくお願いします。
Posted by クマノミ at 2007年10月10日 12:09
はじめまして、
素敵なスクリプトですね!

僕もスクリプト頂いてさっそく作ったオブジェクトに入れてみたのですが、

fellowでもcomeでも、微妙にピクっと動く程度で、移動はしてもらえません。

何が原因なのでしょうか。。。

以前の書き込みであった、lightの設定もしていないですし、プリムの設定も数も大丈夫なはずなんですが。。。
Posted by やいり at 2007年10月25日 06:35
ありゃ?なんでしょ??
現物を見ないとなんともですね…。
せっかくコメント頂いたので原因究明の
お手伝いさせてもらいますよ〜。
お時間あれば今かっぱ池に来てみましたので
よろしければどうぞです〜。
http://slurl.com/secondlife/japan 01/190/21/30
と、すんごい久し振りのinだ…。
Posted by かっぱ at 2007年10月25日 06:50
あっ…見てなかったみたいw
Flexibleかなぁ??

ただの木箱でまず試してもらって
段階を追ってご自身のオブジェになるようにして
どこで動かなくなるか試していけば
原因がわかるかもです〜。
Posted by かっぱ at 2007年10月25日 08:06
あっ、すぐ返事もらえるとは思ってなかったので、すみませんorz

今夜の22時以降、もしinされるようであれば、レス頂けると嬉しいです!
Posted by やいり at 2007年10月25日 19:24
いえいえ〜^^
設定でコメントがあればメール来るようになってますので
何気にすぐ気付くんですね。(o ̄∀ ̄)ノ”ぁぃ

では22時にかっぱ池でお待ちしてますね^^
その前に原因がわかったらお知らせくださ〜い。
Posted by かっぱかっぱ at 2007年10月25日 19:32
ほぃ、一応ご報告…
先日の物理にならない現象は子プリムに
Flexibleのものが紛れていたのが原因でした。

init()で物理にする前にFlexibleがあるかどうかの
チェックをする記述をすれば、通知なり無条件に
Flexibleを外せたりすることは可能そうですね^^
Posted by かっぱ at 2007年10月26日 14:12