2015/07/15

どちらにも開くドア

タッチするか、ぶつかると、「反対側に」開くドアです。
SLでドアが開くとき、うっかり近すぎていると、手前に開いたドアが自分のカラダを通過したりしますね。
べつに実害はないのですが、なんとなく気持ちよくなかったりもします(^^;;

そこで、必ず「向こうに」開くドアです。
タッチした、またはぶつかった人の位置が、ドアの外側ならドアは内開き、人が内ならドアは外開きに開くようにします。

人がどちら側にいるかを調べるのには「ベクトルの内積」というのを使います。
数学の難しい話は抜きにして、2つのベクトルの内積を計算すると、ベクトルが同じ向きのときにプラスの値になり、反対向きのときマイナスになります。(直角のときはゼロ)
なので、あらかじめドアの「外向き」ベクトルを決めておけば、ドアから見た人の方向ベクトルとの内積が、プラスなら「外にいる」→「内開き」、マイナスなら「内にいる」→「外開き」のようにできます。

スクリプトはこんな感じ:
swing(vector pos) {
  if (pos) { // 開く
    Rot = llGetLocalRot(); // 現在の回転(子プリムなら親に対する)を記録
    if (0 < (Face*llGetRot())*(pos-llGetPos())) // 方向ベクトルの内積
      llSetLocalRot(llEuler2Rot(Angle*DEG_TO_RAD)*Rot); // (+)なら内開き
    else llSetLocalRot(llEuler2Rot(-Angle*DEG_TO_RAD)*Rot); // (-)なら外開き
  }
  else llSetLocalRot(Rot); // 閉まる
}

default {
  touch_start(integer n) { // タッチで開く
    swing(llDetectedPos(0));
    state open;
  }
  collision_start(integer n) { // ぶつかって開く
    swing(llDetectedPos(0));
    state open;
  }
}
state open { // 開いた状態
  state_entry() { // 時間設定
    llSetTimerEvent(TimeOut);
  }
  timer() { // 時間で閉まる
    swing(ZERO_VECTOR);
    llResetScript();
  }
  touch_start(integer n) { // タッチで閉まる
    swing(ZERO_VECTOR);
    llResetScript();
  }
}
このドアは、「MySwingDoor」という名前で売ってます:
上のスクリプトでは省略しましたが、両扉のときもう片方が連動するしかけにもなってます。
SLマーケットプレイス
https://marketplace.secondlife.com/p/lovemax-MySwingDoor/7433954
築地場外市場(SLurl)
http://slurl.com/secondlife/TSUKIJI/80/55/22/