アタッチメントのLSLテクニック1

セカンドライフ制作
スポンサーリンク

今回、アバターを作ったので、それにあたってアタッチメントのテクニックをいくつか紹介します。

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 );
	}

}

コメント

  1. 匿名 より:

    lslはシムが制御してるから土地設定で禁止されると動かなくなるわけだけど、パーミッションを取った上でtakecontrolsして「アバターのもの」にする事でクライアント側から動く様になっちゃってるのかなーと思っとります。実際どういう処理にされてるか知らないけどね。

タイトルとURLをコピーしました