土と石と木を再設置できるようにする

「VキャスのVCIで◯ine◯raftっぽいもの作る Advent Calendar 2024」8日目

Vキャス内で、穴を掘って、石を砕き、木を切って、組み合わせて武器を作って、何なら出てくる敵を倒して・・・
そんなことをやりたいなぁっていう試みを12月でできるところまで行こうというカレンダーの8日目です！

今日は持ち運んで動かしたブロックをUseをしたらその場所に設置できるようにします。

# 土と石と木を再設置できるようにする

昨日の時点では、持ち運べる状態のブロックを持ち運べないブロックの中に隠しておき、そのブロックごとの連続で触る回数設定に到達したら、持ち運べないブロックをふっとばして、持ち運べる状態にしていました。

再設置をするということは、持ち運べないブロックを動かしたブロックのもとに再度持ってくる処理が必要です。
ブロックを再利用するので、使い回せるようにブロックを変数に記録するようにして、それを呼び出す書き方に変更していきます。

そこで以下のような作業を今日はしていきます。
① ブロックの情報を変数にいれるように記述を変える
② ①に従ってブロックを持てるようにする処理を書き換える
③ ブロック設置処理を書く
④ VR内で確認する

それではやっていきます。

# 手順

## ① ブロックの情報を変数にいれるように記述を変える

動かせるまでの回数を制御していた「blocks」変数を拡張します。
```lua
local blocks = {
    Stone={count=20,itemcount=25,items={},moveitems={}},
    Soil={count=5,itemcount=9,items={},moveitems={}},
    Tree={count=10,itemcount=3,items={},moveitems={}},
    leaf={count=1,itemcount=19,items={},moveitems={}}
}
```
意味合いとしては、以下のようになっています。
・動かせるまでの叩く回数をcountで指定
・各種類ごとのブロックの数をitemcountで記述
・itemsに動かせないブロックの情報を格納するための場所を確保
・moveitemsに動かせるブロックの情報を格納するための場所を確保

そして、このすぐ後に、ブロック情報を格納する処理を書きます。
格納といっしょに、これまで触れてしまって困っていたので、動かせるブロックは小さくして遠くに飛ばす処理を施しておきます。
```lua
for key, value in pairs(blocks) do
    for i=1, value.itemcount do
        blocks[key].items[i] = vci.assets.GetTransform(key..tostring(i))
        blocks[key].moveitems[i] = vci.assets.GetTransform(key..tostring(i).."_move")
        blocks[key].moveitems[i].SetLocalScale(Vector3.__new(0.001, 0.001, 0.001))
        blocks[key].moveitems[i].SetLocalPosition(Vector3.__new(100, 100, 100))
    end
end
```
これで、動かないブロックと動くブロックの情報がblocks変数に全て格納されました。

## ② ①に従ってブロックを持てるようにする処理を書き換える
①でblocksの構造を以前と変えたのと、ブロック情報も格納したので記述を変更します。
```lua
for key, value in pairs(blocks) do
    if string.find(subItemName,key) ~= nil then
        if flg.count > value.count then
            n = tonumber(string.gsub(subItemName, key,""),10) 
            value.moveitems[n].SetLocalScale(Vector3.__new(0.15,0.15,0.15))
            value.moveitems[n].SetLocalPosition(value.items[n].GetLocalPosition())
            value.items[n].SetLocalScale(Vector3.__new(0.001, 0.001, 0.001))
            value.items[n].SetLocalPosition(Vector3.__new(100, 100, 100))
            flg.count=0
        end
    end
end
```
subItemNameが当たったVCISubItemの名前ですが、連続で当たった回数がブロックの種類に従った回数よりも多い可かを`if flg.count > value.count then`で判定します。

そして、回数が判定値より多ければ、ブロックの番号を`n = tonumber(string.gsub(subItemName, key,""),10)`で確認します。

そして`value.moveitems[n]`で指定される、動かせるブロックを動かないブロックの場所に設置し、`value.items[n]`で指定される動かせないブロックを遠くに飛ばして小さくします。

これで、以前からあったブロックが動かせるようになる処理の記述は完成です。

## ③ ブロック設置処理を書く
ブロック設置の処理を書きます。
```lua
function onUnuse(subItemName)
    for key, value in pairs(blocks) do
        if string.find(subItemName,key) ~= nil then
            n = tonumber(string.gsub(string.gsub(subItemName, key,""),"_move",""),10)
            local p = value.moveitems[n].GetLocalPosition()
            value.items[n].SetLocalScale(Vector3.__new(0.25, 0.25, 0.25))
            value.items[n].SetLocalRotation(Quaternion.Euler(0, 0, 0))
            value.items[n].SetLocalPosition(Vector3.__new(math.floor(p.x/0.25)*0.25,math.floor(p.y/0.25)*0.25,math.floor(p.z/0.25)*0.25))
            value.moveitems[n].SetLocalScale(Vector3.__new(0.001, 0.001, 0.001))
            value.moveitems[n].SetLocalPosition(Vector3.__new(100, 100, 100))
            flg.count=0
        end
    end
end
```

Use処理が終わったタイミングに発動し、動くブロックは動かせるときと逆にふっとばし、動かせないブロックを動くブロックにUSEをした場所に設置をします。

設置の際に、単純に動かせるブロックがある場所においてもいいですが、それだと角度や位置が完全にそのブロックがあった状態になってしまいます。
それでもいいですが、並べたりしていきたいので、自動で整列された状態に設置したいです。
そこで、動かせるブロックの位置から0.25刻みの最も近い位置に設置するように調整を考えます。

今回はとりあえず、XYZ座標を0.25で割って、その整数に四捨五入をし、0.25を再度掛けることで記述しました。
```lua
math.floor(p.x/0.25)*0.25
```

これで、動かせるようにできてなおかつ設置もできるようになったはずです。

## ④ VR内で確認する

VirtualCastを起動し、ルームに入って再度確認します。
![2024120820350508_SAC-CRAFT 1.0_しきはふり.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222644/d2da5568-fd24-ecd1-34b8-7ca27c91868f.jpeg)

動かして、設置できることが確認できました。

# おわりに
今日で、叩いて動かせるようになり、動かせるブロックをUSEで設置できようになりました。
ただ、今は全部の動かせるブロックが動かないブロックと同じ数あり無駄が多く感じます。
また、荷物として持っているというような状態が今はないので、持っていてそれを取り出すということを明日以降は考えようと思います。