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

2007年06月17日

エレベーター

かっぱで暮らしていると人型の人たちには気付いてもらえない
微妙に不便なことがありまして…

足がちょと短いのです...
で 人は登れる階段でよくガツガツぶつかってます (ノД`)シクシク
それで かっぱはいくつかのグループに所属させて頂いてますが
そのうちのグループ購入した土地でお家を共同で作ってまして
案の定 登れない階段が… あぅ

というわけでエレベーターにへんこう~~~


でもせっかく作るのでちゃんとしたエレベーターにしたいなーと
階移動でよくあるのが『SitしてZ座標の瞬間移動』 これ楽しくない うん
実際に中に人が入ってボタン押したらうぃ~んって動いてほしぃ…


というわけで実験
ただの板を用意して↓を流し込み…


default
{
    state_entry()
    {
        llSetTimerEvent(1.0);
    }
    
    timer()
    {
        llSetPos(llGetPos() + < 0.0, 0.0, 0.1>);
    }
}



いや 予想通りなんですがカクカクしてます…  さっぱり楽しくない…
エレベーター

llSetPosはこれだから…
移動系の関数だとllMoveToTargetがスムーズだけど物理属性かぁ~
う~ん まぁいいや がんばろ

...
...


てなわけでプリムの体裁を↓みたいな感じで準備して…
エレベーター
親プリム       …下の薄い緑色の立つところ(ルートプリムが正式名称?)
子プリム(up)    …白い↑向きの円錐(タッチすると上がる~)
子プリム(down) …白い↓向きの円錐(タッチすると下がる~)
周りのプリムは落ちないようの補助だけ~ 一応リンクしてる


親プリムに↓流し込み~


float   _MOVE_HEIGHT     = 10.0;
integer _MOVE_STATE      = FALSE;
float   _MOVE_SECOND     = 3.0;
float   _TIME_INTERVAL   = 0.1;
vector  _TARGET_POS;
integer _TARGET_ID;
float   _TARGET_MARGIN   = 0.2;


keepHorizon()
{
    vector cur_rot = llRot2Euler(llGetRot());
    float  z_rot   = cur_rot.z;
    llRotLookAt(llEuler2Rot(< 0.0, 0.0, z_rot>), 0.5, 0.5);
}

default
{
    on_rez(integer param)
    {
        llResetScript();
    }

    state_entry()
    {
        llSetPrimitiveParams([PRIM_PHYSICS, FALSE]);
    }
    
    link_message(integer sender_num, integer num, string str, key id)
    {
        
        if (!_MOVE_STATE) {
            
            if (str == "up") {
                _TARGET_POS = llGetPos() + < 0.0, 0.0, _MOVE_HEIGHT>;
            }
            if (str == "down") {
                _TARGET_POS = llGetPos() - < 0.0, 0.0, _MOVE_HEIGHT>;
            }

            
            _MOVE_STATE = TRUE;
            llSetTimerEvent(_TIME_INTERVAL);
            llSetPrimitiveParams([PRIM_PHYSICS, TRUE]);
            
            _TARGET_ID = llTarget(_TARGET_POS, _TARGET_MARGIN);
            llMoveToTarget(_TARGET_POS, _MOVE_SECOND);
            
        }
        
    }
    
    at_target(integer number, vector targetpos, vector ourpos)
    {
        
        llTargetRemove(_TARGET_ID);
        llStopMoveToTarget();
        
        llSetTimerEvent(FALSE);
        keepHorizon();
        llSetPrimitiveParams([PRIM_PHYSICS, FALSE]);
        _MOVE_STATE = FALSE;
        
        llSetPos(_TARGET_POS);
    }
    
    not_at_target()
    {   
    }
    
    timer()
    {
        llSetPrimitiveParams([PRIM_PHYSICS, TRUE]);
        keepHorizon();
    }
}



子プリム(up)に↓これ


default
{
    touch_start(integer total_number)
    {
        llMessageLinked(LINK_ROOT, FALSE, "up", NULL_KEY);
    }
}



子プリム(down)に↓これ


default
{
    touch_start(integer total_number)
    {
        llMessageLinked(LINK_ROOT, FALSE, "down", NULL_KEY);
    }
}




あはは すむーず~ でけた
エレベーター


でもやっぱり物理なので複雑です…微調整のためのコードで全体が汚くなって あぁぁ



大まかな流れは…


子プリム(up/down)がtouch_startで発動
 ↓
親プリムへ向けてリンク内メッセージ(up/down)を投げる~
 ↓
親プリムがメッセージを受け取ったら『今 移動中!』のフラグを立てる
 ↓
で移動開始~ (この間に子プリムがtouchされてもメッセージは無視)
 ↓
移動終了したら『今 移動中!』のフラグを引っ込める



です~


仕組みを順番に見てくと…


子プリムたち(up/down)


default
{
    touch_start(integer total_number)
    {
        llMessageLinked(LINK_ROOT, FALSE, "up", NULL_KEY);
    }
}



default
{
    touch_start(integer total_number)
    {
        llMessageLinked(LINK_ROOT, FALSE, "down", NULL_KEY);
    }
}


llMessageLinkedで親に向かって文字列の "up" もしくは "down" を投げてるだけです
今移動中かどうかなんて子供は知らない それは親が判断することにしちゃいましょ~


親プリム

親の最初の方はどうでもいいことなので文字色薄くしちゃってます~


float   _MOVE_HEIGHT     = 10.0;    // 上昇(下降)の距離(なんとなく10mにしてみた)
integer _MOVE_STATE      = FALSE;   // 現在エレベーターが動いてるかどうか
float   _MOVE_SECOND     = 3.0;     // 上昇(下降)に掛ける時間(といっても正確ではない)
float   _TIME_INTERVAL   = 0.1;     // llSetTimerEventにつかう
vector  _TARGET_POS;                // 上昇(下降)の目標地点を入れる
integer _TARGET_ID;                 // 目標地点の識別ID
float   _TARGET_MARGIN   = 0.2;     // 目標地点の誤差半径(この範囲にくれば到達とみなす)


グローバル変数の設定ですね
自分の癖で使いそうな変数は予め全部頭で宣言しちゃいます~
多くとも数百行のコードなのでグローバル変数多用して(・∀・)イイ
(この辺は自己責任で)

あとLSLの定数(ALL_SIDESとか)と被らないように
変数の頭に _ (アンダーバー)入れてます~


keepHorizon()は後にまわして…



default
{
    on_rez(integer param)
    {
        llResetScript();
    }

    state_entry()
    {
        llSetPrimitiveParams([PRIM_PHYSICS, FALSE]);
    }
...


on_rezの中身は常套手段ですね とりあえず全部リセット グローバル変数も全部初期値へ~

state_entryですが… 物理属性にするためにllSetPrimitiveParams([PRIM_PHYSICS, TRUE])
かと思われますがFALSEにしています 理由は…いきなり物理属性にしてるとエレベーターの外から
中に入ろうとしたときに下の段差を上がらずにガツガツ蹴ってしまうのでw
うん とりあえずは非物理にしちゃえ



で本流…
子プリムから"up"もしくは"down"を受け取った親は…


    link_message(integer sender_num, integer num, string str, key id)
    {
        
        if (!_MOVE_STATE) {
            
            if (str == "up") {
                _TARGET_POS = llGetPos() + < 0.0, 0.0, _MOVE_HEIGHT>;
            }
            if (str == "down") {
                _TARGET_POS = llGetPos() - < 0.0, 0.0, _MOVE_HEIGHT>;
            }

            
            _MOVE_STATE = TRUE;
            llSetTimerEvent(_TIME_INTERVAL);
            llSetPrimitiveParams([PRIM_PHYSICS, TRUE]);
            
            _TARGET_ID = llTarget(_TARGET_POS, _TARGET_MARGIN);
            llMoveToTarget(_TARGET_POS, _MOVE_SECOND);
            
        }
        
    }



最初のif文で今移動中かどうかを調べます 移動中だったら子供の声は聞こえないふりです~
移動中ではなく止まってるときであれば

・ _TARGET_POSに目標地点を入れて
・ _TARGET_IDに目標地点を覚えこませて
・ llMoveToTargetで移動開始

その際 ついでに『今 移動中!』のフラグもここで立てちゃう(_MOVE_STATE = TRUE)

あとllSetPrimitiveParams([PRIM_PHYSICS, TRUE])で物理属性にしておかないと
ちゃんとllMoveToTargetが動いてくれないので なんとなくこの位置

llSetTimerEventが唐突に出てますがこれの意味はkeepHorizon()と一緒に後述しまーす



目標地点に到達しました
はい着きました~ といっても誤差の範囲にいるだけなので正確な目標地点にいるわけではありません


    at_target(integer number, vector targetpos, vector ourpos)
    {
        
        llTargetRemove(_TARGET_ID);
        llStopMoveToTarget();
        
        llSetTimerEvent(FALSE);
        keepHorizon();
        llSetPrimitiveParams([PRIM_PHYSICS, FALSE]);
        _MOVE_STATE = FALSE;
        
        llSetPos(_TARGET_POS);
    }
    
    not_at_target()
    {   
    }


at_targetで移動終了後の後始末をいろいろしています
何気に物理属性を解除した後にllSetPos(_TARGET_POS)で正確な位置へと…
ちゃんと正確な位置にいてもらわないと上昇下降を繰り返しているうちにどんどんズレてくるので仕方なく… あぁ

not_at_targetの中身は何も無いです 着いてないときに発動するイベントですが
着いてないときはただひたすら目標地点を目指すだけなので何も書かないです うん



これで一通り完成なんですが…
やっぱり物理の扱いにくいところでして 
このままだと 人が乗ったり ちょっとぶつかったり するだけで直ぐにグルグル回転しちゃう… あぅ


というわけでkeepHorizon()の出番です


keepHorizon()
{
    vector cur_rot = llRot2Euler(llGetRot());
    float  z_rot   = cur_rot.z;
    llRotLookAt(llEuler2Rot(< 0.0, 0.0, z_rot>), 0.5, 0.5);
}


timerイベント内から呼び出される関数にしてましてllSetTimerEventが指定する発動間隔(_TIME_INTERVAL)で
この関数を呼び出しちゃいます 呼ばれると自分が水平になるように頑張ってくれてますが注意点が…
ここではXとY軸を常に0にしてZ軸周りの角度は維持するようにしています
違う初期配置でオブジェを構成したときにはもしかしたらここが変わるかもしれませんので その辺は適当に…

仕組みは…
・ llGetRotで自分の回転値を取得
・ llRot2Eulerでrotation型をvector型へ変換
・ X,Y軸周りは0は決定なので Z軸周りの回転値だけを一旦保管しておいて
・ < 0.0, 0.0, (保管したZ値)>をllEuler2Rotでvector型からrotation型へ変換
・ llRotLookAtで実際に回転を開始
  (llRotLookAtの第2・3引数の意味がよくわかんないけどリンク先には0.2から1.0の間が(・∀・)イイ
   ってかいてあるのでなんとなく0.5にしてみた… う~ん謎 まぁ いっか)




そんなこんなで完成~~~~
最初のただの板で実験だと一瞬で出来るパターンだけど
やっぱり物理属性にするとぐだぐだになりましたね~
エレベーターは無難に非物理でやった方が簡単w


といってもまだまだ欠点が…

・ 今のままでは延々と上に行けちゃう
  特に上限つけてるわけではないので当然です~

・ 各階にボタンが無い 致命的w

・ エレベーターの下にはさまれることも
  かつ はさまれると動けなくなる…こんな感じ↓
エレベーター


まぁ その辺は追々詰めてこ~
エレベーター本体が動いてくれればあとはなんとかなる~~


同じカテゴリー(スクリプト)の記事画像
ふきだし
ペット
打ち上げ花火
エレベーター2
同じカテゴリー(スクリプト)の記事
 ふきだし (2007-08-13 12:20)
 ペット (2007-07-30 13:04)
 打ち上げ花火 (2007-06-23 08:50)
 エレベーター2 (2007-06-21 22:36)
Posted by かっぱ at 22:05│Comments(4)スクリプト
この記事へのコメント
はさまれてるw

エレベーターは難しいでしょうねぇぇ
あのタイタニック風の船のエレベーターもカックカクでしたもの。
Posted by ダミーくん at 2007年06月19日 17:24
あ そうなんだ〜
やっぱり無駄に凝りすぎたかもw
Posted by かっぱ at 2007年06月20日 13:59
こちらでは初カキコですねこんばんはー。

単にエレベーターといっても色々種類がありますよねー。
私はまだカクカクとテレポートのタイプにしか出会ったことありませんが。。。
Posted by scarecrowJACK at 2007年06月21日 01:44
エレベーター出来上がりました~

無駄にスムーズです~

といってもまだどこにも置いてませんがw


シザさんのところをお気に入りにさせてもらいましたね~ わー
Posted by かっぱ at 2007年06月21日 22:50
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。