読者です 読者をやめる 読者になる 読者になる

便利なスクリプトの書き方(ユーザー定義関数)

この記事はセカンドライフ技術系 Advent Calendar2016用の記事です。
www.adventar.org

去年も書こうとは思ってたのですが書けなかったので今年こそと思い数年ぶりにブログを書いてみます。

はてなブログでは簡単にLSLに色付けが出来ると知りブログの開設からやってしまいましたw

ユーザー定義関数とは

さて、タイトルのユーザー定義関数ですがざっくり言うと何度も同じ処理書くの大変だから同じ処理は一箇所でまとめてやっちまえ的な奴です!
オリジナルの関数を作って使えると思ってもらえば良いと思います。
いくつかメリットを上げるとすれば
 ・コードが短くなりメモリの節約になる。
 ・どこに何が書いてあるかわかりやすい。
 ・アップデートや修正などのメンテナンスが楽になる。

自分が書いた1年前のスクリプトを開いて どこに何が書いてあるかさっぱりわからん!なんて事ないですか?僕はよくありますw
きちんとユーザー関数を使って行けばかなりスッキリしたコードが書けるのでスクリプトがぐちゃぐちゃになってしまう人に特にお勧めします。

ユーザー定義関数には2種類あります。

第一の型

//ユーザー定義関数
say(string msg)
{
    llSay(0,msg);    
}
//メインコード
default
{
    state_entry()
    {
        say("Hello, Avatar!");
    }

    touch_start(integer total_number)
    {
        say("Touched.");
    }
}

まずユーザー定義関数には変数を入れることが出来ます。
say(string msg)の部分ですね。 sayというのはオリジナルの関数名です。好きにつけてしまって構いません。
その後の()の中ですが必要に応じて書いていきます。string,integer,float,vector,rotation,listなんでも入ります。
(string msg,integer num,list data_list) のように,で区切って記述していきましょう。
この場合は say()というオリジナル関数が呼び出されたらmsgという変数の中に入っている文字をllSayしてるだけですね。

第二の型

//ユーザー定義関数
integer get_num(integer num_1 , integer num_2)
{
    integer answer = num_1 + num_2;
    return answer;
}
//メインコード
default
{
    touch_start(integer total_number)
    {
        integer number_1 = 100;
        integer number_2 = 200;
        integer total_number = get_num(number_1,number_2);
        llSay(0,(string)total_number);
    }
}

似てるようでちょっと違いますね。
違いはユーザー定義関数の中で処理した結果が返事となって返ってくる所です。
returnの後に返したい変数を書き;で閉めてください。
その返したい型に合わせてユーザー関数の前にiniteger や stringといった型名を書けばOKです。
上のコードではnumber_1(100)とnumber_2(200)を足した数字が返ってきます。

おまけのカラー&テクスチェンジスクリプト

最後におさらいとして無理やり気味にユーザー定義関数を2種類使ったダイアログのスクリプトを作ってみます。

//カラーリスト
list coler_list = [
"Red",<1,0,0>,
"Blue",<0,0,1>,
"Green",<0,1,0>
];
//テクスチャーリスト
list texture_list = [
"tex_1","ee1313b7-451f-97c8-1aff-de8f9f86b120",
"tex_2","fa050b2a-ed2e-098a-9a2d-6dabec00111f",
"tex_3","5b3eacc6-796e-f6db-a920-91e30693875b"
];
//グローバル変数
string dialog_state;
integer dialog_channel;
integer Handle;
//ダイアログを設定
set_dialog(key id)
{
    string dialog_msg = "menu";
    list dialog_list = ["Color_chenge","Tex_change","Close"];
    if(dialog_state == "color_chenge")
    {//dialog_stateがカラーチェンジの時 それ用のリストを作る
        dialog_list = get_dialog_list(coler_list,[" ","<< Back","Close"]);
    }else if(dialog_state == "tex_chenge")
    {//dialog_stateがテクスチェンジの時 それ用のリストを作る
        dialog_list = get_dialog_list(texture_list,[" ","<< Back","Close"]);
    }
    llDialog(id,dialog_msg,dialog_list,dialog_channel);
    llSetTimerEvent(120.0);
}
//ダイアログのボタンリストを作成
list get_dialog_list(list data_list_1,list data_list_2)
{//data_list_2とdata_list_1 のボタン名だけを抜き出したリストをくっつけて返す。
    return data_list_2 + llList2ListStrided(data_list_1,0,-1,2);
}
//メインコード
default
{
    state_entry()
    {
        //ダイアログのチェンネルをランダムに指定
        dialog_channel = (integer)llFrand(20000) + 200; 
    }
    
    on_rez(integer param)
    {
        llResetScript();   
    }

    touch_start(integer total_number)
    {
        //メインメニューでダイアログを表示
        Handle = llListen(dialog_channel, "", "", "");
        dialog_state = "main_menu";
        set_dialog(llDetectedKey(0));
    }
    
    timer() 
    {
        //リッスンを停止 
        llListenRemove(Handle); 
        llSetTimerEvent(0); 
    }
    
    listen(integer channel, string name, key id, string msg) 
    {
        if(msg == "Close")
        {
            llSetTimerEvent(0.1);
        }else if(msg == " ")
        {
            set_dialog(id);
        }else if(msg == "<< Back")
        {
            //メインメニューでダイアログを表示
            dialog_state = "main_menu";
            set_dialog(id);
        }else if(msg == "Color_chenge")
        {//カラーチェンジ 
            //カラーチェンジメニューでダイアログを表示
            dialog_state = "color_chenge";
            set_dialog(id);
        }else if(msg == "Tex_change")
        {//テクスチャチェンジ
            //テクスチャチェンジメニューでダイアログを表示
            dialog_state = "tex_chenge";
            set_dialog(id);                
        }else
        {
            integer index_color = llListFindList(coler_list,[msg]);
            integer index_tex = llListFindList(texture_list,[msg]); 
            if(index_color != -1 && dialog_state == "color_chenge")
            {//カラーチェンジの色指定
                vector color = llList2Vector(coler_list,index_color+1);
                llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_COLOR,ALL_SIDES,color,1.0]);  
            }else if(index_tex != -1 && dialog_state == "tex_chenge")
            {//テクスチャチェンジのUUID指定
                key tex_uuid = llList2Key(texture_list,index_tex+1);
                llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_TEXTURE,ALL_SIDES,tex_uuid,<1,1,0>,<0,0,0>,0]);
            }
            set_dialog(id);//ダイアログを再表示
        }
    }
}

ちょと無理やり使ったのでスマートな書き方ではなくなってしまいますがご愛嬌でw
よくあるダイアログのページが分断化されていていろんな事が出来るメニュー画面。
listenイベント内でif(msg == "Color_chenge"){の所でメニューリストを作りダイアログを出してもいいのですが、ユーザー関数でダイアログ関係を一つにまとめてしまったほうがメンテナンスや仕様変更に柔軟に対応出来ると思います。

他にも便利な使い方は沢山あるのですが長くなってしまうのでこの辺でw
また何かネタがあれば書こうと思いますので何かリクエストがあればコメントなりIMなりくださいませ。