目次

ふわふわパラソル

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

手か頭に装着して高所から飛び降りると、ふわふわ降下できるVCIです。
Useすると開閉します。

サンプルデータ

https://virtualcast.jp/products/946bba6a5e1025c79a10e2c34ee9ab0666b9bc71deae6d1fd35495f717cd825f

Unitypackage

gameapi_parasol.zip

コンポーネント設定

VCI Object

Sub Item 設定一覧 (クリックで展開)
VCI Sub Item : Parasol
VCI Attchable (装着ボーンはLeftHand, RightHand, Head)

VCIスクリプト

main.lua
-- ローカルプレイヤー取得
local localPlayer = vci.vc.room.GetLocalPlayer()
 
-- 重力
local gravity = Vector3.Magnitude(vci.vc.room.GetGravity())
 
-- ローカルプレイヤーのみ取得可能
local playerController = localPlayer.GetRoomPlayerController() 
 
-- 持つところ
local handle = vci.assets.GetTransform("Parasol")
local openPart = vci.assets.GetTransform("Palasol_Open")
local closePart = vci.assets.GetTransform("Parasol_Close")
 
 
local fallStartedY = 0
local grounded = false
local prevTime = os.time()
 
local isGrabbed = false
local isOpen = false
 
 
function change_parasol_state(sender, name, message)
    if message == true then
        open(true)
    else 
        close(true)
    end    
end
 
vci.message.On("change_parasol_state", change_parasol_state)
 
function open(useSfx)
    isOpen = true
    openPart.SetActive(true)
    closePart.SetActive(false)
    if useSfx then
        -- 効果音がある場合はここで再生
        -- vci.assets.PlayAudioFromName("OpenParasol")
    end
end
 
function close(useSfx)
    isOpen = false
    openPart.SetActive(false)
    closePart.SetActive(true)
    if useSfx then
        -- 効果音がある場合はここで再生
        -- vci.assets.PlayAudioFromName("CloseParasol")
    end
end
 
-- 初期化処理
if vci.assets.IsMine then 
    -- 初期化時に所有権があるなら、傘を閉じて初期化
    vci.state.Set('is_open', 0) 
    close(false)
else
    -- 所有権を持ってない場合は、今の状態に追従して初期化
    if vci.state.Get('is_open') == 1 then
        open(false)
    else
        close(false)
    end
end
 
 
function updateAll()
 
    local time = os.time()
    local deltaTime = time - prevTime;
    prevTime = time
 
    local currentV = playerController.GetVelocity()
    local mass = playerController.GetMass()
 
    -- 所有権があり、持ってるか手にくっついてるときのみ動作
    if handle.IsMine == false then
        return 
    end
 
    if handle.IsAttached == false and isGrabbed == false then
        return
    end
 
    -- 傘を閉じているなら何もしない
    if isOpen == false then
        return
    end
 
    -- 地面から離れたらセットアップ
    if grounded == true and playerController.IsGrounded() == false then
        initalize()
    end
 
    grounded = playerController.IsGrounded()
 
    -- 地面についたら終了
    if grounded == true then return end
 
    -- ひっくり返してるなら何もしない
    if Vector3.Dot(Vector3.down, handle.GetUp()) > 0 then
        return
    end
 
    -- 上に向かって飛んでる時は何もしない
    if currentV.y > 0 then return end
 
    local y = localPlayer.GetPosition().y
 
    local deltaY = fallStartedY - y
 
    -- 現在位置よりも上昇したら再計算
    if deltaY < 0 then 
        initalize()
        return
    end
 
    -- 落下開始地点を徐々に現在の位置に追従させる
    fallStartedY = lerp(fallStartedY, y, 5.0 * deltaTime )
 
    -- 落下した分を速度に変換する(グライダーと同じロジック)
    local next = handle.GetUp().normalized * math.sqrt(2.0 * gravity * deltaY)
 
    -- 速度の更新にlerpを挟んでふわふわ感を出す
    next = Vector3.lerp(currentV, next, 8 * deltaTime)
 
    -- SetVelocityだと水平移動が上書きされてしまうため、AddForceで速度を上書きすることで水平移動もできるようにする
    -- F = m * a =  m * (v / s)
    playerController.AddForce(mass * (next - currentV) * (1.0/deltaTime), vci.forceMode.Force)
end
 
function onGrab(target)
    if target == "Parasol" then
        isGrabbed=true
    end
end
 
function onUngrab(target)
    if target == "Parasol" then
        isGrabbed = false
    end
end
 
function onUse(use)
    if use == "Parasol" then
        if isOpen == true then
            vci.message.EmitWithId("change_parasol_state",false,vci.assets.GetInstanceId())
            vci.state.Set('is_open', 0) 
        else
            vci.message.EmitWithId("change_parasol_state",true,vci.assets.GetInstanceId())
            vci.state.Set('is_open', 1) 
        end
    end
end
 
 
function initalize()
    -- 落下開始地点
    fallStartedY = localPlayer.GetPosition().y
end
 
 
function lerp(a,b,t)
    return a + ( b - a ) * clamp01(t)
end
 
function clamp01(x)
    if x < 0 then
        return 0
    end
    if x > 1 then
        return 1
    end
    return x
end