2022/12/11

メリークリスマス!

シーズンものということで クリスマスツリーを作ってみました。

クリスマスツリーの特徴といえば 何といってもあの円錐形と飾り付けですね。
リアルなら植木鉢が必要なところですが SL なら鉢も木の幹も省略できて 1プリムの円筒にテーパーをつければ空中で回転もできます。

回転してるように見せるには テクスチャーのアニメーションを設定します:

default {
  state_entry() {
    llSetTextureAnim(ANIM_ON|SMOOTH|LOOP,
        ALL_SIDES,1,1,1,1,0.1);
  }
}

不思議なのはこういうふうにすると 平面のはずのテクスチャーが 何か奥行きのある飾りのように立体的に見えてくることです。
おそらくテーパーをつけた円筒の表面を分割する具合で アニメーションの動きに微妙なずれができて それが錯覚になるのでしょう…

このクリスマスツリーはベネチアのお店で飾りを兼ねて お客さんに無料でプレゼントしています。
メリークリスマス!

2022/11/04

寄付を匿名で

更新した友だちからの要望に、チップジャーに入金した人の名前を表示しない設定もあります。

世の中には「寄付は必ず匿名で」という方もいらっしゃるようです。
ただ、友だちがいうにはそんな奥ゆかしい話ではなくて、アダルトなお店のときチップの額とか名前が出るのは欲が見えてしまうようで照れくさいとか決まりが悪いのだそうです。

通常(デフォルト)では写真のように、ジャーにログインしてるスタッフの名前, 合計入金額入金者金額を表示します。

これを匿名の寄付にするにはジャーの中にあるスクリプトの設定を書きかえます。
スクリプト pay user の18行目

integer ShowDonor = TRUE;

と書いてある TRUE(はい)を FALSE(いいえ)にします。

同じように、寄付があったときのジャーのリアクション・エフェクトを控えめにしたり無しにしたりもできます。
設定するにはチップジャーの Gold Coins/金貨 プリムの中にある action スクリプトを書きかえます。(6〜8行目)

integer Effect = TRUE; // パーティクル効果 TRUE: あり, FALSE: なし
vector Colour = <1,0.7,1>; // パーティクルの色 <(Red),(Green),(Blue)>
float Volume = 1.0; // 0-1 効果音のボリューム

なお、写真にあるジャーの表示の1番下 So Far: の金額はそのジャーに今まで入金された累積額を表しています。
これも友だちの要望から追加した機能で、この金額はスクリプト内の変数ではなく、プリムの 説明 に記録しています。
説明に1以上の数字を書き込んでおくと、入金があるたびに金額が加算されジャーの上に表示されます。
説明が空または数字以外のときには So Far: は出ません。
なので1番最初の金額はジャーを編集して書いておく必要があります。記憶を頼りに、または希望かそれとも見栄で(^^)~~

2022/10/30

MyTipjar アップデート

ひさびさの製品アップデートです。
友達のお店で試しに使ってもらってた機能がうまくいってるみたいなので製品に反映しました。
変更点はジャーへのスタッフのログイン・ログアウトを基本自動にしたこと。

製品記事: チップジャーからボードに連絡

タッチでログインできるのは同じですが、タッチし忘れても、場所を移動しても、1番近いジャーに自動でログインします。いなくなればもちろんログアウトも自動。
タッチ忘れを気にしなくていいので楽なのと、お客さんが来られてからログインすると、なにかチップをおねだりしてるように見られないか、とか気にせずにすみます。

自動ログインの仕掛けは、タッチがあったとき、お客さんから入金があったとき、一定時間ごとに、センサーを起動してまわりのスタッフとジャーの位置を調べてジャーの近くのスタッフをログインリストに入れ直します。

センサー部分のスクリプトはこちら:

  sensor(integer n)
  { // 自動ログイン: まわりを調べてユーザーを更新; n:人数
    InKeys = []; // ログインユーザーIDリスト(チップをもらう)
    InNames = []; // 名前
    // 1) まわりのユーザーを検出(入金者を除いて)
    list userids = []; // ユーザーIDリスト(仮)
    list userposs = []; // 位置
    key id;
    integer i;
    for(i=0; i<n; ++i) { // まわりの人を順に調べる
      id = llDetectedKey(i);
      if (isUserNotDonor(id)) { // 入金者でないユーザーなら
        userids += [id]; // ユーザーIDリスト(仮)に加える
        userposs += [llDetectedPos(i)]; // 位置
      }
    }
    // 2) まわりの他のジャーを調べてログインユーザーを更新
    // 他のジャーがなければ全ユーザー
    vector pos;
    float d0;
    integer m = llGetListLength(JarPoss); // 他のジャー
    integer j;
    float d;
    n = llGetListLength(userids);
    for (i=0; i<n; ++i) { // まわりのユーザー(チップをもらえる)
      if (JarPoss) { // まわりに他のジャーがあるとき
        pos = llList2Vector(userposs,i); // ユーザーの位置
        d0 = llVecDist(pos,Pos); // このジャーとユーザーの距離
        for (j=0; j<m; ++j) { // まわりの他のジャーを調べる
          d = llVecDist(pos,llList2Vector(JarPoss,j));
            // まわりのジャーとユーザーの距離
          if (d<d0) jump next; // 他のジャーが近い人は除外
        }          
      }
      id = llList2Key(userids,i);
      InKeys += [id]; // ログインユーザーIDリストに加える
      InNames += [agentName(id)]; // 名前          
      @next;
    }
    if (0<Amount) shareAmount(); // 3) 入金があったときは分配
    setText(); // 4) 更新結果を表示
  }

SLマーケットプレイス
https://marketplace.secondlife.com/p/lovemax-MyTipjar/8322026
前のバージョンをお買い上げいただいてるお客様でアップデートご希望の方は lovemax までご連絡ください。無償で最新バージョンの製品をお届けします。

2022/08/30

はじめての Twitter

Twitter アカウントとりました。
誰かをフォローすると今まで見たこともなかった写真がいっぱい出てくるのが新鮮です。
でも自分から何かツイートするのはたぶんまだ…。

https://twitter.com/lovemaxinfo

2022/07/17

箱の使い方まとめ

ベネチア SIM のイベントで広告看板をさげた飛行船 Airship Go Round Signboard を飛ばすコントロールボックス/箱の使い方をまとめました。

  • イベント会場の近くに箱を置く
  • 箱に広告画像を貼る

基本これだけで OK!
…詳しく書いたページです:
Airship Go Round Signboard Box: How to Use

2022/07/16

メニューに表示/調整

看板飛行船を自動で出す箱ですが 時間などコントロール情報はオブジェクトの説明のところに書いてあって変更するときはこの説明を書き直します。

ただ編集モードに慣れてないとどこを変えればいいのか迷ったりもするので もっと簡単にタッチでメニューを出してボタンで調整できるようにしました。

  • 開始や終了時刻を前後にずらす
  • 位置(X/Y/Z)の調整
  • 飛行船のスピードを速く/遅く
  • 手動で開始または終了

実際に変更しなくても または変更する前に 現在の状態をメニューのメッセージ部分で確認することもできます。

メニューのメッセージに現在の状態を表示するスクリプト:

list GoroundMsg = [ // もとのメッセージ
"Going Round: %%", // "%%"部分を数値で置き換える
"Position: %%, Speed: %%",
"Adjust End Time, Position, or Speed:"
];
string setMenuMsg(list msgs,list replaces) {
  string msg = "\n"+llDumpList2String(msgs,"\n"); // 改行でつなぐ
  list context = llParseString2List(msg,["%%"],[]); // 置き換わる"%%"で分解
  return mergeList2String(context,replaces); // 置き換えるリストと混ぜる
}
list getDesc2List() {
  string desc = llGetObjectDesc(); // オブジェクトの説明
  return llParseString2List(desc,[" "],[]); // 説明を空白で分解
}
string mergeList2String(list context,list replaces) { // 2つのリストを混ぜる
  integer n = llGetListLength(context);
  integer i = 0;
  string merged = "";
  for (; i<n; ++i) merged += llList2String(context,i)+llList2String(replaces,i);
  return merged; // 混ぜた文字列
}

メッセージ文の流れは決めておいて箇所箇所を数値データと置き換えます。
でその置き換わる数値データは箱オブジェクトの説明からとるわけです。

ページ: Airship Go Round Signboard Box: How to Use

2022/06/16

看板の縦横調節

イベントの看板はたいてい正方形の画面です。
でも正方形でなくてももちろんOKで 今度のイベント(16日木曜日)では縦が長い看板です。

そこでどんな縦横比の看板でも対応できるようにしました。

看板飛行船の準備は箱を編集して画像を貼ることで(Edit > Texture > Texture)できますが もし看板画面が正方形でない場合には箱の横幅も変えます。(Edit > Object > Size:X)

こうすると飛行船が飛ぶときにさげる看板の縦横比を箱と同じにします。

画面縦横の比率だけが問題なので横幅(X)さえ変えれば箱の高さ(Z)は変えなくてOK!
(…高さを変えると箱の一部が地面に埋まったり逆に浮いたりするので あれ?調整が必要?と悩むはめに…(^^;)…実際にはもちろんこの心配も不要!)

看板の縦横比を調節するスクリプト:

listen(integer ch,string na,key id,string msg)
{
  list info = llParseString2List(msg,[":"],[]);
  string command = llList2String(info,0);
  string data = llList2String(info,1);
  if (command=="XzRatio") { // 縦横比
    float xzratio = (float)data;
    vector size = getSignParams(PRIM_SIZE); // 看板のサイズ
    vector pos = getSignParams(PRIM_POS_LOCAL); // ローカル位置
    pos.z += size.z*0.5; // 看板の上端
    size.x = llSqrt(size.x*size.z*xzratio); // 画面の横幅, 面積は同じ
    size.z = size.x/xzratio; // 画面の高さ
    pos.z -= size.z*0.5; // 看板の中心
    llSetLinkPrimitiveParams(LinkSign,[PRIM_POS_LOCAL,pos,PRIM_SIZE,size]);
  }
}

箱も看板も Xが横で Zが縦です。
スクリプトはイベントが始まる飛行船を出すタイミングで箱の縦横比を調べて Rez した飛行船に伝えます。
飛行船の側ではもとからつけてる看板と面積は同じになるように縦横の長さを変えます。

さげる位置も看板のてっぺんが同じになるように Z 方向の位置を調節しています。

ページ: Airship Go Round Signboard Box: How to Use

2022/06/09

自動で飛ばす飛行船

ベネチアSIM のイベントのとき いつも宣伝看板をさげた飛行船を飛ばしていますが 何度かその時間に来れないことがあったので 事前に用意しておけばその時間に自動で飛ばせるようにしました。
やりかたは:

  1. 専用の箱をイベント会場の近くに置いて
  2. 箱に宣伝用画像を貼れば(Edit > Texture > Texture)準備完了!
    (…準備ができると写真のようにミニ飛行船が出ます)
  3. イベント開始時刻になれば飛行船が自動で飛び始め
  4. 終了時刻で飛行船も箱も消えます

開始と終了時刻はほとんど 22:00-24:00(JST) なのであらかじめ箱の説明のところに書いてあります。
もしも違う時間に開催されるならこれを書き直す(Edit > General > Description)だけでOK!

準備は超簡単なので誰でもできそうです。
イベントスタッフの人に渡しておけば当日 lovemax がいなくても飛行船が飛ばせるのでこれはサボれる!

飛行船を出したり消したりするきっかけを決めるスクリプトはこちら:

integer isNowArrive(integer time)
{ // TRUE: 指定時刻 time <= now < time+Margin に今到達した?
  integer now = getNowMin();
  if (time <= now && now < time+Margin) return TRUE;
  else return FALSE;
}
integer getNowMin()
{ // time: "2022-06-09T00:01:43..." UTC → return 541 JST(+9:00)
  string time = llGetTimestamp(); // UTC 協定世界時
  list info = llParseString2List(time,["T"],[]); // 日付と時刻を分ける
  time = llList2String(info,1); // UTC
  integer now = time2Min(time) + OffsetMin; // 分 JST 日本標準時
  if (28*60 <= now) return now - 24*60; // 28時以降は早朝 4時〜
  else return now;
}
integer time2Min(string time)
{ // time: "01:15:58" → return 75 分; 秒は無視
  list info = llParseString2List(time,[":"],[]);
  integer hour = (integer)llList2String(info,0);
  integer min = (integer)llList2String(info,1);
  if (hour<0) min *= -1; // 時間がマイナスのときは分もマイナス
  return 60 * hour + min;
}

時刻は全部分に換算して比較してます。
現在時刻は llGetTimestamp() で UTC (wikipedia 協定世界時) を調べて x 60 + に JST (wikipedia 日本標準時) オフセットの +9 x 60 を足します。
指定する時刻が真夜中以降の場合は 例えば正規の書き方 "00:30" ではなく "24:30" のように前日から続く深夜の書き方で前後を比べやすくしてます。
(…でも 28時以降はさすがに次の日の早朝 4時〜扱いに…)

ページ: Airship Go Round Signboard Box: How to Use

2022/04/17

超簡単パーティクル

SLでいろいろ楽しいパーティクルの視覚効果ですがスクリプトで書こうとするとなんだかとても大変そうな感じです。
設定する項目や数字がいろいろあってしかもそれぞれ意味がよくわかりません。

そこでこれ以上簡単にはできない?という究極の超簡単なパーティクルというのを考えてみました。
イベントのとき会場上空を回る看板つき飛行船に仕込んだ ぽこぽこ白いのが飛び出してふわ〜っと漂うパーティクルです。

スクリプトはこちら:

default {
  state_entry() {
    // 最初はパーティクルを出さない
    llParticleSystem([]);
    // ここで超簡単なパーティクルの設定
    Particle = [
      PSYS_PART_FLAGS, PSYS_PART_WIND_MASK // 風に漂う
      | PSYS_PART_EMISSIVE_MASK, // 自分で光る(周りの光の影響を受けない)
      PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_ANGLE_CONE, // 発生方向の角度を設定
      PSYS_SRC_ANGLE_BEGIN, 0.3*PI // 角度: 0.3x180=54°
    ];
  }
  link_message(integer n,integer i,string msg,key id) {
    // リンクメッセージで開始または終了
    if ((float)msg) llSetTimerEvent(1);
    else llResetScript();
  }
  timer() { // ランダムな時間間隔でパーティクルを出したり止めたり
    llSetTimerEvent(MinTime+llFrand(MaxTime-MinTime));
    Emit = !Emit;
    if (Emit) llParticleSystem(Particle);
    else llParticleSystem([]);
  }
}

ほんの数行の簡単設定でもとりあえずパーティクルが出るのはデフォルト設定があるからですね。

超簡単では物足りない人向けには LSLポータルのページに詳しい説明がどっさり書いてあります。ただしデフォルトについては書いてないみたいです。(llParticleSystem)

ビューワーの Firestorm のメニューに Build > Object > Edit Particles というのがあって オブジェクト編集中ならそこから発生するパーティクルを編集できる画面が開きます。(つい最近友達に教えてもらいました。知らなかった〜)
この画面に最初から出ている項目や数値がデフォルトなのでしょう。
編集画面の [Copy] ボタンを押せば設定された項目とか数値がクリップボードにコピーされます。
[Inject] ボタンはその編集中のオブジェクトの中に New Particle Script というスクリプトが注入されます。

あと SLインワールドに The Particle Laboratory という場所があって そこではいろいろな展示物やサンプルスクリプトなどでパーティクルのことを詳しく教えてもらえます。
SLurl: https://maps.secondlife.com/secondlife/Teal/196/47/302

2022/03/12

イージングアニメーション

SL 内でオブジェクトを動かしたり形を変えるようなときイージングというアニメーションの定番的な方法を使うともっともらしいです。
物を動かすとき最初はゆっくりしか動かず はずみがつくと速くなって 止まるときはまたゆっくり というような感じです。
(参照: Prototype easing curves)

SL スクリプトにはそういう仕組みが用意されてないようなので作ってみました。

作り方はベジエ曲線という数学的な曲線(wikipedia Bézier curve)の描き方があって その曲線が時間経過と位置や大きさの関係を表します。
よく使われるのは3次ベジエ曲線/Cubic Bezier Curve で 4つの点 P0,P1,P2,P3 のうち P0=(0,0), P3=(1,1) は固定であとの P1と P2 の設定で 0 から 1 までの時間と変化の関係を決めます。
計算式は B = (1-t)3P0+3(1-t)2tP1+3(1-t)t2P2+t3P3
スクリプトで書けば

vector cubicBezier(float t) {
  float t1 = 1.0 - t;
  return t1*t1*t1*P0 + 3.0*t1*t1*t*P1 + 3.0*t1*t*t*P2 + t*t*t*P3;
}

ところで曲線を描くのに時間要素 t を変化させますが これは結果の曲線(x,y)の x: アニメーションの経過時間とは微妙に違います。
そこで描いた曲線 (x,y) からアニメーションの経過時間 t に等しい x に対応する変化量 y の値を 計算するには 曲線上の前後の点から補間します。

float easing(integer i) {
  if (i<=0) return 0.0; // 最初
  else if (N<=i) return 1.0; // 最後
  float t = (float)i/(float)N; // 経過時間→曲線を描くときにも使う
  vector b = cubicBezier(t); // 描いた曲線上の点
  if (t<=b.x) --i; // 1つ前
  else ++i; // 1つ後ろ
  float t0 = (float)i/(float)N;
  vector b0 = cubicBezier(t0); // 曲線上の隣の点
  float r = (b.x-t)/(b.x-b0.x); // 時間の差と隣までの差の比率
  vector br = b - r*(b-b0); // 補間した経過時間の曲線上の点
  return br.y;
}

補間計算のための数値は前後1つ隣しか見てませんが 同じ数で時間を刻めば描いた曲線の点も経過時間に近くて 変化が激しくなければ誤差もきっと小さいでしょう。

このアニメーションは lovemax ベネチア店の最上階 お城のデモを見に行く箱に仕込みました。
ほかにももう一つ わざとわかりにくくした場所にも仕掛けてますが 怪しいところを探せばきっと…。

2022/03/06

螺旋階段は時計回り?

 

西洋のお城の塔にある螺旋階段は登るとき時計回りが基本だそうです。
それは戦争のとき 攻め登る兵士は右手に持った剣を振るのに柱がじゃまになるけど 上から守る側の兵士は右手が自由に使えるので有利だから …。

その話をディスカバリーチャンネルか何かで見て 売ってるお城(参照: お城と岩のセット販売)を確認したら何も考えずに作ってたのでやっぱり逆回りでした。(><)

作ったときは半分に削ったトーラス(ドーナツ状のプリム)を引き伸ばして螺旋階段に見立ててましたが最近の何でもメッシュの世の中に迎合してついに階段だけメッシュ部品と入れ替えました。

すると部品は 1プリムでランドインパクトが 2 なのに大きさを変えるとランドインパクトが 3 になったりほかのプリムとリンクすると全体のランドインパクトがもっと増えるとか不思議なことが起こります。
もとのお城はプリムだけでできていて19プリム=19ランドインパクトですが 階段をメッシュ部品に入れ替えたら同じプリム数でもランドインパクトが 34になるのです!
…メッシュは謎です…。

ところで螺旋階段は本当に時計回りが多いか画像検索してみたら…逆回りもたくさんあります??
しかもお城の攻防で逆の説も出てきました:
螺旋階段のステップは扇型で柱側が狭く壁側が広いので兵士は足場を確保するため壁側に寄る そのとき攻め登る側は反時計回りの階段のほうが右手が壁に近くて自由が利かずに不利…。
…うーんどっちが正しいのか どっちも単なる都市伝説なのか…。

ちなみに lovemax の製品 MyCastle では いちいち階段を登らなくても柱にタッチ→メニューで行き先を選んでジャンプ で行けるので どっち回りか気にしなくてOK!

MyCastle はベネチアのお店の最上階から箱に乗って上空でデモを見ることができます。
あと 上空に行くと作りかけのベネチアの街も見ることができてベネチア SIM がどうやって作られているか雰囲気がなんとなくわかります。



2022/02/23

びっくり?宝箱

lovemax ワゴンの3番目アイテム: びっくり?宝箱 はもとの宝箱(参照: 金貨ぎっしり宝箱)に びっくり?機能を追加してさらに価格を 3分の1(!)まで下げた超お得な商品です。ベネチアカーニバル特設ワゴンセール限定。
…といってももとの価格はそもそもネタでつけた値段だったので その 3分の1もまたネタ価格。

ネタの話が出たので追加ネタを2つ。
ネタバレになって面白みが減ってはいけないので お買い上げしていただいた またはワゴンで確認していただいたお客さんのためだけに書くと:


追加ネタ1: ゼッキーニ金貨

ベネチア共和国で1284年からナポレオンに支配される1797年まで500年以上同じデザインで発行されていた金貨です。

写真は最後から2番目のドージェ(総督)パオロレニエの治世(1779-89年)中に作られた50ゼッキーニ金貨: 直径76mm 重さ192.5g
図柄はドージェが聖マルコに跪いています。(wikipedia ゼッキーノ/Sequin)


追加ネタ2: エトナ火山

イタリア南部シチリア島にある活火山です。

ヨーロッパ最大の活火山で 2018年の標高は3,326mですが活発な活動で高さはしょっちゅう変わるそうです。
アルプスを除いたイタリアでは最も高い山で2番目のヴェスヴィオ山の3倍近くもあります。
50万年前から頻繁に噴火を繰り返して 最近でもついおととい 2022年2月21日噴火があったようです。(wikipedia エトナ火山)

2022/02/21

特設ワゴンセール

ベネチア SIM のサンマルコ広場にはたくさんのセールスワゴンが並んでいます。
lovemax のワゴンで売ってるのは3つ:
  1. 肩乗り飛行船 (無料)
  2. 画像切り替え絵画 (L$ 55)
  3. びっくり?宝箱 (L$ 340)
2. 画像切り替え絵画 はベネチアの景観をたくさん描いた18世紀の画家カナレット(wikipedia カナレット/Giovanni Antonio Canal/1697-1768)の4枚の絵と昔のベネチアの地図が一定時間で切り替わります。

切り替え時間の設定は中のスクリプトを編集します。秒数などで指定できるほか h:時間, d:日, w:週, m:月, s:季節, y:年のように文字も使えます。

切り替えを日付から調べるスクリプト:

integer getCycleDate()
{ // return 年:2022-, 季節:1-4, 月:1-12, 0:それ以外
  if (Cycle=="") return 0;
  integer i = llSubStringIndex("msy",Cycle);
  if (i<0) return 0;
  string date = llGetDate(); // 日付: YYYY-MM-DD
  list info = llParseString2List(date,["-"],[]); // 年,月,日に分解
  if (i==2) return (integer)llList2String(info,0); // 年
  else {
    integer month = (integer)llList2String(info,1);
    if (i==0) return month; // 1-12月
    if (month==12) month = 0; // 12月を0に, 1-11月はそのまま
    return 1 + month / 3; // 季節; 1:冬-4:秋
  }
}

月,季節,年は毎日チェックしてそれ以外は指定した秒数または時間:h→60x60秒, 日:d→24x60x60秒, 週:w→7x24x60x60秒で切り替えます:

timer() {
  integer date = getCycleDate();
  if (date) { // 月,季節,年
    if (Date==date) return; // 前と同じなら何もしない
    else Date = date; // 違ってたら更新
  }
  setPicture(); // 絵を切り替える
}

2022/02/12

ベネチア SIM カーニバル

ベネチアSIMでカーニバルが始まりました。
期間は2022年2月12日(土)〜3月1日(火)でリアルのベネチアカーニバルと同じです。

カーニバル期間中は会場のサンマルコ広場でダンスや音楽イベントが何回もあり 広場には特設セールスワゴンがずらっと並びます。(lovemax も出店しています)

初日オープニングにはダンスイベントが開催されました。
広告看板を下げた飛行船も出動しました。(最近ではイベント恒例になってきました)

カーニバルという言葉(日本語では謝肉祭)はラテン語 carnem (肉を) levare (除く)がもとだそうで 断食をする四旬節が始まる灰の水曜日の前夜(なので最終日は火曜)に開かれた肉に別れを告げる祝宴だということです。(wikipedia 謝肉祭)

リアルのベネチアでは1162年から始まって 有名な仮面は 階級制度の厳しい時代でもカーニバルの間は仮面をかぶって違う階級や違う性別の服を着て 匿名のベネチア市民として自由な行動を満喫するのが流行したからだそうです。(wikipedia ヴェネツィア・カーニバル)

2022/02/05

2プリムでリンクの蓋を開閉

今までマーケットプレイスだけで売ってた宝箱を ベネチアのお店にも置くことにしたので この機会に今まで放置してた 2プリム蓋問題 を解決することにしました。

問題というのは 2プリムでできている宝箱の蓋をいっぺんに開閉するのに 今までは箱と蓋を別々のオブジェクトに(参照: リンクなしでも親子関係)してたのを 一つのオブジェクトでもできるようにする問題です。

千両箱と3億円ケース の蓋は よくあるドアと同じで 1プリムの箱の中心をヒンジにして削れば角度を変えるだけなのでわりと楽です。
でも宝箱の蓋は変形して削った箱(中心をヒンジに→角度だけでOK)と半分の円筒(中心をヒンジにはできない→角度も位置も変更)の組み合わせなのでちょっとめんどう。
なだけでなく角度を変えたり移動するスクリプト: llSetRot(), llSetPos() は 0.2秒停止するという謎なことが起こって そのままだと部品がバラバラに動くことになります。

解決策はスクリプトでも llSetLinkPrimitiveParamsFast() を使うことでした。
Fast と書いてあるだけに止まったりはしないんです!

こんな感じ:

list PrimPosLooks = [ // プリム名, 閉じたローカルの位置,向き, 開いた位置,向き
  "top", <-0.2, 0, 0.15>,<0,0,0>, <-0.2, 0, 0.15>,<0,-60,0>,
  "cap", <0, 0, 0.15>,<90,0,0>, <-0.1, 0, 0.32321>,<90,0,60>
]; // 位置:<x,y,z> メートル, 向き:<x,y,z> 度で表した回転

integer setPosRot(integer open)
{ // open:FALSE/0 →閉じる, TRUE/1 →開く
  string name = llGetObjectName(); // プリムの名前
  integer i = llListFindList(PrimPosLooks,[name]); //
  if (i<0 || LinkNumber<2) return -1; // もし何か間違ってたら脱出
  i = i+1 + open*2; // データの場所を計算
  vector pos = llList2Vector(PrimPosLooks,i); // 位置
  vector look = llList2Vector(PrimPosLooks,i+1); // 向き
  rotation rot = llEuler2Rot(look*DEG_TO_RAD); // 回転
  llSetLinkPrimitiveParamsFast(LinkNumber, // リンク番号
    [PRIM_POS_LOCAL,pos, PRIM_ROT_LOCAL,rot]); // 位置と回転
  return open;
}

宝箱はベネチア店の階段を上がった最上階 鉄格子の中にあります(といっても誰でも開けられる鉄格子なので雰囲気だけ)。

2022/01/30

簡単テレポの設定も簡単に

何年か前に作った簡単テレポ/ジャンプ(参照:階段を昇らずにジャンプ)ですが タッチだけでジャンプ先を設定するには 体の向きなどちょっとしたコツがいります。
それに離れた場所を設定するにはタッチは向いてません。(300メートル先まで設定はできるのですが…)

そこでプリムの説明のところに行先データを書いておけば それを読んで設定できるというスクリプトを書きました。

スクリプトの中に直接データを書くのは もし間違えたとき何が起こるかわからないので ちょっとどきどきですが それよりはずっと気楽に書けます。
説明に書き込むにはプリムの編集権限も必要なので 知らない間に誰かが間違って変えてしまう心配もないでしょう。

読む部分のスクリプトはこちら:

list getDestination(string data)
{ // data: " head : <pos.x, pos.y, pos.z>, look"
  // return [(string)head,(vector)pos,(float)look]
  integer i = llSubStringIndex(data,":"); // ":" がデータを書いてある印
  if (i<0) return [];
  string head = ""; // ":" が先頭(i==0)のとき頭は空
  if (0<i) head = llGetSubString(data,0,i-1); // ":" より前(頭)はデータ以外の説明に
  head = llStringTrim(head,STRING_TRIM); // 前後の空白は取っておく
  string body = llDeleteSubString(data,0,i); // ":" の後ろがデータ
  list info = llParseString2List(body,["<",">",","," "],[]); // 数字の書き方は気楽に
  vector pos = ZERO_VECTOR; // 行先の位置情報
  pos.x = (float)llList2String(info,0); // X座標(東西 メートル)
  pos.y = (float)llList2String(info,1); // Y(南北)
  pos.z = (float)llList2String(info,2); // Z(高さ)
  if (llVecMag(pos)<0.1) return []; // ほとんどゼロ座標だったら行先データではないはず
  float look = (float)llList2String(info,3); // 向き(角度 0度:東, 90度:北)
  return [head,pos,look];
}

写真の遊覧飛行船ドックでは案内看板と乗船デッキへの斜路に同じ仕組みを使ってます。
実際はもう少し複雑ですがそれは省略…(^^)

2022/01/22

繰り返しで説明文を表示

ベネチアSIMにはやはりというかいろんな国の方が来られます。

案内看板の説明が日本語だけだとなにか不親切な感じがします。
国際語の英語はもちろん ここはベネチアなのでイタリア語もほしいところ。
でもいっぺんに表示するとごちゃごちゃしてすっきりしないし 読みたいのは 3ヶ国語全部じゃなくひとつでいいはず。

というわけで 説明文を分けてそれを繰り返しで表示するスクリプトを作りました。
表示が次々変わるので 見た人の気を引く効果もありそうです。

スクリプトはこちら:

// Cycle Text v1.2
list Msgs = [
  "Tocca/Siediti al Porto del Dirigibile Turistico.",
  "Touch/Sit to Airship Sightseeing Port.",
  "タッチ/座って遊覧飛行船の出発地へ"];
float TimeCycle = 7; // 秒ごとに切り替え
integer Stride = 1; // 1度に表示する行数
integer Index = 0;

default {
  state_entry() {
    llSetText("",<1,1,1>,1);
    llSetTimerEvent(TimeCycle);
  }
  timer() {
    list lines = llList2List(Msgs,Index,Index+Stride-1); // 表示する文
    string text = llDumpList2String(lines,"\n"); // 2行以上なら改行でつなぐ
    llSetText(text,<1,1,1>,1); // テキスト表示
    Index += Stride; // 次の表示
    if (llList2String(Msgs,Index)=="") Index = 0; // 終わりなら先頭に戻る
  }
}

表示を1度に何行かまとめて出せるようにもしてあります。
Stride=1 になってますがこれを 2 にすれば2行づつ 4にすれば4行づつというわけです。

2022/01/15

小さくすると頭がつかえる?

ベネチアSIMで遊覧飛行船の準備をしてるとき 売ってる飛行船がそのままでは大きすぎて建物内で圧迫感があるので少し小さくしました。(もともとリサイズ機能つきです)
なかなかかわいくなりましたが ここで問題発生 !
降りるときにどうかすると頭が風船部分につかえて船から出れなくなったりします(TT);;;
風船部分だけファントムにする方法を試しましたが(昔の記事参照: 通り抜けできるプリム)さらに大きな問題が…いきなりランドインパクトが何百もあがってこれだけで SIM に負担がかかりそうなんです !!! 

…そこでどうしたかというと 人が乗ったら飛行船全体をファントムにすることにしました。
ファントムでも人が乗るぶんには何も問題ありません。
降りるときは船体を素通りするので空中にいたら下に落ちますがまあいいことにしましょう。
あとは飛んでるとき建物にぶつかっても船体部分が素通りしてしまいますが 今までちょっとさわっただけで船がひっくり返って大騒ぎ ! だったのがわりと平気になったのでこれもよしとしましょう。(人はファントムにならないのでもちろん素通りしません)

スクリプトはこんな感じ:

default {
  state_entry() {
    llSetPrimitiveParams([PRIM_PHANTOM,FALSE]); // ファントムじゃない
  }
  changed(integer change) {
    if (change & CHANGED_LINK) { // 人の乗り降りでリンクが変わる
      if (llGetNumberOfPrims() != llGetObjectPrimCount(llGetKey())) // 誰か乗ってる
        llSetPrimitiveParams([PRIM_PHANTOM,TRUE]); // ファントムにする
      else llSetTimerEvent(Wait); // 誰も乗ってない しばらく待つ
    }
  }
  timer() {
    llResetScript(); // リセットしてファントムでなくす
  }
}

ここで llGetNumberOfPrims() は座ってるアバターを含めたリンク数 llGetObjectPrimCount() は含まないプリムだけの数 なので比較すれば誰か座ってるかどうかがわかるしかけです。

2022/01/08

遊覧飛行船のテクスチャー

遊覧飛行船のテクスチャーはベネチアSIMのスタッフさんたちが使っているのを使わせていただきました。
これと同じテクスチャーの製品はベネチアのインワールドの売り場の箱にだけ同梱しています。(「MyShip」と「MyShip Shoulder」)
ベネチアSIMに来ていただいたお客様だけの特典です! ^^/

SLurl はこちら:
https://maps.secondlife.com/secondlife/Yumix%20Prada/189/90/22
ベネチアSIMのランディングポイントはリアルト橋にあって お店へはそこから75mです。
遊覧飛行船の案内看板がすぐ近くにあるので そこからおいでください。

2022/01/01

ベネチアSIMにお店を開きました

2022年あけましておめでとうございます。
最近あんまり活動してませんでしたが このたびベネチアSIMにお店を開くことになりました。
SLurl はこちら:
https://maps.secondlife.com/secondlife/Yumix%20Prada/189/90/22
ベネチアSIMのランディングポイントはリアルト橋にあって お店へはそこから運河沿いを海に向かって75m先 写真右下に写ってる建物の中にあります。
例の赤いビームを頼りに散策しながら来られるか または遊覧飛行船の案内看板がすぐ近くにあるので そこから一気においでください。