2008年06月26日
【スクリプト】キャンプチェアーのスクリプト(その2)
以前にこのブログに書いたキャンプチェアーのスクリプト(http://sasapy.slmame.com/e147429.html)にリクエストがあったので、新たに記事にします。
リクエストというのは「座りポーズを変えたい」ということで、スクリプトで保持しているパーミッションの関係などがあり、元記事を直すよりは、新たに立てた方が分かりやすいかなと思ったわけです。
さらに、予想外の問題があることが分かりました。
というのは、キャンプしている座る部分に、無理矢理他のアバターが座ってきた場合、キャンプが中断されてしまうということです。
<パーミッションについて>
サンプルでは椅子本体(ルートプリム)と実際に座るシート(子プリム)で構成しているオブジェクトで、キャンプによる金銭の支払いは各シートで行っています。
ということはオーナーの支払パーミッションは各シートで保持しています。
1スクリプトで保持できるパーミッションは1アバターに限りますので、座っているアバターにポーズ(アニメーション)をさせるということはパーミッションが必要になってきますので、同じスクリプトでは不可能になってきます。
そこで現在の子プリム用のスクリプトとは別にアニメーションをさせるスクリプトを同じプリムに入れる必要が出てきます。
現在の子プリム用のスクリプト(以下、子プリムスクリプト)と新たなポーズ用スクリプト(以下、ポーズスクリプト)の間の通信はリンクメッセージを使い、子プリムスクリプトからアニメーションの開始・停止の指示だけだします。
<割り込みキャンプについて>
同じ場所に座ってくるというのは予想外の行動で、そんないじわるな人がいるのか・・・と思いますが、対応しなければならないでしょう。
スクリプト中にコメントを書いている部分に条件判定をひとつ追加しました。
<ポーズスクリプトについて>
ポーズが一つではないということでしたので、複数のポーズをキャンプをするたびに切り替えることにしました。
子プリムスクリプトからリンクメッセージを受け、開始の場合はメッセージ中のidからアバターのキーを取得し、アニメーションのパーミッション要求・取得を行います。
パーミッションを取得すればリスト番号を更新してリストからアニメーション名を取得して、そのアニメーションを実行します。
リンクメッセージが停止の場合は、単純にアニメーションを停止しています。
では、まず子プリム用のスクリプトです。
//==================================================
// sasa_camp_child
// 1.0.0 2008/02/15
// 2.0.0 2008/06/20 アニメーションをするように処理追加
// 2.1.0 2008/06/20 座っている場所に座ってきた場合の処理追加
// created by sasapy Beck
//--------------------------------------------------
// Mode (スクリプトの動作に関わります。)
integer GROUP_ONLY = FALSE; // FALSE:誰でも
// TRUE:同じグループのみ可
float SECOND_MINI = 1200.0; // 最小時間1200.0秒 = 20分
integer MONEY_MINI = 2; // 最小金額2L$
integer MONEY_MAX = 10; // 最大金額10L$
//--------------------------------------------------
// Define
integer LINK_MSG_RESET = 11; // メッセージ番号
integer LINK_MSG_REQUEST = 21;
integer LINK_MSG_ANSWER = 31;
integer LINK_MSG_LIMIT_NG = 32;
integer LINK_MSG_TIME_NG = 33;
integer LINK_MSG_CONTINUE_NG = 34;
integer LINK_MSG_STAND = 41;
integer LINK_MSG_START_ANIME = 51;
integer LINK_MSG_STOP_ANIME = 52;
float now_time = 0.0; // 経過時間
integer last_money = 0; // 前回までの金額(1日単位)
integer now_money = 0; // 現在の金額
vector SIT_OFFSET = <0.3, 0.0, 0.5>; // 座る位置
vector SIT_ROTATION = <0.0, 0.0, 0.0>; // 座る回転
integer same_group; // アクティブグループが同一か
string GROUP_NAME = "group name"; // グループのみキャンプ可のグループ名
key owner_key = NULL_KEY; // オーナーキー
key avatar_key = NULL_KEY; // アバターキー
key camper_key = NULL_KEY; // キャンプ対象アバターキー
// 座ったときはavatar_key、キャンプ開始したらcamper_key
// プリムをリンクしているので座ったとき/立ち上がったときのイベントが、座っていない場所でも発生する
// 立ち上がったときのイベントでcamper_keyを判定し、自プリムかどうか判定する
vector COLOR_OFF = <1.0, 1.0, 1.0>; // 白
vector COLOR_ON = <1.0, 0.0, 0.0>; // 赤
//--------------------------------------------------
// Main
default
{
state_entry()
{
owner_key = llGetOwner(); // オーナーキー取得
llSitTarget(SIT_OFFSET, llEuler2Rot(SIT_ROTATION * DEG_TO_RAD)); // 座る位置指定
// 保持パーミッションがオーナーの場合
// 保持パーミッションが支払いの場合
// REZしたらllResetScriptしているので、パーミションは持っていない。条件判断しないでllRequestPermissionsするほうがよい。こういうパターンということでそのまま記述
if((llGetPermissionsKey() == owner_key) && (llGetPermissions() & PERMISSION_DEBIT))
{
state operation;
}
else
{
llRequestPermissions(owner_key, PERMISSION_DEBIT);
}
}
// Rez Event
on_rez(integer start_param)
{
llResetScript();
}
// Permission Event
run_time_permissions(integer perm)
{
if(perm & PERMISSION_DEBIT)
{
state operation;
}
}
}
//--------------------------------------------------
state operation
{
state_entry()
{
llOwnerSay("Camp start");
}
// Rez Event
on_rez(integer start_param)
{
llResetScript();
}
// Change Event
changed(integer change)
{
if(change & CHANGED_LINK)
{
avatar_key = llAvatarOnSitTarget();
// 座った場合
if(avatar_key != NULL_KEY)
{
// 座っているのに同じ場所に座ってきた場合の処理追加
if(camper_key == NULL_KEY) // 自プリムが空いている場合
{
same_group = llSameGroup(avatar_key); // アクティブグループが同じ場合TRUE
// グループのみ可で、アクティブグループが違う場合
if(GROUP_ONLY && !same_group)
{
llUnSit(avatar_key); // 立たせる
llSay(PUBLIC_CHANNEL, "This camp is Group Only. Please active group : " + GROUP_NAME);
}
// グループ不問、またはグループのみ可の時のグループメンバーの場合
else
{
// ルートにリクエストを送信
llMessageLinked(LINK_ROOT, LINK_MSG_REQUEST, "", avatar_key);
}
}
}
// 途中で立ち上がった場合
else
{
if(camper_key != NULL_KEY) // 自プリムでキャンプしていた
{
llMessageLinked(LINK_THIS, LINK_MSG_STOP_ANIME, "", camper_key); // アニメーションの停止
llSay(PUBLIC_CHANNEL, "You stopped camping.");
// 今回の金額が発生する場合
if(now_money > 0)
{
llSay(PUBLIC_CHANNEL, "I pay " + (string)now_money + "L$.");
llGiveMoney(camper_key, now_money); // 支払い
llMessageLinked(LINK_ROOT, LINK_MSG_STAND, (string)(last_money + now_money), camper_key); // ルートに情報送信
}
camper_key = NULL_KEY; // キーのクリア
llSetTimerEvent(0.0); // タイマー停止
llSetText("Camp chair\n" + (string)MONEY_MINI + " L$ / " + (string)llFloor(SECOND_MINI / 60.0) + " min", COLOR_OFF, 1.0); // テキスト表示
}
}
}
}
// Link Message Event
link_message(integer sender_num, integer num, string str, key id)
{
// 許可メッセージの場合
if(num == LINK_MSG_ANSWER)
{
last_money = (integer)str; // 前回までの金額
camper_key = id; // キー取得
now_time = 0.0; // キャンプ時間の初期化
now_money = 0; // 今回金額の初期化
llSetText("Your camp\n" + (string)now_money + " L$ / " + (string)llFloor(now_time / 60.0) + " min", COLOR_ON, 1.0); // テキスト表示
llSetTimerEvent(SECOND_MINI); // 最小時間でタイマー起動
llMessageLinked(LINK_THIS, LINK_MSG_START_ANIME, "", camper_key); // アニメーション開始
}
// 金額上限の場合
else if(num == LINK_MSG_LIMIT_NG)
{
llUnSit(avatar_key); // 立たせる
llSay(PUBLIC_CHANNEL, "You reached the limit of 1 day. Please camp tomorrow.");
}
// 前回キャンプから経過時間が少ない場合
else if(num == LINK_MSG_TIME_NG)
{
llUnSit(avatar_key); // 立たせる
llSay(PUBLIC_CHANNEL, "Your time does not pass from the last camping. Please camp after doing it for a while.");
}
// 連続の場合
else if(num == LINK_MSG_CONTINUE_NG)
{
llUnSit(avatar_key); // 立たせる
llSay(PUBLIC_CHANNEL, "You cannot camp in succession. Please camp after doing it for a while.");
}
}
// Timer Event
// 最小時間でタイマーイベント発生
timer()
{
now_time += SECOND_MINI; // キャンプ時間の更新
now_money += MONEY_MINI; // 今回金額の更新
llSetText("Your camp\n" + (string)now_money + " L$ / " + (string)llFloor(now_time / 60.0) + " min", COLOR_ON, 1.0); // テキスト表示
// 前回までの金額と今回の金額で上限となった場合
if((last_money + now_money) >= MONEY_MAX)
{
llMessageLinked(LINK_THIS, LINK_MSG_STOP_ANIME, "", camper_key); // アニメーションの停止
llUnSit(camper_key); // 立たせる
llSay(PUBLIC_CHANNEL, "You reached the limit of 1 day. Please camp tomorrow.");
llSay(PUBLIC_CHANNEL, "I pay " + (string)now_money + " L$.");
llGiveMoney(camper_key, now_money); // 支払い
llMessageLinked(LINK_ROOT, LINK_MSG_STAND, (string)(last_money + now_money), camper_key); // ルートに情報送信
camper_key = NULL_KEY; // キークリア
llSetTimerEvent(0.0); // タイマー停止
llSetText("Camp chair\n" + (string)MONEY_MINI + " L$ / " + (string)llFloor(SECOND_MINI / 60.0) + " min", COLOR_OFF, 1.0); // テキスト表示
}
}
}
//==================================================
次に新たに子プリムに追加するポーズ用のスクリプトです。
//==================================================
// sasa_camp_animation
// 1.1.0
// 2008/06/20
// created by sasapy Beck
//--------------------------------------------------
// Define
list ANIMATION_NAME = [ "anime1",
"anime2",
"anime3"
]; // 座ったときのアニメーション名
integer animation_number = 0; // アニメーション番号
integer animation_max = 0; // アニメーション数
integer LINK_MSG_START_ANIME = 51;
integer LINK_MSG_STOP_ANIME = 52;
//--------------------------------------------------
// Main
default
{
state_entry()
{
animation_max = llGetListLength(ANIMATION_NAME);
}
// Link Message Event
link_message(integer sender_num, integer num, string str, key id)
{
if(num == LINK_MSG_START_ANIME) // アニメーション開始メッセージの場合
{
if((llGetPermissionsKey() == id) && (llGetPermissions() & PERMISSION_DEBIT)) // パーミッションがある場合
{
animation_number ++;
if(animation_number >= animation_max) animation_number = 0;
llStartAnimation(llList2String(ANIMATION_NAME, animation_number)); // アニメーション開始
}
else // パーミッションがない場合
{
llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION); // アニメーションのパーミッション要求
}
}
else if(num == LINK_MSG_STOP_ANIME) // アニメーション停止メッセージの場合
{
llStopAnimation(llList2String(ANIMATION_NAME, animation_number)); // アニメーション停止
}
}
// Permission Event
run_time_permissions(integer perm)
{
if(perm & PERMISSION_TRIGGER_ANIMATION) // アニメーション許可
{
animation_number ++;
if(animation_number >= animation_max) animation_number = 0;
llStartAnimation(llList2String(ANIMATION_NAME, animation_number)); // アニメーション開始
}
}
}
//--------------------------------------------------
(赤文字:変更してください、 青文字:お好みで変更してください)
リクエストというのは「座りポーズを変えたい」ということで、スクリプトで保持しているパーミッションの関係などがあり、元記事を直すよりは、新たに立てた方が分かりやすいかなと思ったわけです。
さらに、予想外の問題があることが分かりました。
というのは、キャンプしている座る部分に、無理矢理他のアバターが座ってきた場合、キャンプが中断されてしまうということです。
<パーミッションについて>
サンプルでは椅子本体(ルートプリム)と実際に座るシート(子プリム)で構成しているオブジェクトで、キャンプによる金銭の支払いは各シートで行っています。
ということはオーナーの支払パーミッションは各シートで保持しています。
1スクリプトで保持できるパーミッションは1アバターに限りますので、座っているアバターにポーズ(アニメーション)をさせるということはパーミッションが必要になってきますので、同じスクリプトでは不可能になってきます。
そこで現在の子プリム用のスクリプトとは別にアニメーションをさせるスクリプトを同じプリムに入れる必要が出てきます。
現在の子プリム用のスクリプト(以下、子プリムスクリプト)と新たなポーズ用スクリプト(以下、ポーズスクリプト)の間の通信はリンクメッセージを使い、子プリムスクリプトからアニメーションの開始・停止の指示だけだします。
<割り込みキャンプについて>
同じ場所に座ってくるというのは予想外の行動で、そんないじわるな人がいるのか・・・と思いますが、対応しなければならないでしょう。
スクリプト中にコメントを書いている部分に条件判定をひとつ追加しました。
<ポーズスクリプトについて>
ポーズが一つではないということでしたので、複数のポーズをキャンプをするたびに切り替えることにしました。
子プリムスクリプトからリンクメッセージを受け、開始の場合はメッセージ中のidからアバターのキーを取得し、アニメーションのパーミッション要求・取得を行います。
パーミッションを取得すればリスト番号を更新してリストからアニメーション名を取得して、そのアニメーションを実行します。
リンクメッセージが停止の場合は、単純にアニメーションを停止しています。
では、まず子プリム用のスクリプトです。
//==================================================
// sasa_camp_child
// 1.0.0 2008/02/15
// 2.0.0 2008/06/20 アニメーションをするように処理追加
// 2.1.0 2008/06/20 座っている場所に座ってきた場合の処理追加
// created by sasapy Beck
//--------------------------------------------------
// Mode (スクリプトの動作に関わります。)
integer GROUP_ONLY = FALSE; // FALSE:誰でも
// TRUE:同じグループのみ可
float SECOND_MINI = 1200.0; // 最小時間1200.0秒 = 20分
integer MONEY_MINI = 2; // 最小金額2L$
integer MONEY_MAX = 10; // 最大金額10L$
//--------------------------------------------------
// Define
integer LINK_MSG_RESET = 11; // メッセージ番号
integer LINK_MSG_REQUEST = 21;
integer LINK_MSG_ANSWER = 31;
integer LINK_MSG_LIMIT_NG = 32;
integer LINK_MSG_TIME_NG = 33;
integer LINK_MSG_CONTINUE_NG = 34;
integer LINK_MSG_STAND = 41;
integer LINK_MSG_START_ANIME = 51;
integer LINK_MSG_STOP_ANIME = 52;
float now_time = 0.0; // 経過時間
integer last_money = 0; // 前回までの金額(1日単位)
integer now_money = 0; // 現在の金額
vector SIT_OFFSET = <0.3, 0.0, 0.5>; // 座る位置
vector SIT_ROTATION = <0.0, 0.0, 0.0>; // 座る回転
integer same_group; // アクティブグループが同一か
string GROUP_NAME = "group name"; // グループのみキャンプ可のグループ名
key owner_key = NULL_KEY; // オーナーキー
key avatar_key = NULL_KEY; // アバターキー
key camper_key = NULL_KEY; // キャンプ対象アバターキー
// 座ったときはavatar_key、キャンプ開始したらcamper_key
// プリムをリンクしているので座ったとき/立ち上がったときのイベントが、座っていない場所でも発生する
// 立ち上がったときのイベントでcamper_keyを判定し、自プリムかどうか判定する
vector COLOR_OFF = <1.0, 1.0, 1.0>; // 白
vector COLOR_ON = <1.0, 0.0, 0.0>; // 赤
//--------------------------------------------------
// Main
default
{
state_entry()
{
owner_key = llGetOwner(); // オーナーキー取得
llSitTarget(SIT_OFFSET, llEuler2Rot(SIT_ROTATION * DEG_TO_RAD)); // 座る位置指定
// 保持パーミッションがオーナーの場合
// 保持パーミッションが支払いの場合
// REZしたらllResetScriptしているので、パーミションは持っていない。条件判断しないでllRequestPermissionsするほうがよい。こういうパターンということでそのまま記述
if((llGetPermissionsKey() == owner_key) && (llGetPermissions() & PERMISSION_DEBIT))
{
state operation;
}
else
{
llRequestPermissions(owner_key, PERMISSION_DEBIT);
}
}
// Rez Event
on_rez(integer start_param)
{
llResetScript();
}
// Permission Event
run_time_permissions(integer perm)
{
if(perm & PERMISSION_DEBIT)
{
state operation;
}
}
}
//--------------------------------------------------
state operation
{
state_entry()
{
llOwnerSay("Camp start");
}
// Rez Event
on_rez(integer start_param)
{
llResetScript();
}
// Change Event
changed(integer change)
{
if(change & CHANGED_LINK)
{
avatar_key = llAvatarOnSitTarget();
// 座った場合
if(avatar_key != NULL_KEY)
{
// 座っているのに同じ場所に座ってきた場合の処理追加
if(camper_key == NULL_KEY) // 自プリムが空いている場合
{
same_group = llSameGroup(avatar_key); // アクティブグループが同じ場合TRUE
// グループのみ可で、アクティブグループが違う場合
if(GROUP_ONLY && !same_group)
{
llUnSit(avatar_key); // 立たせる
llSay(PUBLIC_CHANNEL, "This camp is Group Only. Please active group : " + GROUP_NAME);
}
// グループ不問、またはグループのみ可の時のグループメンバーの場合
else
{
// ルートにリクエストを送信
llMessageLinked(LINK_ROOT, LINK_MSG_REQUEST, "", avatar_key);
}
}
}
// 途中で立ち上がった場合
else
{
if(camper_key != NULL_KEY) // 自プリムでキャンプしていた
{
llMessageLinked(LINK_THIS, LINK_MSG_STOP_ANIME, "", camper_key); // アニメーションの停止
llSay(PUBLIC_CHANNEL, "You stopped camping.");
// 今回の金額が発生する場合
if(now_money > 0)
{
llSay(PUBLIC_CHANNEL, "I pay " + (string)now_money + "L$.");
llGiveMoney(camper_key, now_money); // 支払い
llMessageLinked(LINK_ROOT, LINK_MSG_STAND, (string)(last_money + now_money), camper_key); // ルートに情報送信
}
camper_key = NULL_KEY; // キーのクリア
llSetTimerEvent(0.0); // タイマー停止
llSetText("Camp chair\n" + (string)MONEY_MINI + " L$ / " + (string)llFloor(SECOND_MINI / 60.0) + " min", COLOR_OFF, 1.0); // テキスト表示
}
}
}
}
// Link Message Event
link_message(integer sender_num, integer num, string str, key id)
{
// 許可メッセージの場合
if(num == LINK_MSG_ANSWER)
{
last_money = (integer)str; // 前回までの金額
camper_key = id; // キー取得
now_time = 0.0; // キャンプ時間の初期化
now_money = 0; // 今回金額の初期化
llSetText("Your camp\n" + (string)now_money + " L$ / " + (string)llFloor(now_time / 60.0) + " min", COLOR_ON, 1.0); // テキスト表示
llSetTimerEvent(SECOND_MINI); // 最小時間でタイマー起動
llMessageLinked(LINK_THIS, LINK_MSG_START_ANIME, "", camper_key); // アニメーション開始
}
// 金額上限の場合
else if(num == LINK_MSG_LIMIT_NG)
{
llUnSit(avatar_key); // 立たせる
llSay(PUBLIC_CHANNEL, "You reached the limit of 1 day. Please camp tomorrow.");
}
// 前回キャンプから経過時間が少ない場合
else if(num == LINK_MSG_TIME_NG)
{
llUnSit(avatar_key); // 立たせる
llSay(PUBLIC_CHANNEL, "Your time does not pass from the last camping. Please camp after doing it for a while.");
}
// 連続の場合
else if(num == LINK_MSG_CONTINUE_NG)
{
llUnSit(avatar_key); // 立たせる
llSay(PUBLIC_CHANNEL, "You cannot camp in succession. Please camp after doing it for a while.");
}
}
// Timer Event
// 最小時間でタイマーイベント発生
timer()
{
now_time += SECOND_MINI; // キャンプ時間の更新
now_money += MONEY_MINI; // 今回金額の更新
llSetText("Your camp\n" + (string)now_money + " L$ / " + (string)llFloor(now_time / 60.0) + " min", COLOR_ON, 1.0); // テキスト表示
// 前回までの金額と今回の金額で上限となった場合
if((last_money + now_money) >= MONEY_MAX)
{
llMessageLinked(LINK_THIS, LINK_MSG_STOP_ANIME, "", camper_key); // アニメーションの停止
llUnSit(camper_key); // 立たせる
llSay(PUBLIC_CHANNEL, "You reached the limit of 1 day. Please camp tomorrow.");
llSay(PUBLIC_CHANNEL, "I pay " + (string)now_money + " L$.");
llGiveMoney(camper_key, now_money); // 支払い
llMessageLinked(LINK_ROOT, LINK_MSG_STAND, (string)(last_money + now_money), camper_key); // ルートに情報送信
camper_key = NULL_KEY; // キークリア
llSetTimerEvent(0.0); // タイマー停止
llSetText("Camp chair\n" + (string)MONEY_MINI + " L$ / " + (string)llFloor(SECOND_MINI / 60.0) + " min", COLOR_OFF, 1.0); // テキスト表示
}
}
}
//==================================================
次に新たに子プリムに追加するポーズ用のスクリプトです。
//==================================================
// sasa_camp_animation
// 1.1.0
// 2008/06/20
// created by sasapy Beck
//--------------------------------------------------
// Define
list ANIMATION_NAME = [ "anime1",
"anime2",
"anime3"
]; // 座ったときのアニメーション名
integer animation_number = 0; // アニメーション番号
integer animation_max = 0; // アニメーション数
integer LINK_MSG_START_ANIME = 51;
integer LINK_MSG_STOP_ANIME = 52;
//--------------------------------------------------
// Main
default
{
state_entry()
{
animation_max = llGetListLength(ANIMATION_NAME);
}
// Link Message Event
link_message(integer sender_num, integer num, string str, key id)
{
if(num == LINK_MSG_START_ANIME) // アニメーション開始メッセージの場合
{
if((llGetPermissionsKey() == id) && (llGetPermissions() & PERMISSION_DEBIT)) // パーミッションがある場合
{
animation_number ++;
if(animation_number >= animation_max) animation_number = 0;
llStartAnimation(llList2String(ANIMATION_NAME, animation_number)); // アニメーション開始
}
else // パーミッションがない場合
{
llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION); // アニメーションのパーミッション要求
}
}
else if(num == LINK_MSG_STOP_ANIME) // アニメーション停止メッセージの場合
{
llStopAnimation(llList2String(ANIMATION_NAME, animation_number)); // アニメーション停止
}
}
// Permission Event
run_time_permissions(integer perm)
{
if(perm & PERMISSION_TRIGGER_ANIMATION) // アニメーション許可
{
animation_number ++;
if(animation_number >= animation_max) animation_number = 0;
llStartAnimation(llList2String(ANIMATION_NAME, animation_number)); // アニメーション開始
}
}
}
//--------------------------------------------------
(赤文字:変更してください、 青文字:お好みで変更してください)
この記事へのトラックバックURL
http://sasapy.slmame.com/t285828
