セカンドライフでタッチすると音がでるスクリプト。
特に連打防止機能をつけたものです。
具体的には1人に対して、 X 秒間次のクリックを防止します。
大勢からクリックされても、その1人1人に X 秒間のクリック防止機能が働きます。

当初は、連打すればするほどその人にペナルティー機能とかつけたりしましたが、
結局シンプルなコードへ落ち着きました。

技術的なアピールポイント
・メモリ断片化とかが発生しないように配列を使用していない
・少し冗長でもシンプルで分かりやすい
・連打防止のために時間を扱うが、ポーリングによる監視、タイマー割り込みを一切使用せずサーバーにやさしい

SimpleRendaBoushi5.lsl

// シンプルな連打防止機能付き再生機。5人まで管理。
// 自由に改造・配布OKです。
// code by natade

// 最後に押してから、そのユーザーの情報を消すまでの時間
// 長いほど、ユーザーが押せなくなる時間が長くなる
float G_fResetTimeSec	= 60.0;

// TRUE で最初に触った時のユーザーを表示させる
// FALSE で表示させない
integer G_bIsDrawName	= TRUE;

// 何の音を鳴らすか
key G_kSoundData		= "音声のUIDをここに";










// ---------------------------------------------------------------

checkMemory() { if(llGetFreeMemory() < 128) { llOwnerSay("Sorry. I will complete reset for memory release."); llResetScript(); }}

// メモリの再確保が必要であるため、配列は使わない
key G_kTouchUser1		= NULL_KEY;
key G_kTouchUser2		= NULL_KEY;
key G_kTouchUser3		= NULL_KEY;
key G_kTouchUser4		= NULL_KEY;
key G_kTouchUser5		= NULL_KEY;
integer G_bIsSetUser1	= FALSE;
integer G_bIsSetUser2	= FALSE;
integer G_bIsSetUser3	= FALSE;
integer G_bIsSetUser4	= FALSE;
integer G_bIsSetUser5	= FALSE;
float G_fUserTimerSec1		= 0.0;
float G_fUserTimerSec2		= 0.0;
float G_fUserTimerSec3		= 0.0;
float G_fUserTimerSec4		= 0.0;
float G_fUserTimerSec5		= 0.0;
integer G_bIsSetTimer	= FALSE;

// 新規のユーザーIDを取得する
integer getNewUserId() {
	integer	iNewUser = 1;
	float	fMaxTime = G_fUserTimerSec1;
	
	// NULL_KEY を使用する
	if(G_kTouchUser1 == NULL_KEY) {
		return 1;
	}
	else if(G_kTouchUser2 == NULL_KEY) {
		return 2;
	}
	else if(G_kTouchUser3 == NULL_KEY) {
		return 3;
	}
	else if(G_kTouchUser4 == NULL_KEY) {
		return 4;
	}
	else if(G_kTouchUser5 == NULL_KEY) {
		return 5;
	}
	// 時間が最も長いのを再利用する
	if(fMaxTime < G_fUserTimerSec2) {
		iNewUser = 2;
		fMaxTime = G_fUserTimerSec2;
	}
	else if(fMaxTime < G_fUserTimerSec3) {
		iNewUser = 3;
		fMaxTime = G_fUserTimerSec3;
	}
	else if(fMaxTime < G_fUserTimerSec4) {
		iNewUser = 4;
		fMaxTime = G_fUserTimerSec4;
	}
	else if(fMaxTime < G_fUserTimerSec5) {
		iNewUser = 5;
		fMaxTime = G_fUserTimerSec5;
	}
	return iNewUser;
}

// 新規ユーザー登録
addNewUser(key kTouchUser) {
	integer iNewUser = getNewUserId();
	// User 1
	if(iNewUser == 1) {
		G_kTouchUser1		= kTouchUser;
		G_fUserTimerSec1	= 0.0;
	}
	// User 2
	else if(iNewUser == 2) {
		G_kTouchUser2		= kTouchUser;
		G_fUserTimerSec2	= 0.0;
	}
	// User 3
	else if(iNewUser == 3) {
		G_kTouchUser3		= kTouchUser;
		G_fUserTimerSec3	= 0.0;
	}
	// User 4
	else if(iNewUser == 4) {
		G_kTouchUser4		= kTouchUser;
		G_fUserTimerSec4	= 0.0;
	}
	// User 5
	else if(iNewUser == 5) {
		G_kTouchUser5		= kTouchUser;
		G_fUserTimerSec5	= 0.0;
	}
}

// クリックしたユーザー
onTouch(key kTouchUser) {
	if(G_kTouchUser1 == kTouchUser) {
		return;
	}
	if(G_kTouchUser2 == kTouchUser) {
		return;
	}
	if(G_kTouchUser3 == kTouchUser) {
		return;
	}
	if(G_kTouchUser4 == kTouchUser) {
		return;
	}
	if(G_kTouchUser5 == kTouchUser) {
		return;
	}
	if(G_bIsDrawName) {
		llOwnerSay(llGetDisplayName(kTouchUser) + "さんが触りました…");
	}
	addNewUser(kTouchUser);
	llPlaySound(G_kSoundData, 1.0);
}

actTimeCorrection() {
	float fDeltaTime = llGetTime();
	// 時間を超えたものを削除する
	if(G_kTouchUser1 != NULL_KEY) {
		G_fUserTimerSec1 += fDeltaTime;
		if(G_fResetTimeSec <= G_fUserTimerSec1) {
			G_kTouchUser1	= NULL_KEY;
		}
	}
	if(G_kTouchUser2 != NULL_KEY) {
		G_fUserTimerSec2 += fDeltaTime;
		if(G_fResetTimeSec <= G_fUserTimerSec2) {
			G_kTouchUser2	= NULL_KEY;
		}
	}
	if(G_kTouchUser3 != NULL_KEY) {
		G_fUserTimerSec3 += fDeltaTime;
		if(G_fResetTimeSec <= G_fUserTimerSec3) {
			G_kTouchUser3	= NULL_KEY;
		}
	}
	if(G_kTouchUser4 != NULL_KEY) {
		G_fUserTimerSec4 += fDeltaTime;
		if(G_fResetTimeSec <= G_fUserTimerSec4) {
			G_kTouchUser4	= NULL_KEY;
		}
	}
	if(G_kTouchUser5 != NULL_KEY) {
		G_fUserTimerSec5 += fDeltaTime;
		if(G_fResetTimeSec <= G_fUserTimerSec5) {
			G_kTouchUser5	= NULL_KEY;
		}
	}
	llResetTime();
}

default {
	state_entry() {
	}
	changed( integer change ) {
		if( change & CHANGED_INVENTORY ) {
			llResetScript();
		}
		else if( change & CHANGED_OWNER ) {
			llResetScript();
		}
	}
	touch_start(integer num_detected) {
		if(num_detected == 1) {
			key touch_key = llDetectedKey(0);
			checkMemory();
			actTimeCorrection();
			onTouch(touch_key);
		}
	}
}

関連記事

  • セカンドライフでHSVとRGBを相互変換してみようセカンドライフでHSVとRGBを相互変換してみよう HSVというのは、いわゆるHSV色空間のことです。 これは、Hue(色相)、Saturation(彩度)、Value(明度)を表しておりましています。 ご存知?の通りRGBの色空間から、HSVの色空間へ変換が可能でして、 これを利用すれば、今のRGBの色から、少し濃い色にしたり、逆に薄い色にしたり、 明るい色にしたり、暗い色にしたり、色相を反転させたり、いろいろで […] Posted in セカンドライフ制作
  • アタッチメントのLSLテクニック1アタッチメントのLSLテクニック1 今回、アバターを作ったので、それにあたってアタッチメントのテクニックをいくつか紹介します。 1. […] Posted in セカンドライフ制作
  • セカンドライフでプログラム3(はねるボールを作ろう編)セカンドライフでプログラム3(はねるボールを作ろう編) こんばんは。 セカンドライフでは、どんなものでも手軽に作れてしまいます。 たとえば、右クリックメニューの制作を選ぶと、 いくつか好きな形のプリムを選べます。 上のメニューから分かるとおり、13種類ありまして、 さらにこのプリムそれぞれで、変形させたりもできて、より複雑な形を作れます。 また、プリムが基本的な形なるのですが、 1つのプリムを好きな形へ変 […] Posted in セカンドライフ制作
  • セカンドライフで被らないチャンネルの作り方セカンドライフで被らないチャンネルの作り方 セカンドライフで物づくりしてますと、 llSay / llRegionSayTo と llListen 使ってコマンドで物を操作することありますよね。 そんなときに、どの出力チャネル使おうか迷うことありませんか。 例えばですが、適当に25135034 […] Posted in セカンドライフ制作
  • セカンドライフでプログラム4(アバター情報取得編)セカンドライフでプログラム4(アバター情報取得編) セカンドライフでは、 自分のアバターも他人のアバターも固有のkeyで管理しています。 そのkey情報を使って、いろいろな情報を取得できます。 というわけで、さっそくスクリプトです。 情報別に関数に分けて使いやすい形にしてみました。 下記のスクリプトは、設置するとstartGetAvatorが呼ばれて、 半径10メートルにいるアバターの情報を取得します。 […] Posted in セカンドライフ制作
  • セカンドライフでプログラム7( llSetTextureAnim の SMOOTH 編 )セカンドライフでプログラム7( llSetTextureAnim の SMOOTH 編 ) はじめに llSetTextureAnim はテクスチャを常にアニメーションさせるために必要な関数です。この中のモード SMOOTH は、 そんなに解説が書いていないので、なんとなくサンプルを丸コピーして、適当にいじって動かしているという方も多いと思います。そこで今回は、この llSetTextureAnim の SMOOTH […] Posted in セカンドライフ制作