ルーム来訪者に、すべてVCIが読み込まれるまで待たせるVCI

# ルームでVCIが全部読み込まれるまで、待ってて欲しい！
ルームでは、ロケーションを含めて、複数のVCIで構成されていると思います。
Vキャスでは、すべてのアイテムが読み込まれる前から、ルームに入ることができるので、
* モデルの一部が読み込まれる前の、景観が悪い状態で散策されてしまう
* 本来、コライダーがある場所を突破されてしまう
* イベントのトリガーを踏んだ際に、連携するアイテムがないため、エラーが発生してしまう

などといった事が発生してしまいます。
これらを防ぐために、自分の作ったルームでは↓のような、通せんぼをする看板とコライダーを設置しています。
ここでは、どのようにこちらのVCIを実装したか、ご紹介します。
![ダウンロード (4).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985893/b76a0767-e90c-1619-c8f4-c52479af9f82.gif)
# 読み込みを待っている間も楽しんで欲しい！
Vキャスのいい点の一つとして、ロケーションが読み込まれれば、ルームに入れる点が挙げられます！
（ミクランドとかでも思いましたけど、待ち時間を最小限にして、ロケーションを楽しめるっていいですよね！）
このいい点が先ほど挙げた、問題に繋がってしまうのですが、このVキャスのいい点を活かしたロケーションの構成にしていきたいと思います！
まず、ロケーション自体をリスポーン地点を中心に構成し、読み込みを待つアイテムVCIが見えないような構造にしておきます。
今回は、このような袋小路を作って、ここをリスポーン地点として、待ってもらいます。
![スクリーンショット (61).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985893/7439c1eb-928f-1a10-cbd3-1ca1779bfcfd.png)
さらに袋小路の先は、道が曲がるようにして、ロードしているアイテムVCI（この先にある建物）が見えないようにしました。
![スクリーンショット (62).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985893/4e7f0485-2a10-31ed-1acd-95db908ee6a7.png)

待っていただいている間に楽しんでもらうために、雰囲気に合うBGMも用意します。
今回はフリーBGMを使うと、「あ、この曲は、あの動画で使われてるBGMだ」というような、違うところに意識が取られてしまう恐れがあったため、有償BGMを使用しました。
Audiostock様のこちらのBGMを使わせて頂いてます。

https://audiostock.jp/audio/863393

続いて、待っていただいている間、風景も楽しんでもらうため、[亞希乃さん](https://twitter.com/fairychirno)作の素敵な星空も用意しました。
これで、建物の間から見える星空がいい感じになりました！

https://seed.online/products/40fc961192c0ea8ff1267c81206af1cab8e945b3debcbadc16a5f2387c700a12

これで、待っている間に楽しんで頂ける風景と音楽の用意できました！
![2022122401154829_シャボンの国_小山内シノブ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985893/e942e3c8-28fc-e5a3-ea7f-f88ca95a875e.jpeg)

# VCIの読み込みに対応して、通せんぼするVCI
冒頭でご紹介したこちらのVCIは、リスポーン位置から少し離れた位置にあり、限りなく軽くしてあるので、ルームに入った瞬間にいち早くロードさせ、通せんぼする仕組みとなっています。
厳密には、こちらのVCIは2つのアイテムで構成されていて、「通せんぼするコライダーVCI」と「コライダーが機能しているかどうかを表すエフェクトVCI」となってます。
これは、前者のVCIをなるべく早くロードして、確実に通せんぼするためです。
![ダウンロード (4).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985893/b76a0767-e90c-1619-c8f4-c52479af9f82.gif)
さらに、確実に狙い通りの位置で、来訪者を通せんぼできるよう、messageで移動位置情報を飛ばして、移動させるようにします！
こんな感じのやり取りを、VCI同士でやらせて移動させます。
![Nekoyama_nae (idolD) (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985893/47434529-eb60-7f9c-e503-8dab2c47dd98.png)
実際のスクリプトは以下のような感じで、「通せんぼVCI」のvci.message.Emit("EntranceBlockTransformPlz", ...)が上図①、「ロケーションVCI」のfunction blockTransformReturn ...が上図②、「通せんぼVCI」のfunction blockTransform ...が上図③に対応してて動いてます。
ロード関係は、他者の環境は関係なく、自分の環境（ロードされたか、されないか）が重要となるため、ローカルで処理されるように、自分の名前も一緒に飛ばして、自分から送られたメッセージのみをトリガーとして、処理されるようにしています。
「エフェクトVCI」は「通せんぼVCI」と同様に、移動させ、エフェクト再生のスクリプトを追加するだけでOKです。
（ルームは位置情報が記録されるので、毎回スクリプトで移動を実行する必要はありませんが、念のため毎回実行するようにしています。）
```lua:通せんぼVCI
local block = vci.assets.GetTransform("Block")--”Block”は通せんぼするSubItem
local blockPos = Vector3.zero
local blockRot = Quaternion.identity

local transformFlag = false
--入場制限のブロックの位置情報取得
function blockTransform(sender, name, message)
    if vci.studio.GetLocalAvatar().GetName() == message[1] then
        blockPos.x = message[2]
        blockPos.y = message[3]
        blockPos.z = message[4]
        blockRot.x = message[5]
        blockRot.y = message[6]
        blockRot.z = message[7]
        blockRot.w = message[8]
        block.SetPosition(blockPos)
        block.SetRotation(blockRot)
        transformFlag = true
    end
end
vci.message.On("EntranceBlockTransformReturn", blockTransform)

function updateAll()
    if transformFlag == false then
        vci.message.Emit("EntranceBlockTransformPlz", vci.studio.GetLocalAvatar().GetName())
    end
end
```

```lua:ロケーションVCI
local entranceBlockPos = vci.assets.GetTransform("EntranceBlockPos")--"EntranceBlockPos"は通せんぼVCIの位置情報の空オブジェクト
--入場制限のブロックの位置情報
function blockTransformReturn(sender, name, message)
    if vci.studio.GetLocalAvatar().GetName() == message then
        vci.message.Emit("EntranceBlockTransformReturn", {
            vci.studio.GetLocalAvatar().GetName(),
            entranceBlockPos.GetPosition().x,
            entranceBlockPos.GetPosition().y,
            entranceBlockPos.GetPosition().z,
            entranceBlockPos.GetRotation().x,
            entranceBlockPos.GetRotation().y,
            entranceBlockPos.GetRotation().z,
            entranceBlockPos.GetRotation().w
        })
    end
end
vci.message.On("EntranceBlockTransformPlz", blockTransformReturn)
```
続いて、ルーム内アイテムがすべてロードされたことを確認し、通せんぼを解除する工程になります。
ここでは、新たに「管制VCI」が出てきて、VCIの状況を確認したり、「通せんぼVCI」に通せんぼの解除をお願いしたりします。
![adcale2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985893/308c6315-d0d6-9e0d-b405-12809a179576.png)
![adcale3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985893/03512dd5-d671-9bb6-eb65-1173a343eb9f.png)
上記のイラストをスクリプトにすると以下のような感じとなり、「管制VCI」の vci.message.Emit("BovoloInitializeCheck",...が上図①、「アイテムVCI」のfunction initialize(...が上図②、「管制VCI」のvci.message.Emit("ALLVCISetOK",...が上図③、「通せんぼVCI」のblock.SetActive(false)が上図④に対応して動いてます。
上図にはありませんが、その後、「通せんぼVCI」からvci.message.Emit("BlockOFF",...を出して、「管制VCI」からの③を停止させてます。 
（「エフェクトVCI」は、ほとんど「通せんぼVCI」と一緒なので、省略）
「アイテムVCI」は、読み込みが完了しない限り、上図②が動かないので、すべてのアイテムVCIが読み込まれて、すべての上図②が実行されることで、すべてのアイテム読み込み→通せんぼの解除、となります。
```lua:管制VCI
--他のVCIの初期化フラグ
local initialFlag = false
local initialize1 = false
local initialize2 = false
local entranceFlag = false
local effectFlag = true
local blockFlag = true

--他のVCIの初期化チェック
function initializeCheck(sender, name, message)
    if vci.studio.GetLocalAvatar().GetName() == message then
        if "Bovolo1InitializeOK" == name then
            initialize1 = true
        end
        if "Bovolo2InitializeOK" == name then
            initialize2 = true
        end
    end
end
vci.message.On("Bovolo1InitializeOK", initializeCheck)
vci.message.On("Bovolo2InitializeOK", initializeCheck)

--入場可否チェック
function entranceCheck(sender, name, message)
    if vci.studio.GetLocalAvatar().GetName() == message then
        if "EffectOFF" == name then
            effectFlag = false
        end
        if "BlockOFF" == name then
            blockFlag = false
        end
    end
end
vci.message.On("EffectOFF", entranceCheck)
vci.message.On("BlockOFF", entranceCheck)

function updateAll()
    if initialFlag == false then
        vci.message.Emit("BovoloInitializeCheck", vci.studio.GetLocalAvatar().GetName())
        if initialize1 == true and initialize2 == true then
            initialFlag = true
        end
    elseif initialFlag == true and entranceFlag == false then
        vci.message.Emit("ALLVCISetOK", vci.studio.GetLocalAvatar().GetName())
        if effectFlag == false and blockFlag == false then
            entranceFlag = true
        end
    end
end
```

```lua:アイテムVCI
--VCIの読み込み判断関数、ローカルで実行
function initialize(sender, name, message)
    if vci.studio.GetLocalAvatar().GetName() == message then
        vci.message.Emit("Bovolo1InitializeOK", vci.studio.GetLocalAvatar().GetName())
    end
end
vci.message.On("BovoloInitializeCheck", initialize)
```

```lua:通せんぼVCI
function blockStop(sender, name, message)
    if vci.studio.GetLocalAvatar().GetName() == message then
        block.SetActive(false)
        vci.message.Emit("BlockOFF", vci.studio.GetLocalAvatar().GetName())
    end
end
vci.message.On("ALLVCISetOK", blockStop)
```
# おわりに
これで、すべてのアイテムが読み込まれまで、待ってもらうような準備が整いました。
よろしければ、みなさんもこんな感じの”待機場所”をルームに作ってもませんか？

実は、「エフェクトVCI」のほうでも少し一工夫があるのですが、それはまた別の機会がありましたら、ご紹介します！