OculusIntegrationを使ってレバーっぽい挙動を作成する

概要

この記事では、OculusIntegrationを使用して、スロットマシーンのレバーのような挙動を作成するにはどんな感じのアプローチでできるのかを簡易的に行うためのものです。

また、簡易的といっているのは、本来の挙動的に、レバーを引くなどの事を行う際には、手側がレバーの取っ手に対して、手を掴み、リアル側で、ある程度離れてしまうと放してしまうなどの挙動があればよりリアリティがましますが、その辺は今回は考慮しないものとします。

なので、今回の完成品としては以下のような挙動を作ります。

TODO:用意したVideoを持ってくる。

LaverDemo - YouTube

 対象

ひとまず動かしてみたいっていう人

開発環境

Unity2018.4.20f OculusIntegration 25.0

下準備

手順としては以下の通りです。 1. プレイヤーの挙動を持ってくる 2. レバー側の準備

1に関しては、DistanceGrabのScene内で行うのであれば不要な工程です。

  1. プレイヤーの挙動を持ってくる OculusIntegrationについているDistanceGrab.sceneの中にあるPlayerControllerというものが必須になるので、それを新しいSceneに持ってきてください。

これらは、「掴む側」に必要な挙動のスクリプトがついているもの 且 カメラなども全部あるので、VR空間に降り立つのにもこれがあれば降り立てる状態になります。

  1. レバー側の準備 レバーの構造としては以下のようになっています。

    Hieraruchy

    LaverRoot

    -Box ・・・1

    -LaverTrans・・・2

    --LaverRotation・・・3

    ---Stick・・・4

    ----Grip・・・5

    1はレバーが刺さっているオブジェクトです。 2はレバーの根本の位置にあるオブジェクトです。 3はレバーを動かした時に回転するためのオブジェクトです 4はレバーのスティックです。 5はレバーの握る部分です。

    それぞれの設定は以下の通り

    PositionとかRotationとか、Scaleの設定
    1 Box

    Position x:0.0 y:0.5 z:0.0

    Rotation x:0.0 y:0.0 z:0.0

    Scale x:1.0 y:2.0 z:1.0


    2 レバーの根本の位置

    Position x:0.0 y:0.5 z:0.5

    Rotation x:0.0 y:0.0 z:0.0

    Scale x:1.0 y:1.0 z:1.0


    3 レバーの回転

    Position x:0.0 y:0.0 z:0.0

    Rotation x:0.0 y:0.0 z:0.0

    Scale x:1.0 y:1.0 z:1.0


    4

    Position x:0.0 y:0.0 z:0.0

    Rotation x:0.0 y:0.0 z:0.0

    Scale x:0.2 y:0.2 z:1.0


    5

    Position x:0.0 y:0.0 z:0.63

    Rotation x:0.0 y:0.0 z:0.0

    Scale x:2.0 y:2.0 z:0.5

    またGripのオブジェクトに対してBoxColiderとRigidBodyとDistanceGrabbleをつけた状態にする必要があります。

ソースコードの修正

OculusIntegrationのサンプルでは、オブジェクトを掴んだ際に、その位置の更新を掴む側で行っており、掴まれる側に位置更新はありません。

そしてレバーなどの場合、その動き方は、レバーが持っている方がいいかなという風に個人的にはかんがえているため、そのような実装で行います。

まず、掴まれる側から修正を加えていきます。 DistaceGrabbleの継承元であるOVRGrabbableクラスに以下の設定項目と処理を追加します。

bool IsFixedDevice 動きが固定されているかの判断のためのもの GameObject RotationRoot 回転を行う所 前の章の3がそれに当たります。

ソースコードとしては以下のような感じです。

OVRGrabbable.cs

    [SerializeField]
    private bool IsFixedDevice = false;
  

    [SerializeField]
    private GameObject RotationRoot = null;

  /// <summary>
    /// 動きの部分はこっちで行うかどうか?
    /// </summary>
    public bool IsFiexed
    {
        get
        {
            return IsFixedDevice;
        }
    
    }

  public void MoveGrabObject(Vector3 grapperPos)
    {
        Vector3 dir = grapperPos - RotationRoot.transform.position;

        if(XRotationLock)
        {
            dir.x = 0f;
        }

        if (YRotationLock)
        {
            dir.y = 0f;
        }

        if(ZRotationLock)
        {
            dir.z = 0f;
        }

        Vector3 lookPos = RotationRoot.transform.position + dir;

        RotationRoot.transform.LookAt(lookPos);
    }

次に掴む側のDistanceGrabberのソースコードを修正していきます。 MoveGrabbedObjectという関数に対して

DistanceGrabber.cs

    protected override void MoveGrabbedObject(Vector3 pos, Quaternion rot, bool forceTeleport = false)
    {
        if (m_grabbedObj == null)
        {
            return;
        }

        Rigidbody grabbedRigidbody = m_grabbedObj.grabbedRigidbody;
        Vector3 grabbablePosition = pos + rot * m_grabbedObjectPosOff;
        Quaternion grabbableRotation = rot * m_grabbedObjectRotOff;

        if (m_movingObjectToHand)
        {

            float travel = m_objectPullVelocity * Time.deltaTime;
            Vector3 dir = grabbablePosition - m_grabbedObj.transform.position;
            if(travel * travel * 1.1f > dir.sqrMagnitude)
            {

                m_movingObjectToHand = false;
            }
            else
            {

                dir.Normalize();
                grabbablePosition = m_grabbedObj.transform.position + dir * travel;
                grabbableRotation = Quaternion.RotateTowards(m_grabbedObj.transform.rotation, grabbableRotation, m_objectPullMaxRotationRate * Time.deltaTime);
            }
        }

        //以下の2行を
        //grabbedRigidbody.MovePosition(grabbablePosition);
        //grabbedRigidbody.MoveRotation(grabbableRotation);
        //下の形式に変更する。

        if (m_grabbedObj.IsFiexed)
        {
            //掴む側に動作を任せるためのもの
            m_grabbedObj.MoveGrabObject(grabbablePosition);
        }
        else
        {
            //掴む側をこちらが操作する本来の処理
            grabbedRigidbody.MovePosition(grabbablePosition);
            grabbedRigidbody.MoveRotation(grabbableRotation);
        }
    }

にて、改造を終了です。

マーダーミステリー体験したので、それに対してのもの

概要

この文章は、2020年3月5日現在において、身内でのと野良のとの通算2回目の段階で書いたマーダーミステリーを行った状態での感想と考察です。 あくまでも個人の段階での感想です。

また、一応最後を覗いて、ネタバレを含まない内容に心掛けたつもりではありますが、かなり推理力高めの人などはそこから、推測出来る人がいるかもしれません。 「アガスティアレコード」及び「バード将軍」をやっていない場合は、念を入れるなら、見ないほうがいいかもしれません。

マーダーミステリーとは?

それぞれに与えられた役割(以後ロール)のキャラクターをそれなりに演じつつ、「目的」の達成を目指すゲームです。 「目的」は、シナリオによって違ったりするのですが、ドラえもんで例えるなら、隠しているどらやきを見つけて食べてしまったので、その食べた事実が自分だとばれない みたいな、本当は自分だけど、犯人が自分であると思われないようにする といったものから、逆に犯人を見つけ真相を究明するといったものもあります。

といったようなそれぞれのロール部分に対しての「目的」があり、それを達成するように動きます。

ゲームの流れ

ゲームの流れとしては 1. 演じるキャラクターを選択する 2. キャラクターの生い立ちや持っている情報の文章を読み込む 3. フェーズ1-3程度の情報の出し合い、探り合いなどをしつつのロール 4. 自身が犯人だと思う人の推理 5. 解説+感想戦

といった感じになります。 補足として  2の部分では、選んだキャラクターの情報 (どんな人なのか?事件当日に知っている情報や、思惑、目的など)があるので、それらを頑張って覚える。 また、この段階で、3のフェーズ毎に必ずしゃべる必要がある内容も書かれています。

 3の部分では、2で書かれている内容のそのフェーズで必ず話さなければいけない内容を話す+相手に対して質問する時間です。例えば、この時間は、私はこれを行っていたんだが、君の方は何を行っていたんだい?みたいな感じのやりとり。

4の部分に関しては単純な推理です。しかし、ほとんどの場合真相解明にたどり着けない人が多いので、私の場合それっぽい理由をつけて、この人が犯人だと思うみたいな内容です

5の部分は、事件の真相をGMから語られます。 GMによって、説明のよしあしや、納得具合によって大きく体験に関わる内容になります。

マーダーミステリーの面白いところ

これは、あくまでも個人の感想なのですがという枕詞を使うのですが、解説+感想戦といった部分が一番面白い部分かなと思っています。  もちろん、ロール+推理も面白い部分ではあるのですが、ここは得意不得意があり、また推理に関しては、かなり難しいので、たどり着く事が難しいので、そうなると解説+感想戦になるのかな?と思われます。

理由としては、解説によって、それまで疑問に思っている部分に対しての回答が返ってくるわけですが、それはもやもやとしたものが、すっきりする部分になります。リアル脱出ゲームとかを体験したことがある人ならわりかしわかる体験かな?と思います。 人自体がそもそも白黒をつけたい生き物なので、未完の状態も同様にあまり好きな人もいないでしょう。(もちろん例外もあり) なので、すっきりする部分という意味で、解説はすごく「良い体験」の部分であり、やりきった感も味わえる部分です。

もう一つの感想戦に関しては、結構シナリオによっては盛り上がる部分かなと思っていて、あの時に本当はこう動きたかったんだけど、これがあったから、動けなかったんだよ。みたいな事があり、より物語としての中身を拾えたり、深めたり、その振り返りの部分で、結構ここでその場で居合わせた人とかと仲良くなる箇所かなと思います。 たぶん、自分のロール的にこれできなかった。仲間だったと思ってたのに―と叫びたかったとかを言い出せば、そこからつながるので積極的に声にだしていきましょう。

ネタバレを含むので「バード将軍」「アガスティアレコード」をやってない人は見ないでください。

将来的な個人的考察

このトピックでは2回体験した感じの今後どういった所が、改善されるところか?などの個人的に感じた部分を記述します。 ここから先は、ネタバレなどを含む可能性が高くなります。(一応考慮はしたつもり)

アガスティアレコード」及び「バード将軍」をやっていない場合は、念を入れるなら、見ないでください。

といっても現状としては 身内のDiscord内での、1回と、VR上での1回の計2回を体験しただけなので、まだ初心者も初心者ではあるのだけど、現段階で感じた内容を記述します。

ストーリーについて

文章の各所で、シナリオによってはーという部分が散見されていると思うのですが、これは、本当に相性とかが本当にあって、私自身が、文章をよむのが苦手、短期的に覚えるの苦手という事もあり、「アガスティアレコード」に関しては、本当に合わない分類のシナリオの一つだったかなと思っています。 また、それぞれのキャラクターのロールによっては、極端に有利だったり、極端に不利だったりする場合があるのが嫌いという人とか「バード将軍」は向かなかったりするので、本当に相性。 ただ、個人的には、極端に不利、有利だと感想戦部分で、こう思ったからといった想起がしやすいので、感想戦の部分では活かされるかも?といった感じ。

VRでのマーダーミステリー

まだ「アガスティアレコード」しかVRで行ったストーリーはないのでなんとも言えないが、現状みている感じ、そこまでVRでやる必要があるか?といった感じでした。 理由としてはいくつかあって - 推理を行うための照らし合わせのために、自分の文章、他人の話した内容を色々と見る必要があるため、VRの「視覚」を活かせる機会が「世界観(風景、音楽)」「演者のロールした時の身振り手振り」しかないのだが、周りを見渡す余裕がなければ、これらがまったく活かせない場合が多いのかなと思ったため。 - 相手の会話のメモを取る必要があるため、HMDが邪魔になりやすい。この辺はあるあるちゃあるあるなのかもしれないが、VR空間でペンがあるところもあるとは言え、結構微妙なものかなと思われる。

商売としてのマーダーミステリー

現在、マーダーミステリーを「イマーシブクラウド」が行っているわけだが、すごい些細な事ではあるけど、気になったとか商売としての観点から、こうしたらいいのかな?みたいな事を記述したものです。 戯言と思ってみるのが良いでしょう。

GMと同じ団体所属のプレイヤーがいた場合のやり取りについて 現状の無料でやる分には、全然きになるものではないが、今後有料コンテンツ等を増やす場合個人的に気になったのが、GMの人とプレイヤーの中に「イマーシブクラウド」内の普段GMやっている人が、居たときのやり取り等はきおつけるべき点なのかなと思いました。  仲いい者同士で、話す分には当たり前だし問題ないし、当たり前なのではあるのだけど、それを外から見た時に、会話の中で、内輪的なネタの会話がGMと団体所属プレイヤーが行われた場合、ついていけない人は、確実に蚊帳の外状態であり、後のフラットの感想戦を言い合う際に、阻害要因につながるのじゃないかな?と思っています。  感想戦というのは、プレイヤーが主体で行われる事になるであろうかなと今の所思っていて、上記部分は、それらの阻害につながるんじゃないかな?と思いました。

VR体験ならではの要素の追加など マーダーミステリーの性質上、推理と感想戦がもっとも面白い部分であり、VRでやる以上それらをプラスの方向に持って行かせる活かし方はだいぶ練る必要があるかなと思っています。 例えば「アガスティアレコード」の場合家の模型が置かれているが、今回に限っては推理中にほとんど活用される機会がなかったのです。推測ですが、単純にみずらい。  メモも取りずらいなどがある以上どうしてもその辺は代替えする何かは今後慣れていない人も入れるなら間違いなく必須なのかなと思いました。現段階では、多くのものが、Discordでもできるし、なんならそっちの方が便利まである段階なのかなと思いました。  もっとも活かせそうな部分としては、現場検証や実際の場所っぽいものを移動を行えるような仕組みなどがあればいいのかな?と思った次第。(もちろんその場合は、ストーリーと合わせて、そういった背景は必要)

感想戦をいいやすい流れなどの仕組みの整備 感想戦自体好みがありますが、面白さの一部なので、結構この仕組み自体は、仕組みとして作ってると、その部分のクオリティは担保されそうな感じはあったのかなと思いました。  私が考える理想としての感想戦になるものとしては以下の通り - 客側(以下ゲスト)が推理や、フェーズの際に、非常に強く感じる感情(キャラクターのロール的にといったあくまでもプレイしているゲスト以外の部分で生じるものがあると良い)があるものか?そして、それらが進めば進むほど継続した感情であるか?(主にジレンマ) - ゲストが、このストーリーに対しての答えが、明確に理解して、納得できるものであるか? - ストーリーの答えに対して、抱いた感情に対して、行動が結び付きやすいか?

の3点かなと思っています。

感想戦として面白くなるパターンとして 1. 披露した推理が賞賛につながる推理でそれをゲスト側がその推理に納得出てきていたかどうか? 2. 動きづらいなどの感情を話せるネタとして持っているかどうか?

1に関しては、ストーリーに対して、ものの見事に推理をし真実を明かし説明が納得できる人が周りにいる状態なわけですが、推理した人は鼻高々だし、周りもあの人すげーとか、くやしいみたいな状態で、その人に対しての感想戦が始まる事になるから、結果的に会話量が増えて面白くなるパターンですが、基本的には、このパターンはかなり稀か意図的なものじゃないとたぶん発生しないものと考えています。

となると必然的に2になるわけですが、これらの感情に至るには、自分の状況と役割、目標(なにをしてはいけないとか何をする)とかが明確で、道中にそれらが、確定しづらい状態があるかどうかと、意識がそれに対して収束しているか?なのかな?と思っています。 バード将軍の執事を私はやったわけですが、王様に疑いをかからないようにする、自分に疑いをかからないようにするというのがあり、全ての行動やロールはそこに紐づきます。 疑いがかからないようにするために、こういった事に、相手に気づいてもらおうとか、 疑いがかからないようにするために、こいつが犯人だという部分を指摘しようといった感じです。

こうする事で、あの時のあれは、疑いがかからないようにするためだ、もしくはそれに準ずるものだという事になるので、感想戦として披露しやすい環境になるのかなと思います。

しかしながら、それらも正しい解説がなければおじゃんになるのも間違いないかなと思っています。 解説がわかりにくければ、あの時のあれはーみたいな事が発生しづらく感想戦がいたってさっぱりしたものになってしまいます。  ではわかりやすい解説は何か?  解説の際に、視覚情報 + 順序立てが該当するかなと思っています。例えばですが、説明の際には、プレイヤーが触れるものは一切合切消した上で、時間系列が文章としてあるなら、登場人物の行動を追っていく。 その際に、図面+実際のアニメーションなどを使えると良いかもしれませんね。

そこで、真実的な部分の内容を含む疑問符をゲスト側に投げかける。 例えば、私が、こういったのを覚えていますでしょうか?そうここにいる登場人物は、この4人だけではありません。 他に誰か思い当たる部分はありませんでしょうか?といった感じで、大ヒントみたいなのを投げる事で、なるべくゲスト側が気づける誘導。

さらに解説みたいな感じでしょうか?

この辺は、リアル脱出ゲームとかがかなりの割合でうまくやってたりするので、理想としてはあれかもしれませんね。

最後に

まだ、マーダーミステリーを経験していない人とかは、多少時間を取るのに難などはあるかもしれないですが、リアル脱出ゲームみたいな、推理と最後のあぁこうだったのかーといった感じの事が好きな人は良いものかもしれませんので、軽率に体験して良いのではないかなと思います。

 

経路探索A*探索アルゴリズムをやってみた

経路探索

経路探索の種類としては以下の通り - ダイクストラ法 - A*探索アルゴリズム

また、探索の仕方や、評価に使う値の例として、以下のようなものがあります。 探索の仕方(どのように、次の場所を確認していくか?) - 幅優先探索(開始地点基準で、離れた距離が同様の箇所を順番に探索していく。) - 深さ優先探索(選択した所が、探索する場所がなくなるまで探索していく)

評価に使う値の例(どれくらい移動にかかるコストがかかるかなどを計るためのもの) - ヒューリスティックコスト(そのマスに対して、移動するためのコスト) - マンハッタン距離(開始位置からゴール位置からの距離) - ユークリッド距離(2点間の直線距離)

ダイクストラ法とは?

候補を順番に確認していく方法。 そのため、確認の仕方によっては、最後の最後まで目的とした場所が見つからない場合がある。

そこで、その検索回数を減らすために後述するA*探索アルゴリズムがあります。

A*探索アルゴリズムとは?

ゲームによって、探索の制限が変化する場合はあるかもしれませんが、検索してよく出てくる基本的な内容としては以下の通りです。

探索の際に、 探索している場所からのゴールの地点との距離 + 探索している場所が、スタート地点から通ってきた距離を通ってきたか? という評価値を設定して、もっとも低い場所を検索していくというスタイルです。

これを実装した内容が以下のツイートです。

なお、障害物があったときはこんな感じの探索結果 f:id:herie270714:20210302172725p:plain

参考文献

https://mathtrain.jp/dfsbfs

https://youtu.be/T9bR6DnhJMM

https://yttm-work.jp/algorithm/algorithm_0015.html

それはかつて、夢見たような体験が、そこにはあるかもしれない[XOasis体験記]

注意

記事で扱う内容の特性上、R18な内容を含む内容もあります。 そういった事が苦手である場合はブラウザバックをお願いいたします。 また、一切情報を知らずに、体験したい場合なども同様にお願いいたします。

概要

XOasisに行ってきたので、おおまかな流れや、どんな感じの事を感じたかなどを、私なりに記述したつもりです。

目次

X-oasisとは?

X-Oasisは、VR上で1対1で性的なサービスを受ける事の出来る風俗店。 こまごました説明等は、実際のHPを見た方がはやいので以下のリンクで見てみてください。

https://x-oasis.com/static-page/960

セッションまでのざっくりとした流れ

セッションまでのざっくりとした流れとしては以下の通り

  1. 自身の環境での接続テストを行う・・・音声通話がただしく動いているかどうかのチェック。
  2. キャストの選択・・・あなたのお相手が誰かを決める
  3. シチュエーションや、プレイ内容を決める。 ・・・キャストさんによって、出来るプレイ内容とかが違ってくる 以下の動画の内容では最大3つくらいを選ぶ事が出来るみたいです。

参照元URL:

バーチャル風俗店X-Oasis - サービスの流れ | VR風俗店 X-Oasis

  1. 選んだ時間まで待つ・・・待っている間って謎の緊張感ありますよね。
  2. セッション開始・・・楽しみにまっていた時間のはじまり
  3. 終了・・・今日はお楽しみでしたね

といった感じの流れです。

接続テスト

これは、ログイン後のゲストマイページで行うもので、 「2台の端末」で行う音声の確認するものです。

「」書きで一応書いているのは、このテストを1台でやるものだと勘違いしたまま、やってたりする人がいたからです。(はい、私です。)

2台の端末で,ライブデートの音声をテストを各端末で行うと以下のような画面になります。

f:id:herie270714:20210217114516p:plain

※この際の音声マーク上の大文字英字と、数値の文字列は、テストを行う度に変わるものです。

私は、これをスマートフォン端末と、DeskTopでブラウザを開いて確認したのですが、 上記の画像のように、すごくシンプルなUIのため、個人的には確認に手間がかかった工程になります。(個人差があります)

理由としては、上側のものが、相手からの出力かどうかがふと振り返ったタイミングで大変まれによくどちらかがわからなくなる。(個人談)

一応画面上側のが、相手から聞こえるものの設定なので、聞く側画面で上側の音声をメガホンマークが斜線がない状態になっていれば、相手側からの通話が出来るようになっています。 下側は、自分でしゃべった内容が、しゃべった端末から聞こえるような仕組みのためのもので、多分しゃべった内容が、ちゃんと送れているかのチェックのため?なのかなと思います。

なお、スマートフォンなどでイヤホンをつけない場合、音声の出力と入力の物理的な距離の関係上、ハウリングが起きうる場合があります。 私の場合もスマートフォンと別の端末での声が、別の端末側で聞こえる場合が2分にしゃべり続けると1度くらいの頻度で発生していました。

ですが、上記くらいの頻度だと、実際のライブデート時にはほとんど気にならないレベルなので、恐らくいける事でしょう(各自の判断でおまかせします)

キャスト選択 及び プレイ内容の選択 と 備考

自分の好みなお相手と、プレイ内容を選んでいくところです。 好きにカスタマイズしましょう。

キャストさんは、かりんさんかなちぽよさんかで正直な所悩んではいたんですが、甘やかされたいと気分とお姉さんみがあるのが好きなので、かりんさんを選択。

プレイ内容は、結構興味を引く内容としてはあったのですが、ただでさえ色々と初めての身なので、想像とかイメージがつきやすいものとして妥当?と思われる、キス責めと、手コキを選択。

服装なども選ぶ事ができたのですが、服装選び自体が苦手なので、基本的には設定せず何も選択しないのは面白くないので、下着だけを選択。

備考部分には、主に要望とかを書く部分なのですが、何もかもが初めて過ぎてなんも判らんの状態だったので、ひとまず「両世界でもこういった事は初めてなので、リードしてもらえると嬉しいです。」とだけ書いて、予約ボタンを押しました。

予約が完了した時点で、予約完了のメールが登録しているメールアドレスに届きます。

ご利用プラットフォームの選択は、今回はスマホスマホVRゴーグルを選択しました。 一応、QuestやViveなどを使用して、VirtualDeskTopを通して行う事も可能でした。なので、そちらを見越してテストも行って問題がなかったので、そちらを選択する事も可能だったのですが、Quest版のVirtualDeskTopの設定が正しくできているか?ライブデートを行った際に正しく映像を見る事ができるのか?の確信がもてなかったので、今回はスマホVRでの参加しました。

セッション開始前

セッションのために色々準備していると良いです。 私自体は、気持ちがよくなるのためのアイテムなどを準備して、時間がくるまでわりかしそわそわしてました。

セッション開始までの流れとしては大まかに以下の通り

  1. 自分側のセッションの準備をする
  2. URLがメールで届くのを待っておく。
  3. キャストさんの準備完了のメールが届くのを待っておく。
  4. ライブデート開始

開始直前の時間はキャストによって時間がまちまちなのかもしれませんが、今回のケースだと開始五分前くらいにURLが送られてきます。 ただし、この時点でのURLはブラウザ開く事は出来るが、ライブデート自体は別途キャストさんのセットアップ完了のメールが来る感じの流れです。 スマホVRの場合、スマホの端末で、開始してから映像が映し出されてから、VR機器にセットする感じです。 映像が映し出されている状態になったら、すでに音声のやりとりが出来る状態になっているので、やりとりを楽しみつつスマートフォンを、VRヘッドセットにセットしましょう。

(なお、スマートフォンのアクションボタンとかが消せる機種などの場合は消しておくと良いです。)

セッション開始

最初の方結構、機器的不安や、行為的な不安とか一杯あったのですが、映像がちゃんと映った事と口頭でのやり取りをできた事でひとまず安堵したのもあり、細かい所まではあまり覚えていないのですが、おおまかな流れとしては以下

最初かるい挨拶とか ↓ 深い方のキス等々 ↓ 乳首とかいじられたりで徐々に下に移動してのお口でしてもらったり ↓ お胸ではさんでもらったり ↓ 本番 ↓ 終わった後の雑談

と言った感じの流れでした。

視点に関しては、基本的には固定で行われ、首を回してもそれによって視界が変わるわけではないので、キャストさんにゆだねる感じだと思ってください。

リアルタイムでのやりとりの中で、すごく肯定されている感じがすごい良かったなと、思いました。

例えばですが、キスをしてもらったりするのですが、私からもそれっぽく音とかを立てたりすると、「すごく上手だよ」とか、小さな喘ぎ声とかをあげてくれるという反応がもらえるので、それがなんというかすごく嬉しいとか、楽しいとかといったプラスの感情と言った感じのものを感じたりとかで、なんとなく「この人は受け入れてくれる」っていう感じのそういった小さな幸福感というんでしょうか?そういった安心感と心地良さがそこにはありました。

その後も、私側の反応としては、終始小さな喘ぎ声みたいなのしかだせなかったわけですが、それに対して、「かわいい」とか「いいこだねー」って言ってくれたりと、なでなでしてもらったりといったリアクションがあってすごく良かったという感じでした。

感想

正直なところVRでそういった事を行うのも初めてだったのもあって、セッション始まる直前まで、かなり不安になったり、そわそわしてました。

ところが、実際はじまっているみると、かりんさんがとても優しい雰囲気をかもしだしているのもあって、緊張はわりとすぐにとけて楽しめました。 セッション開始の所でもかいたこちら側の反応に対して、「すごく上手だよ」や「かわいい」や「いいこだね」とリアクションを取ってくれる事による肯定の安堵・安心感みたいなのを覚えました。

今回備考に、「両世界でもこういった事は初めてなので、リードしてもらえると嬉しいです。」と書いた通り、コミュニケーション的にも、行為的にも本当にリードしてもらえたので、楽しめるので、初めての人も安心して行ってみると思います。

VR風俗に興味はあるけど、プレイ内容とかむっちゃあるし、ちょっと不安、、、みたいな事を思っている人は、ぜひ行ってほしいと思いました。

興味がわいた人はこちらの記事も読んでみてください。とてもわかりやすい内容でした。

vr-lifemagazine.com

VRCでワールド制作においての固定砲台的なものの作成の仕方

概要

この記事は、以下のワールドで、作成した固定された筐体でハンドルを動かしたらそれに伴って、砲身も一緒に動くといった仕組みを作成する際の問題解決に関するものです。

作ったワールド

https://vrchat.com/home/launch?worldId=wrld_7c9e20ea-fb8c-4a1c-9cb8-ff17d560056b

この記事を読む事で、以下の内容を知る事ができます。 - 固定砲台系のハンドルと砲身の動かし方 - 一部同期の話

元としては、遊園地の車両に乗って、的を狙って点数を稼ぐアトラクションを模しています。

 開発環境

Unity2018.4.20f1 VRCSDK3-WORLD-2020.10.28 15.57_Public(なお作成時点ではすでに古い) U# v0.18.8 

固定砲台系とは?

ここでいう固定砲台系というものは以下の要件を満たすものです。 - ハンドルを持ったタイミングから砲身が、ハンドルの方角と逆方向に砲身が向いている。 - 他人から見たときに、ハンドルを持ったタイミングから動きだし、それ以外は動かない - さわっていない時は、初期位置に戻る

VRCのPickUpのみを利用した場合

おそらくもっとも最初に思いつく方法かなと思います。 色んなワールドで、PickUp使用して動かしている事があるので、もっとも身近で、最初に思いつくものじゃないかなと思います。 もちろん私も最初に試してみました。

結論を言ってしまうと、うまくいきませんでした。

理由はシンプルなもので、「固定砲台系とは?」の部分で書いた通り、それ単体だけでは解決出来るものではなかったためでした。

逆に、もの「単体」としての動作(例えば、銃を持つ、剣を持つ)の場合はかなり有効且つシンプルなもので、PickUpを追加するだけでとても楽に実装する事ができます。

実際に行ったアプローチ

そのため、基本的には今回は、以下のアプローチになりました。 1. PickUpObjectを持った時に、「操縦桿」を持ったという事を「銃身及びハンドルを動かす」部分に対して、通知を行う。この通知は、同期を行うため、そのオブジェクトのオーナーになった上で他の人にも送るようにする。 2. 通知が行われたら、「操縦桿」と「銃身」の中心となるオブジェクトの位置に対して、PickUpObjectの位置との差分を取って、それを操縦桿の方角、それと逆方向を銃身の方角に変更する。

---

f:id:herie270714:20210204183037p:plain
通知を行う図

同期に関しては、以下の記事にて、もう少し詳細を記述しているので、そちらをごらんください。

Udonのワールドを作った時の同期の話 - herie270714’s blog

さて、結局のところ、この仕組みとして肝となるものとしては 1. PickUpObjectとハンドルの動かす処理をしている所は違う 2. PickUpを行ったという通知を行う

の2点にかぎられています。 1に関しては、最初のPickUpのみを使用した際に発生する問題点の回避のために行うものです。PickUpObjectは常に同期されてしまうため、それによって、見かけのハンドルと、それ 2に関しては、時分以外の人の弾が飛んでいる場所を計算するために必要だったので同期を行っています。もう少しかみ砕くならば、2の通知が来ることで、受け取り手側の指定の操縦桿が動いている状態であるとなり、その人側で、送信者の手の動きに対しての位置から計算して、疑似的にほぼ同様の動きをさせています。

この時、同期されているのは、手の動き(PickUpOject)のみであり、それ以外は、同期されている内容に対して、「ローカル上」で再現を行っているというものです。

この「ローカル上」というのは、自分のPC上で動いている状態のものをさします。 この「ローカル上」では、通信によって、相手の状態が通信で、おくられてこないとそれらが再現されないものです。一番身近な例かはわかりませんが、通信状況が不安定な状態(相手の状態が送られてきていない状態)から、安定した際に、相手のポジションがワープする(最新の相手の状態が送られてくる)といったものが身近かもしれません。

なので、砲身などは同期を取らなければ、他人から見たときには、動かないものですから、PickUpを行ったというものを通知して、以降は、PickUpによる位置同期のみで「各ローカル上」で再現を行っています。

この同期を行う理由としては、主に相手の弾を撃った場所を特定するためです。 VRCでの同期、通信などは、値の同期はたしかに可能ですが、 以下の記事によると

Udon開発する上での注意点[Unity]

https://qiita.com/toRisouP/items/16bd06aa303a1bb1a747

UdonSyncは「常に送信している」ものであり、量によっては、大変負荷がかかるっていうものらしいのです。 一番実直に書くならば「位置」と、「向き」を同期すれば、可能だとはおもいますが、上記の仕組みをVRCPickUpと別に使用する必要が出てくるため、それらを少しでも控ようといった具合のためです。

また、本来の目的である、「他人がどこらへんを狙ったか?」によって、自分の弾と混在する遊園地のあのアトラクションのごちゃごちゃ感も「弾を打った」という同期だけで達成する事ができます。

弾の同期に関しても同様に、UdonSyncを使用して、直接的に位置の同期を行う事もできます。 しかし、砲身がシュミレートによって向いているであろう場所を向いているので、わざわざ位置同期をしなくても、「そのタイミング」「その方向」さえわかれば写真判定レベルの事をしないとわからないレベルでそれっぽく動いている事でしょう。

終わりに

今回は、「UdonSync」に絡むものを極力使わない方向性で作成しました。近いものとしては、今回のワールドにおいては、PickUpのみしかUdonSyncに近い動作のものがないのではないでしょうか? その関係で、他にもそれっぽく動かしているというものがあり、それらは長くなるので、以下の内容にまとめています。 どうぞお時間とご興味がありましたら、ご一読ください。

Udonのワールドを作った時の同期の話

概要

ワールド名:Ride Around ShootingGame を作った際に、同期関係のものに関して焦点をあてて工夫した点などを記事化したものです。

ワールドは以下 https://vrchat.com/home/launch?worldId=wrld_7c9e20ea-fb8c-4a1c-9cb8-ff17d560056b

同期した内容としては以下の内容です。 - 他人から見た他の人の操縦している砲身の向き 及び弾の同期 - スコアの同期 - 敵のクールタイムの同期

[注意] ワールドを一度体験していただいてからこの記事を読んでいただくと理解しやすい可能性があります。 また同期の関係上、2人以上でワールドを遊んでいただくとわかりやすいです。

目次

  • 開発環境
  • 前提知識や前提条件
  • 同期についての少しだけ補足
  • オーナーという概念について
  • 他人から見た他の人の操縦している砲身の向き 及び弾の同期
  • スコアの同期
  • 敵のクールタイムの同期

開発環境

Unity2018.4.20f1 VRCSDK3-WORLD-2020.10.28 15.57_Public(なお作成時点ではすでに古い) U# v0.18.8 

前提知識 や 前提条件

-前提知識- - プログラムを多少書いたことがある。 - Udonの同期が、UdonSyncを使用しない場合、値を送る事が出来ないという事を知っている

-前提条件- - [UdonSync]が常に同期されるものである可能性が高いため、極力使用しない作り方である

これは以下の記事の内容から来ている考えです。

Udon開発する上での注意点[Unity] https://qiita.com/toRisouP/items/16bd06aa303a1bb1a747

同期について少しだけ補足

これから同期という言葉が飛び交いますが、同期とはいったいなんなのでしょうか? 同期とは、他の人の世界に影響を及ぼすといったイメージを持っていただければ、おおまか間違えません。 同期がどういったものかわかる問題ないという人は、この項目を飛ばして頂いて問題ありません。

よくワールドとかで実装されているミラー(Local)などは、自分の世界だけしか影響を受けないもので、これは「同期されていない状態」でローカルといいます。  一方、ミラー(Global)といったものは、自分とか相手が触ったものに対して、「触った」という事を「通知」されて、「他の人も同様に同じ状態になる」といったものです。  この通知によって、他の人も同様の状態になることが「同期」で、Globalとかの言葉でついているIntarctのテキストとして使われている事が多いです。

基本的には、どんなゲームワールドもゲーム開始とかは、なんらかの手段で「同期」がされており、そのおかげで「ほぼ」同じタイミングで、ゲームを開始できます。

念のため、「ほぼ」とつけたのは、同期=その瞬間相手も同じ状態になるというイメージを持つ人が多いかもしれませんが、そうではありません。 多かれ少なかれ自分、もしくは相手の通信状況によっては、それなりの遅れが存在してしまうためです。 AさんからBさんに対して、PickUpできるObjectを持ったとします。 これはAさんからBさんに対して、Objectを持ったという事を通知して同期されなければ、Bさんからみた時にAさんがObjectを持っていない状態になります。

オーナーという概念について

同期関係を考える時にこの「オーナー」は知らなければいけません。 VRCには「オーナー」という概念が存在します。 オーナーは最初にインスタンスに入った人の事を指し、それ以外の人はオーナーではない状態です。 また、オーナーがインスタンスから抜けた場合、時系列的に入って来た人が次のオーナーになる性質を持っています。 (ただし、プログラム等で、強制的に変える事は可能) またこれらは、GameObjectごとに対してのオーナーを持っています。

この「オーナー」は、個人的には、値とかの同期を取る時の基準というイメージです。 例えば、そのオーナーである人以外の人が同期の取られている数値Aを1だと言っていたとしても、オーナーである人が数値Aを0だと言ったら、それは0として扱うみたいイメージに近いと個人的には考えています。

そのため、何かの値として最初に更新をかける場合、それをオーナーで処理する必要があります。 先ほどの例だと、数値Aを1だと言っている人が、最初に更新をかける必要があるので、その人をオーナーに変えてから数値Aを更新する必要があるといったものです。

他人から見た他の人の操縦している砲身の向き 及び弾の同期

以下の記事にて、詳細が記載されていますので、こちらも合わせて参照ください。

基本的には、PickUpObject自体は常に同期を取られているものと、持った人がオーナーになった上で、PickUpObjectとPickUpObjectを持った、落としたの状態の2つだけ同期を行っています。

位置同期はPickUpObject

ゲーム開始の同期

このワールドでは、ゲーム開始のためのStartのオブジェクトを触ったタイミングで、通知されるだけです。

通知を受けた際に、椅子に座らされ、それと同時にアニメーションを再生しています。 厳密には、押した人とそれ以外の人では、誤差のレベルで位置がずれている事があるかもしれません。 しかしながら通知を受けた際に、アニメーションを動かしているので、それほどずれを感じないはずです。

スコアの同期

このゲームでは、4人で争えるように、スコアでのランキングなどを表示しています。 このスコアも、同期あるいは、それをカバーする何かをしなければ基本的には、点数が同じ数値になる事はありません。

では、SendCustomNetWorkを使用して、プレイヤー何番が、何点を取ったという事だけ取っています。それ以外は同期を取っていません。 つまり、スコアの合計などは、それぞれのローカルで作られている点数です。 まぁ、何番の人が何点を取ったというものが取られていれば、基本的には、同じ点数になるため、スコア自体を同期とらなくていいという考えです。

ただ、SendCustomNetWorkは少し曲者で、「数値」を相手に送る手段がないため、基本的には関数呼び出しを行うという方式しかとれないです。 そのため、「誰が」「何点」取ったというものを、関数で識別する必要があります。

その方法とは、Targetとなっているオブジェクトを的にあたるようと、点数用のオブジェクトに分けた上で、点数用のオブジェクトのオブジェクト名を点数とした形式にしています。

また、通知方法を図で表すと以下の内容になります。

f:id:herie270714:20210201003756p:plain
スコアの取得のされ方の図

誰がというものは、各乗る場所によって、名前とひもづけているので 「誰が」は「何番の」という言い換えを行う事ができます。

これで、「誰が」「何点」という部分を指定できるので、以下の形式の文字列でメソッド名を統一する事で、指定したメソッドを呼び出す事ができます。

例えば、プレイヤー1の人が、1点を取った場合のメソッドとしては以下のようなメソッド名になります。 Player1GetPoint1

このPlayer〇GetPoint〇の〇の部分をプレイヤー番号と、獲得した点数といったものが入ります。

メソッドを作成する部分の処理としては以下のようになります。

string methodName = string.format("Player{0}Point:{1}",playerNo,getPoint)

なので、プレイヤー数 × 獲得できるポイント種類数 の関数を用意する必要があります。

あとで調べてわかったんですが、キャストを使用したGetComponentを使用すれば、ローカル上では、数値を取る事ができたみたいです。しかしながら、同期の段階で、数値を送るもしくは確実に同じスコアになる部分が怪しいので、どの道同じアプローチになってたと思います。

敵のクールタイムの同期

敵の的には、クールタイムというのが実装されています。 これは、一度的にあててしまうと、連続的に点数を稼ぐ事ができてしまうため、1-2秒あたりのクールタイムを設けています。(的によってはもっと設けている可能性もあります)

クールタイムの同期はどのようにしているかというと、「当たった」という通知だけを行っています。これは「弾を打った」の同期に近い部分があります。

最後に

同期関係については、VRCの現状難しい部分や、安直に同期させた結果処理的に不安定になったりという事が多々起こりえるというのは、色んなワールドをめぐっているあなた方ならわかる事かと思います。

新しいゲームワールドを作成する上で、何か参考になる事があれば、幸いです。

VRCUdonWorldで初めてチーム開発した時に、こうしておけばよかったとかの感想+小ネタ

概要

この記事では、VRCのワールド制作を3人のチームで作成した時の内容の振り返りです。 「DENSUKEHORRORWORLD」のワールドを作成するための、チーム開発を行うにあたり、良かったとか、ここは改善したほうがよかったなどといったもの。 使用したツールなどを記録したものです。


目次

  • チーム開発のはじまりの経緯
  • チームのメンバー構成
  • 開発環境 使ったツールなど
  • チーム開発を行うにあたって、良かった事、及び改善点
  • 途中起きたVR版で反応が起きなかった時の対処法
  • 他のチームメンバーの記事

チーム開発のはじまりの経緯

経緯としては、単純な理由で、ホラーが苦手な子が、クエストユーザーで、いけるホラーワールドがほとんどなかったため。 ないなら、作ればいいじゃない?という話になり、作る事になったのが事の始まりです。


チームのメンバー構成

herieru @herie270714

kanchan @vr_min_chan 

kyon @kyon_VRChat 

いずれもなんらかのプログラムは弄ってはいる状態ではあるが、Udonというものには触れている状態ではないため、Udon初心者且デザインは全員出来ない状態でのメンバー構成です。

開発環境 使ったツールなど

Unity2018.4.20f1 VRCSDK3-World 2020.10.28 15.57(たしかこれ) U# v0188以降のもの

Git + GitHub(Ver管理用)

Discord(作業通知や、Issueなどの連絡を行いやすくするため)


ワールド作る上での方針

方針としては、ホラーの軽減表現を入れて、ホラー苦手でもそれなりにみんなと楽しめるホラーを作るというものでした。

理由として、起点となったその子が本当にホラーが苦手だったので、作ったワールドで嫌な気持ちになったらいけないのと、後ほどトラウマになってはいけないというのがありました。

なので、みんなで行って、その子が軽減された表現でのホラーを見て、一緒に行った人達ががっつりホラーという形になれば、「あんなのが怖いなんてねー」みたいな会話が生まれて面白いね。という事になり、DensukeSwitchというものが生まれました。


 しといて良かった事、及び改善点

しといて良かった事

  • 作業シーンの分割 個人単位で、作業を行う事が出来るため他の人の作業内容に干渉せず作業を行う事が出来るという点で良かった。
  • Object配置においてのルール 具体的には、上記の作業シーンの分割に対して、最終的に統合する必要がある。 そのため、それぞれのシーン内のTopの階層から一段下げた所で、オブジェクトを配置するようにする。

    Ex Root

    • ここから各シーン内での作業
  • 使用するアセットが、別々でインストールしてもScene内で同様に適用されるかのチェック 内容としては、A側の環境で使用した追加Assetが、B環境で新規でインストールしても、Aの追加Assetを使用した作業がなくならないか?というものです。

    理由として、GitHubの制限で、あまり大きなコミットが不可能になる場合があるための処置でした。

    チームの方針としては、Assetは使用するものに対しては通知。それぞれの環境下で、インストール後に、他の人の作業の内容を取り込むようにしました。

    ちなみに、追加されたAssetを、インストール前に作業内容を取得してしまうと、作業した内容と際がでてしまうのでかならずインストールしてからする必要があり。

改善点

  • 動作確認する際にDeskTopのみでの確認じゃなくて、VRでの確認をする必要があった。 UdonBehaviorから行う事が出来るInteractの機能を使用したワープ機能だったが、開発終盤まで、全員DeskTop(主にTestBuildによる)で開発していたため、気づかなかった。 解決自体は、後述。

  • 修正のしやすいObjectHowToなどの事前共有とかはしといたほうが良かった。 例えば、特定の部屋を作成した場合に、一つGameObjectをはさんで、大まかの移動などはそのObjectで行い、細かい内容は、それより下の個々の移動でおこなうといったもの。

    これの優れている内容は、オブジェクトの原点から離れすぎた事による失敗などが発生した場合、修正が、まとめているRootのオブジェクトだけを移動させればよいため。


途中起きたVR版で反応が起きなかった時の対処法

これはUdonBehaviorのComponentがついているもので、Allow OwnerShip Transfer On Coliderのチェックがついている状態 且つ ColiderがIsTriggerでない場合、発生します。 それもVR環境でのみ発生し、インスタンスを立てた人が誰でもかかわらず、発生しました。

内容としては、VR環境下で、Coliderが反応しない状態になる。事が発生します。

これの解決策としては、そのオブジェクトに対してRigidbodyをつけた上で、IsKinematicをOnにした状態のものをつけると、回避は可能です。

他のチームメンバーの記事

かんちゃん VRChatのワールド制作をチームでやってみた話

zenn.dev