ソラマメブログ

2008年05月30日

【スクリプト】ヴィークル(乗り物)の基本形

ヴィークル系のスクリプトのサンプルは、たぶんいろんなところにあると思いますが、載せておきます。

※乗り物として動きますが、快適に動かすには各パラメーターの調整が必要です。

//==================================================
// sasa_vehicle
// ヴィークルの基本サンプル
// 1.0.0
// 2008/05/26
// created by sasapy Beck

//--------------------------------------------------
// Mode
    integer UP_DOWN_MODE = 1; // Up/Downキーの機能割り当て
                                                // 1: 上昇・下降する
                                                // 2: ギアチェンジ

//--------------------------------------------------
// Define
    key owner_key = NULL_KEY; // オーナーキー
    key sitting_key = NULL_KEY; // 座っているアバターのキー
    key avatar_key = NULL_KEY; // イベントを起こしたアバターのキー

    vector SIT_POSITION = <-0.1, 0.0, 0.85>; // 座る位置
    vector SIT_ROTATION = < 0.0, 0.0, 0.0>; // 座る回転
    vector CAMERA_OFFSET = <-2.0, 0.0, 1.0>; // カメラ位置
    vector CAMERA_AT = < 2.0, 0.0, 1.0>; // カメラの向き

    vector LINER_FORWARD = < 5.0, 0.0, 0.0>; // 直進時のパラメーター
    vector LINER_BACK = <-3.0, 0.0, 0.0>; // 後退時のパラメーター
    vector LINER_UP = < 0.0, 0.0, 5.0>; // 上昇時のパラメーター
    vector LINER_DOWN = < 0.0, 0.0, -3.0>; // 下降時のパラメーター
    vector ROLL_RIGHT = < 0.0, 0.0, -1.0>; // 回転時のパラメーター
    vector ROLL_LEFT = < 0.0, 0.0, 1.0>; // 回転時のパラメーター
    vector BANK_RIGHT = <-1.0, 0.0, 0.0>; // 傾き時のパラメーター
    vector BANK_LEFT = < 1.0, 0.0, 0.0>; // 傾き時のパラメーター

    float gear = 1.0; // ギア
    float GEAR_MAX = 4.0; // ギアの上限
    float GEAR_MINI = 1.0; // ギアの下限

    vector motor_linear = ZERO_VECTOR; // 直進方向のパラメーター
    vector motor_angular = ZERO_VECTOR; // 回転方向のパラメーター

    string ANIMATION_SIT = "sit"; // アニメーション名
    string ANIMATION_FORWARD = "forward"; // アニメーション名
    string ANIMATION_BACK = "back"; // アニメーション名
    string ANIMATION_LEFT = "left"; // アニメーション名
    string ANIMATION_RIGHT = "right"; // アニメーション名
    string ANIMATION_UP = "up"; // アニメーション名
    string ANIMATION_DOWN = "down"; // アニメーション名

//--------------------------------------------------
// Function
// ヴィークルのパラメーター設定
    ssSetVehicleParams()
    {
// タイプ
        llSetVehicleType(
//          VEHICLE_TYPE_NONE // なし
//          VEHICLE_TYPE_SLED // ソリ
//          VEHICLE_TYPE_CAR // 車
//          VEHICLE_TYPE_BOAT // ボート
            VEHICLE_TYPE_AIRPLANE // 飛行機
//          VEHICLE_TYPE_BALLOON // 気球
        );

// フラグ(一旦全フラグを解除してから設定する)
        llRemoveVehicleFlags(0
            | VEHICLE_FLAG_NO_DEFLECTION_UP // 垂直方向無効
            | VEHICLE_FLAG_LIMIT_ROLL_ONLY // 上下に向いても垂直方向の移動に影響しない
            | VEHICLE_FLAG_HOVER_WATER_ONLY // HOVERの水面を基準とする
            | VEHICLE_FLAG_HOVER_TERRAIN_ONLY // HOVERの地面を基準とする
            | VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT // HOVERの指定の高さを基準とする
            | VEHICLE_FLAG_HOVER_UP_ONLY // HOVERの上昇のみ有効(下降は重力)
            | VEHICLE_FLAG_LIMIT_MOTOR_UP // 空中にいるときはモーター無効
            | VEHICLE_FLAG_MOUSELOOK_STEER // マウスルックした向きへ方向転換
            | VEHICLE_FLAG_MOUSELOOK_BANK // マウスルックした向きへバンク
            | VEHICLE_FLAG_CAMERA_DECOUPLED // 乗り物の回転に視点を合わせない
        );

        llSetVehicleFlags(0
//          | VEHICLE_FLAG_NO_DEFLECTION_UP // 垂直方向無効
            | VEHICLE_FLAG_LIMIT_ROLL_ONLY // 上下に向いても垂直方向の移動に影響しない
//          | VEHICLE_FLAG_HOVER_WATER_ONLY // HOVERの水面を基準とする
//          | VEHICLE_FLAG_HOVER_TERRAIN_ONLY // HOVERの地面を基準とする
//          | VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT // HOVERの指定の高さを基準とする
//          | VEHICLE_FLAG_HOVER_UP_ONLY // HOVERの上昇のみ有効(下降は重力)
//          | VEHICLE_FLAG_LIMIT_MOTOR_UP // 空中にいるときはモーター無効
//          | VEHICLE_FLAG_MOUSELOOK_STEER // マウスルックした向きへ方向転換
//          | VEHICLE_FLAG_MOUSELOOK_BANK // マウスルックした向きへバンク
//          | VEHICLE_FLAG_CAMERA_DECOUPLED // 乗り物の回転に視点を合わせない
        );

// フロートパラメーター
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 0.5); // 力を前後移動に変換する0.0~1.0
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 0.5); // 変換が最大になる時間(秒)
        llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 10.0); // 静止するまでの時間(秒)
        llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, 2.0); // 最高速度になる時間(秒)

        llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 1.0); // 力を向きに変換する0.0~1.0
        llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 2.0); // 変換が最大になる時間(秒)
        llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 5.0); // 角速度が静止するまでの時間
        llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, 3.0); // 角速度が最大になるまでの時間

        llSetVehicleFloatParam(VEHICLE_BANKING_EFFICIENCY, 1.0); // バンクを回転に変換する-1.0(外側)~0(なし)~1.0(内側)
        llSetVehicleFloatParam(VEHICLE_BANKING_MIX, 0.7); // 速度が速いとカーブする0.0(しにくい)~1.0(しやすい)
        llSetVehicleFloatParam(VEHICLE_BANKING_TIMESCALE, 3.0); // バンクが最大になるまでの時間(秒)

        llSetVehicleFloatParam(VEHICLE_BUOYANCY, 0.0); // 浮力-1.0(重力2倍)~0.0(重力1倍)~1.0(無重力)

        llSetVehicleFloatParam(VEHICLE_HOVER_HEIGHT, 0.0); // 基準からHOVERする高度0.0~100.0(m)
        llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.5); // 高度変更のなめらかさ0.0~1.0
        llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 50.0); // 目標高度に達するまでの時間(秒)

        llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 0.9); // 垂直を維持する強さ0.0(弱い)~1.0(強い)
        llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 2.0); // 垂直になるまでの時間(秒)

// ベクトルパラメーター
        llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_OFFSET, <0.0, 0.0, 0.0>); // プリム中心からのモーター位置
        llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0.0, 0.0, 0.0>); // モーターの最高速度(m/s)
        llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <90.0, 10.0, 5.0>); // 停止までの時間(秒)
        llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <0.0, 0.0, 0.0>); // 最大角速度(rad/sec)
        llSetVehicleVectorParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, <5.0, 5.0, 5.0>); // 回転が停止するまでの時間(秒)

// ローテーションパラメーター
        llSetVehicleRotationParam(VEHICLE_REFERENCE_FRAME, <0.0, 0.0, 0.0, 1.0>); // 乗り物の向きがデフォルトと違う場合の回転の向き
    }

//--------------------------------------------------
// Main
    default
    {

// 初期設定
        state_entry()
        {
            owner_key = llGetOwner(); // オーナーキー取得
            llSetSitText("Ride"); // パイメニュー設定

// 座る位置と視点位置の設定
            llSitTarget(SIT_POSITION, llEuler2Rot(SIT_ROTATION * DEG_TO_RAD)); // 座る位置と回転
            llSetCameraEyeOffset(CAMERA_OFFSET); // カメラ位置
            llSetCameraAtOffset(CAMERA_AT); // カメラの向き

            ssSetVehicleParams(); // ヴィークルパラメーターの設定
        }

// REZ Event
// REZされたらリセットする
        on_rez(integer start_param)
        {
            llResetScript();
        }

// Touch Event
// タッチされたらインフォメーションを表示
// ヴィークルの動作に影響しないので、お好みで処理を抜くか、宣伝(LM配布、Notecard配布)等を入れてください
        touch_start(integer total_number)
        {
            avatar_key = llDetectedKey(0); // アバターキー取得

            if(avatar_key == owner_key) // オーナーの場合
            {
                llOwnerSay("This vehicle is yours");
            }
            else // オーナー以外の場合
            {
                llSay(PUBLIC_CHANNEL, "This vehicle is not yours");
            }
        }

// Change Event
// オブジェクトにアバターが座った/立ったときのイベント
        changed(integer change)
        {
            if(change & CHANGED_LINK) // LINKが変わる=座る/立つ
            {
                avatar_key = llAvatarOnSitTarget(); // 座ったアバターキー取得

                if((sitting_key == NULL_KEY) && (avatar_key != NULL_KEY)) // 今まで座ってなくて座られた
                {
                    sitting_key = avatar_key; // 座っているアバターキー更新
                    llSetStatus(STATUS_PHYSICS, TRUE); // 物理属性にする
                    llRequestPermissions(sitting_key, PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS); // パーミッション要求
                }
                else if((sitting_key != NULL_KEY) && (avatar_key == NULL_KEY)) // 今まで座っていたが居なくなった
                {
                    sitting_key = NULL_KEY; // 座っているアバターキークリア
                    llSetStatus(STATUS_PHYSICS, FALSE); // 物理属性解除
                    llReleaseControls(); // キーコントロールの解放
                    llStopAnimation(ANIMATION_SIT); // アニメーションの停止
                    gear = 1.0; // ギアの初期化
                }
            }
        }

// Permission Event
// パーミッションの許可
        run_time_permissions(integer permissions)
        {
            if(permissions & PERMISSION_TRIGGER_ANIMATION) // アニメーション許可
            {
                llStartAnimation(ANIMATION_SIT); // 基本ポーズ
            }
            if(permissions & PERMISSION_TAKE_CONTROLS) // キーコントロール許可
            {
                llTakeControls( CONTROL_FWD | CONTROL_BACK |
                                        CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT |
                                        CONTROL_RIGHT | CONTROL_LEFT |
                                        CONTROL_UP | CONTROL_DOWN,
                                        TRUE, FALSE); // 使用するキーの設定
            }
        }

// Control Event
// キー入力による処理
// 同時に2つ以上のキーが押された場合を考慮していない
        control(key name, integer levels, integer edges)
        {
            motor_linear = ZERO_VECTOR;
            motor_angular = ZERO_VECTOR;

// ↑キー、Wキー
            if((levels & CONTROL_FWD) && (edges & CONTROL_FWD)) // 押したとき
            {
                llStartAnimation(ANIMATION_FORWARD);
            }
            if(levels & CONTROL_FWD) // 押している最中
            {
                motor_linear = LINER_FORWARD * gear;
            }
            if(!(levels & CONTROL_FWD) && (edges & CONTROL_FWD)) // 放したとき
            {
                motor_linear = ZERO_VECTOR;
                llStopAnimation(ANIMATION_FORWARD);
            }

// ↓キー、Sキー
            if((levels & CONTROL_BACK) && (edges & CONTROL_BACK)) // 押したとき
            {
                llStartAnimation(ANIMATION_BACK);
            }
            if(levels & CONTROL_BACK) // 押している最中
            {
                motor_linear = LINER_BACK * gear;
            }
            if(!(levels & CONTROL_BACK) && (edges & CONTROL_BACK)) // 放したとき
            {
                motor_linear = ZERO_VECTOR;
                llStopAnimation(ANIMATION_BACK);
            }

// →キー、Dキー
            if((levels & CONTROL_ROT_RIGHT) && (edges & CONTROL_ROT_RIGHT)) // 押したとき
            {
                llStartAnimation(ANIMATION_RIGHT);
            }
            if(levels & CONTROL_ROT_RIGHT) // 押している最中
            {
                motor_angular = ROLL_RIGHT * gear;
            }
            if(!(levels & CONTROL_ROT_RIGHT) && (edges & CONTROL_ROT_RIGHT)) // 放したとき
            {
                motor_angular = ZERO_VECTOR;
                llStopAnimation(ANIMATION_RIGHT);
            }

// ←キー、Aキー
            if((levels & CONTROL_ROT_LEFT) && (edges & CONTROL_ROT_LEFT)) // 押したとき
            {
                llStartAnimation(ANIMATION_LEFT);
            }
            if(levels & CONTROL_ROT_LEFT) // 押している最中
            {
                motor_angular = ROLL_LEFT * gear;
            }
            if(!(levels & CONTROL_ROT_LEFT) && (edges & CONTROL_ROT_LEFT)) // 放したとき
            {
                motor_angular = ZERO_VECTOR;
                llStopAnimation(ANIMATION_LEFT);
            }

// Shift+→キー、Shift+Dキー
            if((levels & CONTROL_RIGHT) && (edges & CONTROL_RIGHT)) // 押したとき
            {
                llStartAnimation(ANIMATION_RIGHT);
            }
            if(levels & CONTROL_RIGHT) // 押している最中
            {
                motor_angular = BANK_RIGHT * gear;
            }
            if(!(levels & CONTROL_RIGHT) && (edges & CONTROL_RIGHT)) // 放したとき
            {
                motor_angular = ZERO_VECTOR;
                llStopAnimation(ANIMATION_RIGHT);
            }

// Shift+←キー、Shift+Aキー
            if((levels & CONTROL_LEFT) && (edges & CONTROL_LEFT)) // 押したとき
            {
                llStartAnimation(ANIMATION_LEFT);
            }
            if(levels & CONTROL_LEFT) // 押している最中
            {
                motor_angular = BANK_LEFT * gear;
            }
            if(!(levels & CONTROL_LEFT) && (edges & CONTROL_LEFT)) // 放したとき
            {
                motor_angular = ZERO_VECTOR;
                llStopAnimation(ANIMATION_LEFT);
            }

// Page Upキー
            if((levels & CONTROL_UP) && (edges & CONTROL_UP)) // 押したとき
            {
                if(UP_DOWN_MODE == 1)
                {
                    llStartAnimation(ANIMATION_UP);
                }
                else if(UP_DOWN_MODE == 2)
                {
                    gear += 1.0;
                    if(gear > GEAR_MAX) gear = GEAR_MAX;
                }
            }
            if(levels & CONTROL_UP) // 押している最中
            {
                if(UP_DOWN_MODE == 1)
                {
                    motor_linear = LINER_UP * gear;
                }
            }
            if(!(levels & CONTROL_UP) && (edges & CONTROL_UP)) // 放したとき
            {
                if(UP_DOWN_MODE == 1)
                {
                    motor_linear = ZERO_VECTOR;
                    llStopAnimation(ANIMATION_UP);
                }
            }

// Page Downキー
            if((levels & CONTROL_DOWN) && (edges & CONTROL_DOWN)) // 押したとき
            {
                if(UP_DOWN_MODE == 1)
                {
                    llStartAnimation(ANIMATION_DOWN);
                }
                else if(UP_DOWN_MODE == 2)
                {
                    gear -= 1.0;
                    if(gear < GEAR_MINI) gear = GEAR_MINI;
                }
            }
            if(levels & CONTROL_DOWN) // 押している最中
            {
                if(UP_DOWN_MODE == 1)
                {
                    motor_linear = LINER_DOWN * gear;
                }
            }
            if(!(levels & CONTROL_DOWN) && (edges & CONTROL_DOWN)) // 放したとき
            {
                if(UP_DOWN_MODE == 1)
                {
                    motor_linear = ZERO_VECTOR;
                    llStopAnimation(ANIMATION_DOWN);
                }
            }

// ヴィークルの直進力と回転力の設定
            llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, motor_linear);
            llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, motor_angular);
        }
    }
//==================================================

(赤文字:変更が必要です。 青文字:お好みで変更してください。)


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

http://sasapy.slmame.com/t257380
この記事へのコメント
はじめまして。
これはきれいに整理されたスクリプトですね〜。

車屋をやっていますが、新しいスクリプトを開発したいなぁと思っていたところです。
参考にします〜^^
Posted by Est400 BeckEst400 Beck at 2008年05月30日 12:54
Est400 Beckさん、こんにちは。

お褒めいただきありがとうございます。

サンプルのスクリプトでは、キー入力の処理の部分ですべての入力の処理を入れています(マウスがらみ以外ですけど)。
実際には必要のない部分とかあったりしますので、そういうところは抜いて使うためのサンプルです。
基本的なヴィークルのスクリプトは形としては固まっているので、その「ひな型」的に載せたのですが、ヴィークルに関して言えばスクリプトよりもパラメーターの調整の方が難しいですね。

以前に作ったヴィークルのスクリプトは、もうちょっと凝っていてキーを放した時、キーが何も押されていないときの減衰もタイマーを使って設定したりしてました。

私はあまりレースとかはやらないので(操作がヘタ)、パラメーターの「おいしいところ」がよく分かっていませんが、いちいちスクリプトを開いて設定値を変えて再テストというようなスクリプトではなくて、例えばタッチするとダイアログが表示されて「もっとピーキー」とか「アンダーぎみに」とか選んで、ヴィークルのパラメーターを設定できれば調整も楽になるのかと思います。
Posted by ささぴ at 2008年05月30日 15:05