今回、アバターを作ったので、それにあたってアタッチメントのテクニックをいくつか紹介します。
1. アタッチオブジェクトをスクリプト禁止エリアで動かす
通常、スクリプト禁止エリアでは、スクリプトは動かせないのですが、方法が1つあるようです。それは、llTakeControlsを利用する方法です。llTakeControlsは、行動をコントロールを操作不能にする可能性があるスクリプトです。おそらく、このスクリプトが入ったままスクリプト禁止に行ってしまうと、何も操作ができなくなってしまうことから、禁止エリアでも動かせるようにしたんだと思われます。具体的には、llRequestPermissionsでPERMISSION_TAKE_CONTROLSを許可してもらい、run_time_permissionsイベントの中で、llTakeControls(-1,FALSE,FALSE)とします。最初の「-1」は、0xFFFFFFFFを表しており、すべての操作を禁止させるという意味です。
default { state_entry() { if(llGetAttached()) { llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS); } } attach(key id) { if(llGetAttached()) { llRequestPermissions(id, PERMISSION_TAKE_CONTROLS); } } run_time_permissions(integer perm) { if(perm & PERMISSION_TAKE_CONTROLS) { llTakeControls(-1, FALSE, FALSE); } } }
2. アタッチオブジェクトを正確に動かす
作っていて発生した問題として、アタッチメントをしているものを動かそうとしたときにSIMによっては、動かないことが発生しました。また、SIMにはよらないのですが、すこし動かそうとしても全く反応しないという問題もしばしば発生しました。調べてみると結局、不具合のようでして、回避する方法は動かす際に、物体の大きさも少し変えてみるという方法です。関数を作るとこんな感じです。
setLocalPos(integer linknumber, vector position ) { list default_size_list = llGetLinkPrimitiveParams(linknumber, [PRIM_SIZE]); vector default_size = llList2Vector(default_size_list, 0); llSetLinkPrimitiveParamsFast(linknumber, [PRIM_SIZE, default_size + , PRIM_POS_LOCAL, position] ); llSetLinkPrimitiveParams(linknumber, [PRIM_SIZE, default_size] ); }
3. 優先度が高いアニメーションに解除されないようにする
ある個所を固定したいためにポーズをとっているときにダンスをすると、その部分がダンスで上書きされることがあります。ここで、タイマーなどで定期的に llStartAnimation で自分のポーズを維持させようとしても、実はすでに再生しているため上書きできないのです。これを防止するためには、いったんポーズを停止して再スタートする必要がありますが、ダンスなどをしていない場合は、この一瞬の解除をすると見た目に影響が出てきてしまいます。これを防止する方法は、同じアニメーションを2つアップロードすることです。つまり、「ポーズを停止して再スタート」する前に、別のアップロードしたポーズで上書きしておくのです。関数を作るとこんな感じです。後ろに「_1」と「_2」を用意しておくのがポイントです。この関数を定期的に呼ぶことで、アニメーションの解除を自然に防げます。
setAnimation(string name, integer is_animation) { if(is_animation) { llStartAnimation(name + "_2"); llStopAnimation(name + "_1"); llSleep(0.1); llStartAnimation(name + "_1"); llStopAnimation(name + "_2"); } else { llStopAnimation(name + "_1"); llStopAnimation(name + "_2"); } }
以上、テクニック集でした!
そうそう、いつもながらおまけコーナー。
今回は、いろいろ作る途中で生まれたので多いです。
テクスチャの設定を取得して表示する。
getTextureParams(integer face_number) { list params = llGetPrimitiveParams([PRIM_TEXTURE, face_number]); string texture = llList2String(params, 0); vector repeats = llList2Vector(params, 1); vector offsets = llList2Vector(params, 2); float rotation_in_radians = llList2Float(params, 3); llOwnerSay( "texture = " + (string)texture + "\n" + "repeats = " + (string)repeats + "\n" + "offsets = " + (string)offsets + "\n" + "rotation_in_radians = " + (string)rotation_in_radians ); }
指定したプリム名のリンクIDを取得する。
integer LINK_NOT = -5; integer getLinkId(string target_name) { integer link_prim_length = llGetNumberOfPrims(); if(link_prim_length == 1) { if(llGetObjectName() == target_name) { return(0); } } else { integer i; for(i = 1;i <= link_prim_length;i++) { string name = llGetLinkName(i); if(name == target_name) { return(i); } } } return(LINK_NOT); }
メモリが少なくなっていたら謝ってリセットする。
checkMemory() { if(llGetFreeMemory() < 64) { llOwnerSay("Sorry. I will complete reset for memory release."); llResetScript(); }}
指定したリンクIDを入れたリストについて、リスト内のIDの物体の向きと位置を表示する。
vector getLocalPosition(integer link_number) { if(link_number == LINK_NOT) { return(NULL_VECTOR); } list style = llGetLinkPrimitiveParams( link_number, [PRIM_POS_LOCAL] ); return(llList2Vector(style, 0)); } rotation getLocalRotation(integer link_number) { if(link_number == LINK_NOT) { return(NULL_ROTATION); } list style = llGetLinkPrimitiveParams( link_number, [PRIM_ROT_LOCAL] ); return(llList2Rot(style, 0)); } showData(list link_list) { integer link_list_length = llGetListLength(link_list); integer i; for(i = 0; i " + (string)link_num + ", " + (string)getLocalPosition(link_num) + ", " + (string)getLocalRotation(link_num) + ", " ); } }
自動でウィンクするひな形のスクリプト
integer IS_AUTO_WINK = FALSE; float TIMER_TIME_SEC = 1.0; float WINK_SEC_AVERAGE = 15.0; float WINK_SEC_VARIANCE = 10.0; float WINK_TIME_NEXT = 0.0; float WINK_TIME_NOW = 0.0; setEyeClose() { } setEyeOpen() { } setAutoWink(integer is_autowink) { IS_AUTO_WINK = is_autowink; } actWink(){ setEyeClose(); llSleep(0.3); setEyeOpen(); } checkAutoWink() { if(!IS_AUTO_WINK) { return; } WINK_TIME_NOW += TIMER_TIME_SEC; if(WINK_TIME_NOW > WINK_TIME_NEXT) { WINK_TIME_NOW = 0.0; WINK_TIME_NEXT = WINK_SEC_AVERAGE + llFrand(WINK_SEC_VARIANCE) - (WINK_SEC_VARIANCE * 0.5); actWink(); if(llFrand(3.0) < 1.0) { llSleep(0.3); actWink(); } } } default { state_entry() { llSetTimerEvent(TIMER_TIME_SEC); } timer() { checkAutoWink(); } }
データ名とデータ値を送信して、それを受信するスクリプト
// 送信部分 string CHANNEL_NAME = "MYCHANNLE"; integer CHANNEL = 0; integer CHANNEL_HANDLE = 0; integer getOriginalKey(string src) { integer i; integer start_pos = 0; integer seed = 0x32123; integer hash = seed; string buffer = llSHA1String((string)llGetOwner() + (string)src); for(i = 0; i < 40; i += 4) { hash = hash * 0x12344321 + (integer)("0x" + llGetSubString(buffer, i, i + 3)); } if(hash == 0) { hash = 0x43019768; } return(hash); } sendMessage(string data_key, string data_value) { if(CHANNEL == 0){ CHANNEL = getOriginalKey( CHANNEL_NAME ); } llWhisper(CHANNEL, CHANNEL_NAME + data_key + "=" + data_value); } // 受信部分 receivedMessage(string data_key, string data_value) { llOwnerSay(data_key+"="+data_value); } string removeStartsWith(string data, string word) { if(llSubStringIndex(data, word) != 0) { return ""; } integer string_length = llStringLength(word); return(llGetSubString(data, string_length, -1)); } onFirstMessage( string message ) { string text = removeStartsWith(message, CHANNEL_NAME); if(text == "") { return; } integer equal_point = llSubStringIndex(text, "="); if(equal_point != -1) { integer string_length = llStringLength(text); string data_key = llGetSubString(text, 0, equal_point - 1); string data_value = llGetSubString(text, equal_point + 1, string_length - 1); receivedMessage(data_key, data_value); } } attachReceivedMessage() { if(CHANNEL == 0){ CHANNEL = getOriginalKey( CHANNEL_NAME ); } if(CHANNEL_HANDLE != 0) { llListenRemove(CHANNEL_HANDLE); CHANNEL_HANDLE = 0; } CHANNEL_HANDLE = llListen(CHANNEL, "", "", ""); } default { state_entry() { attachReceivedMessage(); } listen( integer channel, string name, key id, string message ) { onFirstMessage( message ); } }
コメント
lslはシムが制御してるから土地設定で禁止されると動かなくなるわけだけど、パーミッションを取った上でtakecontrolsして「アバターのもの」にする事でクライアント側から動く様になっちゃってるのかなーと思っとります。実際どういう処理にされてるか知らないけどね。