2012/06/17

またもや引越し!?

またもや引越しです。
今回の引越しは、このブログに何か問題があるということではなくて、引越し先に、スクリプトをきれいに書いてくれる機能がある!という単純な理由です。

引越し先はこちら
http://www4.atword.jp/lovemax/
(今システムを修理中のようです…2013/9/16)
(サービス終了になるそうです…2014/4/30)

2012/06/16

むふふなHUD


むふふ商品を使うときに、チャットでタイプするのが面倒なら、HUD(ヘッドアップディスプレイ)を使ってマウスのクリック(タッチ)だけですます方法もあります。

写真のようなものを装着すると、画面上中央のように見えます。
そのマークをタッチするというのは、装着したオブジェクトをタッチしているわけです。

HUDのスクリプトでは、タッチした面の面番号に割当てたマークを、専用のチャンネルでむふふ商品に伝えます。
default {
  touch_start(integer num_detected) {
    string mark = llList2String( Marks,
        llDetectedTouchFace(0) );
        // タッチした面に対応するマーク
    string message = (string)llGetOwner()+":"+mark;
      // 所有者キーと一緒に送る(万一の混線防止)
    llWhisper( HUDchannel, message );
  }
}
むふふ商品側では、それを聞いて、角度を変えたり変形させたりするわけです。
実際のスクリプトはチャットも聞きますが、ここでは省略しています。
default {
 state_entry() {
  llListen( HUDchannel, HUDname, NULL_KEY, "" );
      // HUD専用チャンネルで連絡を待つ
 }
 listen( integer channel, string name, key id, string message ) {
  string s;
  integer n = 1;
  if ( channel == HudChannel ) { // HUDチャンネルから聞こえた
   list info = llParseString2List( message, [":"], [] );
   if ( llGetOwner() != llList2Key(info,0) ) return; // 混線防止
   s = llGetSubString(llList2String(info,1),0,0);
  }
  // (角度変更部分も省略)
  else if ( s == "*" ) { // 「*」マークなら
   llMessageLinked(LINK_THIS,Transform, // 変形スクリプトに連絡
     "Transform:" + (string)TransSteps, NULL_KEY);
  }
 }
}

2012/06/15

むふふな変身


むふふな商品には2種類あって、男性用と女性用です。
めんどくさいのは男性用で、元気なときと休憩のときでは、形がかなり違うので、「変身」させなければなりません。
例によって写真はお人形?で代用してます。

この変身の命令は、チャットで「/8*」のように言いますが、本体スクリプトがチャットを聞き、変身専用のスクリプトに「Transform:10」のような連絡を送り、変身はこの専用スクリプトが行います。

変身スクリプトには、あらかじめ元気なとき(オン)と休憩中(オフ)の各プリムパーツの位置・大きさ・角度などのパラメータが記録されています。
オンとオフの数字の切り替えが「変身」というわけですが、実際には一気に替えるのではなく、何段階かのステップを踏んで少しづつ変えます。
こうすると見た目には、にょきーっと立ち上がったり、ふにゃ~としぼんだり、アニメーションのように見えるのですね。

変身スクリプト(全部は長いので、かなり省略しています)
list Params = [
 <3.8,0,-2.4>,<6,6,5>,<0,40,0>,  <7,0,-0.2>,<15,6,5.5>,<0,0,0>, // 体
 <4.5,0,-4>,<6,5,6.5>,<0,0,90>,  <12,0,0>,<7,8,6>,<0,0,90> // 頭
 ]; // オフのときの位置・大きさ・角度、オンのときの位置・大きさ・角度
 
stepForm( float step ) { // 変身中の各段階の形
 list rules;
 integer link = 2;
 for ( ; link<=3; ++link ) { // リンクしている各部品に
  rules = [PRIM_POSITION, stepParams(link,step,0) * Ratio]; // 各数字の設定
  rules += [PRIM_SIZE, stepParams(link,step,1) * Ratio];
  rules += [PRIM_ROT_LOCAL, llEuler2Rot(stepParams(link,step,2)*DEG_TO_RAD)];
  llSetLinkPrimitiveParamsFast(link,rules); // 各部品にパラメータを設定
 }
}
transForm(integer n) { // n段階で変身
 integer i = 1;
 float step;
 for ( ; i<=n; ++i ) {
  if (Active == 1) step = (float)i/(float)n; // オフ→オンのとき
  else step = (float)(n-i)/(float)n; // オン→オフのとき
  stepForm( step ); // 変身中の各段階の形
 }
}
 
default {
 link_message(integer from, integer script, string msg, key id) {
  list info = llParseString2List( msg, [":"], [] );
  if ( llList2String(info,0) == "Transform" ) { // 「変身」の連絡を受ける
   integer n = (integer)llList2String(info,1); // 変身の段階数
   if (Active == 1) Active = 0; // オン/オフの切り替え
   else Active = 1;
   transForm(n); // n段階で変身
  }
 }
}

2012/06/14

むふふな角度調整


さて、そもそものはじまりのアダルト用品ですが、むふふな時に一番大事なのは角度調整だと思います。
角度ぴったりだと、らぶらぶ度もぐんとアップしますね。

写真は、本物では刺激が強すぎるかもしれないので、お人形?で代用してます。
左がもとの状態だとすると、右のは30度ほど傾いてます。

角度を調整するためには、チャットで「/8++」のように言います。
「/8」はチャンネル指定、「+」「-」が5度きざみの角度指定で「++」なら10度アップになります。
「/8.」でもとに戻ります。

スクリプトでは
default {
 state_entry() {
  llListen( ChatChannel, "", llGetOwner(), "" );
   // 指定チャンネルで所有者の命令を聞く
  llSetRot(llAxisAngle2Rot(Axis,Angle*DEG_TO_RAD));
   // 回転軸と角度で回転を設定
 }
 listen( integer channel, string name, key id, string message ) {
  string s = llGetSubString(message,0,0); // 先頭の文字
  integer n = llStringLength(message); // 文字列の長さ
  if ( s == "+" || s == "-" ) { // 先頭が「+」「-」なら
   if ( s == "+" ) Angle += Step * n; // 角度を変更
   else Angle -= Step * n;
   llSetRot(llAxisAngle2Rot(Axis,Angle*DEG_TO_RAD)); // 回転を設定
  }
  else if ( s == "." ) llResetScript(); // 「.」もとに戻る
 }
}
築地のお店はこちら(SLurl)
http://slurl.com/secondlife/TSUKIJI/90/47/22/
ただし、むふふな商品は地上には置いてません。
上空のアダルト用品売場にあります。(テレポートで行けます)
または通販ショップからどうぞ。
https://marketplace.secondlife.com/stores/97156

2012/06/13

飛行船のプロペラの回転


飛行船のプロペラは、動きに合わせて回転するようになってます。
本体のスクリプトからリンクメッセージで連絡をもらって、回転の向きや速度を変えます。

飛行船アバターの場合は、アニメーション名を聞いて速度だけ変えてます。
(「飛行船アバターのAO」で説明しているスクリプトでは連絡の部分は省略しています)

飛行船アバターのプロペラのスクリプト
vector Axis = <1,0,0>; // 回転軸:X
float Fwd = -PI; // 左プロペラの回転、右はPI
 
default {
 state_entry()  {
  llTargetOmega(ZERO_VECTOR,0,0);
 }
 link_message(integer from, integer int, string msg, key id) {
   // 再生中のアニメーション名を聞く
  float spin;
  if (msg == "hover") spin = Fwd * 0.5; // 回転速度を変える
  else if (msg == "walk") spin = Fwd;
  else if (msg == "fly") spin = Fwd * 2;
  else llResetScript();
  llTargetOmega(Axis, spin, 1); // 軸の周りを回転
 }
}

2012/06/12

飛行船アバターのAO


飛行船アバターを作ったきっかけは、写真の初期アバターです。
人格なしのアカウントのつもりだったので、どうせなら、とまったく人に見えないのを選んだわけですが(ほかに動物やロボット、車型もありました)、人型でも初期アバターに不満がでてくるように、他人の作った姿のままでいるのは抵抗あったので、自分で作り直しました。

アダルト商品取り扱いなので、ちょっとワイルド風味に海賊ぽいマークをつけて、その流れで人型の服装も海賊コスプレなわけです。
(商品の飛行船は、海賊マークなしです。)

アバターのアニメーションも自前のに変えました。
といっても、ふわふわ高さを変えたりする程度ですが、手足のない飛行船に細かいアニメーションは必要ないので都合よいです。

下のスクリプトは、アニメーションを自分のに変更する、つまりAO(アニメーションオーバーライド)ですね。
default {
 attach(key id) {
  if (id) { // 装着されたらアニメーション変更の許可を依頼
   llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION);
   Id = id;
  }
  else { // とり外されたら今のアニメーションを止める
   if (Anim) llStopAnimation(Anim);
   llResetScript();
  }
 }
 run_time_permissions(integer perm) { // 継続的に
  if (perm & PERMISSION_TRIGGER_ANIMATION) llSetTimerEvent(0.2);
 }
 timer() {
  string anim = llGetAnimation(Id); // 再生中のアニメーションを調べる
  if (anim == "Walking") anim = "walk"; // 組込アニメーションを自分のに変更
  else if (anim == "Running" || anim == "Flying") anim = "fly";
  else anim = "hover";
  if (Anim == anim) return; // 前と同じなら 戻る
  if (Anim) llStopAnimation(Anim); // 前のアニメーションを止める
  llStartAnimation(anim); // 新しいアニメーションを始める
  Anim = anim;
 }
}
LSLポータルのllGetAnimation()のところに組込アニメーションの説明と簡単なAOのサンプルがあります。
http://wiki.secondlife.com/wiki/LlGetAnimation/ja

2012/06/11

オンライン伝言板


築地のお店にオンライン伝言板を置いています。
タッチしてチャットで何か言うと、私がオンラインのときに伝言として送ります。
何も用事はなくても、ひやかしでもいいので、何か送ってみてください。
「ブログ見たよ」でもいいので^^

スクリプトでは、タッチした人の伝言が聞こえたらそれを記録して、私がオンラインかどうか問合せ、オンラインだったら伝言を送ります。
一定時間たっても何も聞こえないときは、聞くのをやめます。
問合せてもしオフラインだったら何もしないのですが、一定時間ごとにオンラインかどうか問合せするので、オンラインになった時にまとめて送るしくみになってます。

実際のスクリプトは、オンライン/オフラインの表示など、もっといろんなこともしてますが、伝言を聞いて送る部分はこんな感じです…。
default {
 state_entry() {
  Owner = llGetOwner();
  llSetTimerEvent(StepTime);
 }
 touch_start(integer touch_num) { // 誰かがタッチしたら
  llWhisper(0, "Say your message on chat.");
  Handle = llListen(0, "", llDetectedKey(0), ""); // 伝言を待つ
  llSetTimerEvent(StepTime);
 }
 listen(integer channel, string name, key id, string message) { // 伝言を聞いたら
  llWhisper(0, "Thank you for your message.");
  removeListen(); // 聞くのをやめる
  Messages += name+": "+message; // 名前と伝言を記録
  llRequestAgentData(Owner, DATA_ONLINE); // オンラインを問合せ
 }
 timer() { // 一定時間たったら
  if (Handle) removeListen(); // 伝言待ちなら聞くのをやめる
  llRequestAgentData(Owner, DATA_ONLINE); // オンラインを問合せ
 }
 dataserver(key query, string online) { // 問合せの答
  if ((integer)online == TRUE && Messages != []) {
   // 所有者がオンラインで、伝言があればIMを送る
   llInstantMessage(Owner, llDumpList2String(Messages,"\n\t"));
   llResetScript();
  }
 }
}
築地のお店

2012/06/10

スカイボックス


スカイボックス「MyBox」は、サンドボックスなどの上空に臨時の部屋やプラットフォームなどを出して、もの作りの作業や着替えなどができるようにしたものです。

箱に座って、メニューで上空に行って部屋などを出し、用がすんだら「Clear」で片付けます。
写真は築地のお店のデモ機で、場所が狭いので小さめの8m四方のプラットフォームを出しています。
商品では標準で20m四方、サイズ変更でもっと大きくもできます。

下に、スクリプトの部屋を出す(Rez)ところと、「Clear」で片付けるところを書きます。
片付けるときには、llDie()という、名前からして恐ろしい、オブジェクトをきれいさっぱり消去する命令を使います。
llDie()で消えたオブジェクト(中のスクリプトも)を復活する方法はありませんので(ゴミ箱にもない)、テストする前には必ずコピーをとっといてください…経験者は語る^^;
default {
 // (省略)
 listen(integer channel, string name, key id, string button) { // 押されたボタンを聞く
  // (省略)
  else if ( 0 <= llListFindList( Rooms, [button] )) {
   // 部屋名のボタンで部屋をRezしRoomChannelの数字を渡す
   llRezAtRoot( button, llGetPos() + Offset,
     ZERO_VECTOR, ZERO_ROTATION, RoomChannel );
  }
  else if ( button == "Clear" ) {
   // 「Clear」ボタンでRoomChannelで「Clear」と言う
   llRegionSay( RoomChannel, "Clear" );
   llListenRemove(Handle);
   llSleep(0.7);
   jumpPos(HomePos); // もとの場所に戻る
   llSleep(0.7);
   unsitAll(); // 座っている人を立たせる
   llDie(); // 自分を消去(デモでは消えずに残る)
  }
 }
}
部屋側には「Clear」を聞いて自分を消去するスクリプトを入れておきます。
default {
 on_rez(integer start_param) {
  if (start_param) llListen(start_param,"","","Clear");
   // Rezで渡された数字のチャンネルで「Clear」を聞く
 }
 listen(integer channel, string name, key id, string msg) {
  llDie(); // 聞こえたら自分を消去
 }
}

2012/06/09

サイズ変更のデモも


デモ飛行船は、サイズ変更のデモもできます。
乗物の飛行船は、もともと最初に作ったアバター用の小さな飛行船を拡大したものなのです。
タッチでメニューが出ますので、大きさをいろいろ変えてみてください。

よく服のパーツなんかについてるサイズ変更のスクリプトと同じなのですが、あれでいつも不満に思ってたのを解消しています。
というのは、「+10%」「-5%」などのボタンを何度も押していると、だんだん数字がずれてくることがあります。
たとえば、「+10%」は比率110%、「-5%」は比率95%で、次々ボタンを押すと、100%×110%×95%=104.5%となって、105%ぴったりにはなりません。

このスクリプトでは、ぴったりの数字になるよう、比率は比率で100%+10%-5%=105% のように別に計算してから、もとの大きさを基準に拡大縮小します。

サイズの記録と再設定(拡大縮小)の部分は、こんな感じです…
getParams() { // プリムのもとの位置と大きさを記録する
 Scale = llGetScale(); // 親プリムの大きさ
 Children = []; // 子プリムの位置と大きさを記録するリスト
 PrimNum = countPrims(); // リンクしているプリム数
 integer link = 2; // 最初の子プリムのリンク番号
 for ( ; link <= PrimNum; ++link) // 子プリムの数だけ記録
  Children += llGetLinkPrimitiveParams(link,[PRIM_POS_LOCAL,PRIM_SIZE]);
}
setParams( float ratio ) { // プリムの位置と大きさを設定(拡大縮小)する、ratio:比率
 llSetScale( ratio * Scale ); // 親プリムの大きさ、もとのサイズに比率をかける
 integer link = 2;
 for ( ; link <= PrimNum; ++link)
  llSetLinkPrimitiveParamsFast(link,
    [PRIM_POS_LOCAL, ratio * llList2Vector(Children,(link-2)*2),
    PRIM_SIZE, ratio * llList2Vector(Children,(link-2)*2+1)]);
}
デモを試せる築地のお店はこちら
http://slurl.com/secondlife/TSUKIJI/90/47/22/


2012/06/08

引越してきました

こんにちはlovemaxです。
そらまめブログから引越してきました。
仮想世界のセカンドライフにいたりいなかったりします。
セカンドライフで動くプログラムLSL(Linden Script Language)をあれこれいじって遊んでます。

6月7日以前の日付の記事は、旧ブログの記事とほとんど同じです。
ちょっとだけ違うのは、利用条件が違うので。
興味ある方は、旧ブログもご覧ください。
http://lovemax.slmame.com/

2012/06/07

飛行船でデモ飛行


お店に展示してある飛行船は「デモ飛行」ができます。
店が狭いので、半分に切ってありますが、性能にかわりはありません。
動かすには、船のどこかに座ってから、船体にタッチします。
操縦には、キーボードの矢印キー(前後左右)と PageUp・PageDownキー(上下)を使います。
止まるには、もういちどタッチするか、立ち上ってください。
あと、デモ飛行船は、もとの場所にもどさなくても大丈夫です。
乗客が降りると、勝手に消えるし、元の場所には新しい展示用の飛行船が出るようになってます。

スクリプトでは、飛行船オブジェクトを「乗り物」に設定し、それっぽい動きをするいろいろな設定をします。
細かいところは全部すっとばして、操縦のとこだけ一部を書くと…

矢印キーはふだん歩いたり飛行したりに使ってるので、これを飛行船操縦用に切り変えます。
default {
 touch_start(integer total_number) { // タッチで矢印キーのコントロールを取る許可を依頼
  llRequestPermissions(llDetectedKey(0), PERMISSION_TAKE_CONTROLS);
 }
 run_time_permissions(integer perm) {
  if ( perm ) { // 許可を得てそれぞれ矢印キーのコントロールを取る
   llTakeControls(CONTROL_FWD | CONTROL_RIGHT | // 「↑」「→」(以下省略)
  }
 }
 control(key id, integer level, integer edge) { // 矢印キーを押したり離したりした時
  if(level & ~edge & CONTROL_FWD) { // 「↑」キーを押してるとき
   if( LinearMotor.x < 50 )    LinearMotor.x += 10; // 前進
   LinearMotor.z = 0;
  }
  if(level & ~edge & CONTROL_RIGHT) { // 「→」キーを押してるとき
   if ( AngularMotor.x < 2.5 ) AngularMotor.x += 0.5; // 右へ傾ける
   if ( -5 < AngularMotor.z ) AngularMotor.z -= 1; // 右回り回転
  }
  // (ほかは省略)
  fly( LinearMotor, AngularMotor);
 }
}
fly( vector linear_motor, vector angular_motor) { // 飛行船を動かす
 llSetVehicleVectorParam( VEHICLE_LINEAR_MOTOR_DIRECTION, linear_motor );
 llSetVehicleVectorParam( VEHICLE_ANGULAR_MOTOR_DIRECTION, angular_motor );
}
…こんな感じです。

参考:乗り物制作のチュートリアル
http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial/ja

築地のお店で乗り心地を試してみてください。
http://slurl.com/secondlife/TSUKIJI/90/47/22/

2012/06/06

ノートもらえます


お店で売ってる商品で右のような表示のある箱からは、ノートももらえます。
右クリックででるメニューの「Get Note」を選ぶとノートカードが来ます。
説明や使い方が書いてありますので、参考にしてください。

このスクリプトは商品と一緒に入っていて、お店でお買いあげいただいたお客様には、おまけとして差し上げてます。内容は、
string Note = ""; // ノートカードの名前

default {
 state_entry() {
  Note = llGetInventoryName(
    INVENTORY_NOTECARD, 0);
    // まずノートの名前を調べる
  if (Note) llSetTouchText("Get Note");
    // ノートがあれば右クリックメニューの「タッチ」を「Get Note」に変える
  else llSetTouchText(""); // なければもとに戻す
 }
 touch_start(integer total_number) {
  if (Note) llGiveInventory(llDetectedKey(0), Note); // 誰かがタッチしたらノートを渡す
 }
 changed(integer change) {
  if(change & CHANGED_INVENTORY) llResetScript(); // 中身が変わったら最初から
 }
}

築地のお店はこちら(SLurl)
http://slurl.com/secondlife/TSUKIJI/90/47/22/

2012/06/05

テレポート


上空にはアダルトショップもあって、地上のお店の端っこにあるテレポーター(デモ商品)を使って行けます。
タッチするとメニューが出て行先を選べ、うにうにと出現する怪しげな物体に座ると、それが目的地まで運んでくれるしかけです。

目的地まで運ぶしくみは、スクリプトの中で、プリムのパラメーター設定をする llSetPrimitiveParams() を使っています。
人が座っているオブジェクトを移動させるためで、位置設定の llSetPos(<x,y,z>) と同じことをするため、llSetPrimitiveParams([PRIM_POSITION, <x,y,z>])というふうに書きます。
なぜこちらを使うかというと、llSetPos() で動ける距離が10mしかなく、遠くに行くためには何度も繰り返さないといけないのですが、繰り返すたびに0.2秒休憩してしまうので、時間もかかり、テレポという感じじゃなくなります。
このことは llSetPrimitiveParams() でも同じなのですが、裏技があって、[PRIM_POSITION, <x,y,z>, PRIM_POSITION, <x,y,z>,...]というふうに同じことを繰り返して書いておけば、(10mづつ)何度動いても休憩は1回だけ、なので一瞬で行ったようになります。
そこで、行先までの距離を10mで割って、何回繰り返すか調べ、その回数分の長~いリスト[PRIM_POSITION, <x,y,z>, PRIM_POSITION, <x,y,z>,...]を作って、それで llSetPrimitiveParams() を呼び出すわけです。

スクリプトで書くと、こうなります。
jumpPos(vector pos) { // posは目的地の<x,y,z>
 list rules = [];
 integer n = (integer)(llVecDist(pos, llGetPos()) / 10.0) + 1;
 for ( ; 0<n; --n ) rules += [ PRIM_POSITION, pos ];
 llSetPrimitiveParams(rules);
}
llSetPrimitiveParams()の詳しい説明はこちら
http://wiki.secondlife.com/wiki/LlSetPrimitiveParams/ja
築地のお店はこちら(SLurl)
http://slurl.com/secondlife/TSUKIJI/90/47/22/

2012/06/04

築地のお店


「築地場外市場」にあるお店です。
通販ショップだけでなく、SLの中にも店をもってしまったわけですね。
ここでは、デモとかができるようにしています。
買う気がなくても、飛行船に乗って遊んだりできますよ。

場所はこちら
http://slurl.com/secondlife/TSUKIJI/90/47/22/

写真の、作業しているフリをしているのは人型の私です。どうぞ気になさらずに^^

2012/06/03

こんにちはlovemaxです


こんにちは。
もともとSLマーケットプレイスに通販ショップを開くためだけにアカウントをとり、人格は無しでいくつもりだったのに、人の姿がないと何かと不便で、人型でうろうろしているうちに、なりゆきでブログまで作ってしまった lovemax です。
なので、ほんとの姿はこのままでいいんです。

もし人型でうろうろしてる lovemax がいても、そっちは世をしのぐ仮の姿です。あくまでも。たぶん…。

その通販ショップというのはこちらです。
https://marketplace.secondlife.com/stores/97156
アダルトも見えるようにしてると、いきなりびっくりな絵がでてくるかもしれませんので、ご注意を!…まあ、そういうのがあるので、ちょっともとのアカウントは隠しときたかったってのが、正直なとこですね^^

2012/06/02

もの作りとスクリプト


SLの楽しみのひとつに、もの作りってあると思うんですけど、その中でも「スクリプト」がけっこう面白くて、そういうのをいろいろ書いてみようと思ってます。

写真の場所は、もの作りの方法をわかりやすく展示している「アイボリータワー」という建物の隣のサンドボックスです。
Ivory Tower Library of Primitives Sandbox
http://slurl.com/secondlife/Natoma/166/118/26/

そして、スクリプトを書くときにとても便利なのが、こちらのサイトです。
LSL ポータル - Second Life Wiki
http://wiki.secondlife.com/wiki/LSL_Portal/ja
日本語の説明や、サンプルもすごく充実していて、重宝しています。
サンプルをコピペするだけでも、実際に役に立つスクリプトができたりします。