目次

重力無効バッジ

対応バージョンは、UniVCI v0.35以降です。

バッジを装着すると、球が出現し、球を操作すると空中を自由に移動操作できるVCIです。

サンプルデータ

https://virtualcast.jp/products/4c7c164b86988acd9986254cf967b9c0977fd7ee6b81c8f35f581c10cf178e77

Unitypackage

gameapi_floating.zip

コンポーネント設定

VCI Object

Sub Item 設定一覧 (クリックで展開)
VCI Sub Item : controller_root

VCI Sub Item : attach_sub
VCI Attchable (装着ボーンはHips)

VCIスクリプト

main.lua
local player =  vci.vc.room.GetLocalPlayer()
local playerController = player.GetRoomPlayerController() -- ローカルプレイヤー以外では nil が返る
local character = player.Character
 
local my_chest
 
local is_modeactive = false--ダミーの所有権を持っていてかつ装着されているか。これを有効状態のフラグにする
local is_pre_modeactive = false--ダミーの所有権を持っていてかつ装着されているか。これを有効状態のフラグにする
local is_controllergrabbing = false
local is_subgrabbing = false
 
local controller_root = vci.assets.GetTransform("controller_root")
local attach_sub = vci.assets.GetTransform("attach_sub")
local controller_model = vci.assets.GetTransform("controller_model")
--はじめにモデルは見えなくする
controller_model.SetActive(false)
 
local is_onoffswitch = false
 
 
 
-----制御関連
local initialYDiff = 0--基準リセットタイミングでのプレイヤー位置とコントローラの位置差分
 
local deltaAttachPos
local deltaAttachRot
local function toggleActivation()
    is_onoffswitch = not is_onoffswitch
end
 
--基準リセット
local function recordInitialTransform()
    initialYDiff = controller_root.GetPosition().y - player.GetPosition().y
end
 
local function resetInitialPos()
    deltaAttachPos = controller_root.GetPosition() - player.GetPosition() 
    local eular = player.GetRotation().eulerAngles
    deltaAttachRot = Quaternion.Inverse(Quaternion.Euler(0, eular.y, 0))
end
 
 
-- Playerに対する相対的なCubeの位置の差分を取得
--- @return Vector3
local function getRelativeControllerYDifference()
    local currentPlayerToController = controller_root.GetPosition() - player.GetPosition()
    return currentPlayerToController.y - initialYDiff 
end
 
 
local anitGravityCoef = -1
local moveCoef = 30
local breakCoef = 3
local breakThreshold = 0.1
 
--- @param force Vector3
--- @param forceMode string NOTE: ExportForceMode は現在比較可能でない
local function FireAddForce(force, forceMode)
    if forceMode == "Impulse" then
        playerController.AddForce(force, vci.forceMode.Impulse)
    elseif forceMode == "Force" then
        playerController.AddForce(force, vci.forceMode.Force)
    end
end
 
 
 
local function flyByController()
    if not is_modeactive then return end
    if not is_onoffswitch then return end 
 
    --local movedVector = getRelativeControllerYDifference()
    local movedY = getRelativeControllerYDifference()
 
    local anitGravity = anitGravityCoef * vci.vc.room.GetGravity() 
 
    local force = anitGravity
 
    force = force + Vector3.up * movedY * moveCoef
 
    -- 雑に逆向きの力をかけてスライドを止める
    -- SetVelocityは効かない
    local velocity = playerController.GetVelocity()
    if velocity.sqrMagnitude > breakThreshold * breakThreshold  then
        force = force -velocity * breakCoef
    end
 
 
    FireAddForce(force * playerController.GetMass(), "Force")
end
 
function Default_pop_pos()
    --コントローラ位置を自分の目の前に
    my_chest = character.GetBoneTransform("chest")
    if my_chest ~= nil then
        local pos = my_chest["position"] + player.GetForward()*0.5
        controller_root.SetPosition(pos)
        recordInitialTransform()
        resetInitialPos()
    end
end
 
 
function CheckModeActive()--modeONOFF判定
    is_pre_modeactive = is_modeactive--更新
    if attach_sub.IsMine == true then
        if attach_sub.IsAttached == true then
            is_modeactive = true
        else
            is_modeactive = false
        end
    else
        is_modeactive = false
    end
end
 
local function attach() --位置調整
    if is_controllergrabbing then return end --コントローラ掴み中は追従しない
    if is_modeactive == false  then return end --装着してないときは追従しない
    if is_pre_modeactive == false and is_modeactive == true  then return end --装着した瞬間のフレームは追従しない
 
    local rotation = Quaternion.LookRotation(controller_root.GetUp(), player.GetPosition() - controller_root.GetPosition())
    rotation = Quaternion.Euler(0, rotation.eulerAngles.y, 0)
 
    if deltaAttachRot ==nil then return end
    if deltaAttachPos ==nil then return end
    controller_root.SetPosition(player.GetPosition() + player.GetRotation() * deltaAttachRot * deltaAttachPos)
    controller_root.SetRotation(rotation)
end
 
 
 
function onUse(use)
    if use == "controller_root" then
        --基準リセット
        recordInitialTransform()
        resetInitialPos()
    end
    if use == "attach_sub" then
        toggleActivation()
    end
end
 
function onGrab(target)
    if target == "controller_root" then
        is_controllergrabbing = true
    elseif "atttach_sub" then
        is_subgrabbing = true
    end
    --かつ装着してない時基準リセット
    --Default_pop_pos()
 
end
function onUngrab(target)
    if target == "controller_root" then
        is_controllergrabbing = false
    elseif "atttach_sub" then
        is_subgrabbing = false
    end
end
 
function update()
    my_chest = character.GetBoneTransform("chest")
    if is_pre_modeactive ~= is_modeactive then
        --未装着状態から装着状態,またはその逆へと切り替わった時
        --基準位置のリセットを行う
        --コントローラ位置を自分の目の前に
        Default_pop_pos()
        --スイッチの状態も自動切り替え
        is_onoffswitch = is_modeactive
    elseif is_subgrabbing == true then
        Default_pop_pos()
    end
 
    --モデルの表示非表示切り替え
    if is_onoffswitch == true then
        controller_model.SetActive(true)
    else
        controller_model.SetActive(false)
    end
 
    CheckModeActive()
    flyByController()
    attach()
end