「VキャスのVCIで◯ine◯raftっぽいもの作る Advent Calendar 2024」12日目
Vキャス内で、穴を掘って、石を砕き、木を切って、組み合わせて武器を作って、何なら出てくる敵を倒して・・・
そんなことをやりたいなぁっていう試みを12月でできるところまで行こうというカレンダーの12日目です!
今日は装着した状態でも持ち運べるようにしていきます。
持ち物の概念をつくる その4
装着のコードも書いていくので今日はコード整理をメインにやっています。
手順は以下の通り。
① 追従コードを変更する
② 装着しているときと持っているときで追従オブジェクトを切り替える
さっそくやっていきます。
手順
① 追従コードを変更する
一昨日の時点では、CubeとCylinderを掴んだときだけに追従したら良いと思っていたのですが、
よくよく考えると手につけた状態では、Sphereに追従する必要がありました。
つまり場合によって3種類のオブジェクトのどれを追従するということがあり得るということです。
そこで、変数へのオブジェクトの格納の書き方や追従の書き方を整理します。
SubItems = {
Cube = {item=vci.assets.GetTransform("Cube")},
Cylinder = {item=vci.assets.GetTransform("Cylinder")},
Sphere = {item=vci.assets.GetTransform("Sphere")},
slot1 = {item=vci.assets.GetTransform("slot1")},
slot2 = {item=vci.assets.GetTransform("slot2")},
slot3 = {item=vci.assets.GetTransform("slot3")},
slot4 = {item=vci.assets.GetTransform("slot4")},
slot5 = {item=vci.assets.GetTransform("slot5")},
slot6 = {item=vci.assets.GetTransform("slot6")},
slot7 = {item=vci.assets.GetTransform("slot7")},
slot8 = {item=vci.assets.GetTransform("slot8")},
select = {item=vci.assets.GetTransform("select")},
l_v = {item=vci.assets.GetTransform("l_v")}
}
宣言は全てのオブジェクトをまとめてにしました。
わざわざ変数を分けて記述が増えるのも良くないのでまとめてしまいます。
そして、CubeとCylinder、Sphereの3つのオブジェクトからの距離と角度を格納します。
サイズも直書きするより、元のサイズを取得しておいたほうが正確だしコードが減るので、変数内に格納しておきます。
for key, value in pairs(SubItems) do
if key ~= "Cube" then
SubItems[key].cubedist = SubItems[key].item.GetPosition() - SubItems.Cube.item.GetPosition()
SubItems[key].cuberoat = Quaternion.Inverse(SubItems[key].item.GetRotation()) * SubItems.Cube.item.GetRotation()
end
if key ~= "Cylinder" then
SubItems[key].cylinderdist = SubItems[key].item.GetPosition() - SubItems.Cylinder.item.GetPosition()
SubItems[key].cylinderroat = Quaternion.Inverse(SubItems[key].item.GetRotation()) * SubItems.Cylinder.item.GetRotation()
end
if key ~= "Sphere" then
SubItems[key].spheredist = SubItems[key].item.GetPosition() - SubItems.Sphere.item.GetPosition()
SubItems[key].sphereroat = Quaternion.Inverse(SubItems[key].item.GetRotation()) * SubItems.Sphere.item.GetRotation()
end
SubItems[key].Scale = SubItems[key].item.GetLocalScale()
end
SubItems.Cube["roat"] = Quaternion.Inverse(SubItems.Cube.item.GetRotation())
SubItems.Cylinder["roat"] = Quaternion.Inverse(SubItems.Cylinder.item.GetRotation())
SubItems.Sphere["roat"] = Quaternion.Inverse(SubItems.Sphere.item.GetRotation())
変数を変えたので、それに従ってCubeとCylinderの追従コードの記述も更新。
if mode then
local pos = SubItems.Cube.item.GetPosition()
local roat = SubItems.Cube.item.GetRotation()
for key, value in pairs(SubItems) do
if key ~= "Cube" then
local offset = roat * SubItems.Cube["roat"] * SubItems[key].cubedist
local pos_d = pos + offset
SubItems[key].item.SetPosition(pos_d)
SubItems[key].item.SetRotation(roat * Quaternion.Inverse(SubItems[key].cuberoat))
end
end
else
local pos = SubItems.Cylinder.item.GetPosition()
local roat = SubItems.Cylinder.item.GetRotation()
for key, value in pairs(SubItems) do
if key ~= "Cylinder" then
local offset = roat * SubItems.Cylinder["roat"] * SubItems[key].cylinderdist
local pos_d = pos + offset
SubItems[key].item.SetPosition(pos_d)
SubItems[key].item.SetRotation(roat * Quaternion.Inverse(SubItems[key].cylinderroat))
end
end
end
変数にまとめたので記述は短くてすむようになりました。
そして、ON/OFFの関数での拡大縮小も変数に格納したものを利用するように書き換えます。
function setON()
for key, value in pairs(SubItems) do
if key == "Cylinder" then
SubItems[key].item.SetLocalScale(Vector3.__new(0.001,0.001,0.001))
else
SubItems[key].item.SetLocalScale(SubItems[key].Scale)
end
end
end
function setOFF()
for key, value in pairs(SubItems) do
if key == "Cylinder" or key == "Sphere" then
SubItems[key].item.SetLocalScale(SubItems[key].Scale)
else
SubItems[key].item.SetLocalScale(Vector3.__new(0.001,0.001,0.001))
end
end
end
こちらも短くなりました。
② 装着しているときと持っているときで追従オブジェクトを切り替える
あとは、装着オブジェクトを装着しているときは、装着したオブジェクトを追従させ、CubeかCylinderを持っているときはそちらを追従するように切り替えるコードを書きます。
まず、CubeかCylinderを持っているとき、という状態を見る変数「grab」を作ります。
初期は掴んでないので、値はfalse
とします。
grab = false
そして、オブジェクトを掴んだタイミングで掴んだフラグをONにします。
CubeもしくはCylinderをみ始め(onGrab関数が発火する)たら、掴んだ状態(grab = true)。
function onGrab(subItemName)
if subItemName=="Cube" or subItemName=="Cylinder" then
grab = true
end
end
そして、CubeもしくはCylinderを掴み終え(onUnGrab関数が発火する)たら、掴んだ状態解除(grab = false)に切り替わる処理を書きます。
function onUngrab(subItemName)
if subItemName=="Cube" or subItemName=="Cylinder" then
grab = false
end
end
これでgrab
を見ると、掴んでいるかいないかわかるので、updateAllの処理に分岐を書きます。
grabがfalseの場合は、Sphere(装着オブジェクト)を追従するという記述です。
function updateAll()
if grab == false then
local pos = SubItems.Sphere.item.GetPosition()
local roat = SubItems.Sphere.item.GetRotation()
for key, value in pairs(SubItems) do
if key ~= "Sphere" then
local offset = roat * SubItems.Sphere["roat"] * SubItems[key].spheredist
local pos_d = pos + offset
SubItems[key].item.SetPosition(pos_d)
SubItems[key].item.SetRotation(roat * Quaternion.Inverse(SubItems[key].sphereroat))
end
end
else
最後のelseにCubeとCylinderの追従コードの記述をそのままくっつけて、これで完成です。
コードの全体は以下の通り。
SubItems = {
Cube = {item=vci.assets.GetTransform("Cube")},
Cylinder = {item=vci.assets.GetTransform("Cylinder")},
Sphere = {item=vci.assets.GetTransform("Sphere")},
slot1 = {item=vci.assets.GetTransform("slot1")},
slot2 = {item=vci.assets.GetTransform("slot2")},
slot3 = {item=vci.assets.GetTransform("slot3")},
slot4 = {item=vci.assets.GetTransform("slot4")},
slot5 = {item=vci.assets.GetTransform("slot5")},
slot6 = {item=vci.assets.GetTransform("slot6")},
slot7 = {item=vci.assets.GetTransform("slot7")},
slot8 = {item=vci.assets.GetTransform("slot8")},
select = {item=vci.assets.GetTransform("select")},
l_v = {item=vci.assets.GetTransform("l_v")}
}
for key, value in pairs(SubItems) do
if key ~= "Cube" then
SubItems[key].cubedist = SubItems[key].item.GetPosition() - SubItems.Cube.item.GetPosition()
SubItems[key].cuberoat = Quaternion.Inverse(SubItems[key].item.GetRotation()) * SubItems.Cube.item.GetRotation()
end
if key ~= "Cylinder" then
SubItems[key].cylinderdist = SubItems[key].item.GetPosition() - SubItems.Cylinder.item.GetPosition()
SubItems[key].cylinderroat = Quaternion.Inverse(SubItems[key].item.GetRotation()) * SubItems.Cylinder.item.GetRotation()
end
if key ~= "Sphere" then
SubItems[key].spheredist = SubItems[key].item.GetPosition() - SubItems.Sphere.item.GetPosition()
SubItems[key].sphereroat = Quaternion.Inverse(SubItems[key].item.GetRotation()) * SubItems.Sphere.item.GetRotation()
end
SubItems[key].Scale = SubItems[key].item.GetLocalScale()
end
SubItems.Cube["roat"] = Quaternion.Inverse(SubItems.Cube.item.GetRotation())
SubItems.Cylinder["roat"] = Quaternion.Inverse(SubItems.Cylinder.item.GetRotation())
SubItems.Sphere["roat"] = Quaternion.Inverse(SubItems.Sphere.item.GetRotation())
function setON()
for key, value in pairs(SubItems) do
if key == "Cylinder" then
SubItems[key].item.SetLocalScale(Vector3.__new(0.001,0.001,0.001))
else
SubItems[key].item.SetLocalScale(SubItems[key].Scale)
end
end
end
function setOFF()
for key, value in pairs(SubItems) do
if key == "Cylinder" or key == "Sphere" then
SubItems[key].item.SetLocalScale(SubItems[key].Scale)
else
SubItems[key].item.SetLocalScale(Vector3.__new(0.001,0.001,0.001))
end
end
end
mode = true
grab = false
setON()
function updateAll()
if grab == false then
local pos = SubItems.Sphere.item.GetPosition()
local roat = SubItems.Sphere.item.GetRotation()
for key, value in pairs(SubItems) do
if key ~= "Sphere" then
local offset = roat * SubItems.Sphere["roat"] * SubItems[key].spheredist
local pos_d = pos + offset
SubItems[key].item.SetPosition(pos_d)
SubItems[key].item.SetRotation(roat * Quaternion.Inverse(SubItems[key].sphereroat))
end
end
elseif mode then
local pos = SubItems.Cube.item.GetPosition()
local roat = SubItems.Cube.item.GetRotation()
for key, value in pairs(SubItems) do
if key ~= "Cube" then
local offset = roat * SubItems.Cube["roat"] * SubItems[key].cubedist
local pos_d = pos + offset
SubItems[key].item.SetPosition(pos_d)
SubItems[key].item.SetRotation(roat * Quaternion.Inverse(SubItems[key].cuberoat))
end
end
else
local pos = SubItems.Cylinder.item.GetPosition()
local roat = SubItems.Cylinder.item.GetRotation()
for key, value in pairs(SubItems) do
if key ~= "Cylinder" then
local offset = roat * SubItems.Cylinder["roat"] * SubItems[key].cylinderdist
local pos_d = pos + offset
SubItems[key].item.SetPosition(pos_d)
SubItems[key].item.SetRotation(roat * Quaternion.Inverse(SubItems[key].cylinderroat))
end
end
end
end
function onGrab(subItemName)
if subItemName=="Cube" or subItemName=="Cylinder" then
grab = true
end
end
function onUngrab(subItemName)
if subItemName=="Cube" or subItemName=="Cylinder" then
grab = false
end
end
function onUnuse(subItemName)
if subItemName == "l_v" and mode==true then
mode = false
setOFF()
elseif subItemName == "Cylinder" and mode==false then
mode = true
setON()
end
end
おわりに
今日までで、やっと情報表示板を持ち運び、そして手につけて追従させられるようになりました。
明日はやっと、もともとやりたかったアイテムの所有ということをこの情報表示版に実装していきます。