目次

アンケートVCI(わんコメ対応)

VirtualCast公式わんコメOSCプラグインでYouTube・ニコニコ生放送のコメントを受信してアクションを起こすVCIのサンプルです。


サンプルデータ

https://virtualcast.jp/products/a44c9225543e9a4ac63ec0171d5310f2566ab631710c3131cf70a82dea0608aa

Unitypackage

questionnairevci.unitypackage

コンポーネント設定

VCI Object

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

VCI Sub Item : SwitchCollider

VCIスクリプト

main.lua
local roomFlag
local voteTbl = {}              --投票を行った人のIDを管理するTbl
local textZeroPos = 0.37        --0票の際のテキストのゼロ位置
local textSlide = -0.01         --1票入った際のテキストのスライド量
local barZeroScl = 0.006        --0票の際のバーのスケール量(チラリと見える量)
local boradSclSide = 0.00057    --100票を超えた際のボードの拡大量
 
local board = vci.assets.GetTransform("BoardDummy")
local bar = {}
local voteText = {}
for i = 1, 4 do
    bar[i] = vci.assets.GetTransform("BarDummy"..i)
    voteText[i] = vci.assets.GetTransform("VoteText"..i)
end
local switch = vci.assets.GetTransform("Switch")
local switchCollider = vci.assets.GetTransform("SwitchCollider")
local switchFlag = false
 
local voteKey = {"#1","#2","#3","#4"}
 
--四捨五入
--digit:四捨五入する桁数。
--10の位までを有効数字として四捨五入する場合は、1
--1の位までを有効数字として四捨五入する場合は、0
--0.1の位までを有効数字として四捨五入する場合は、-1
local function shiShaGoNyu(num, digit)
    num = num + 0.5*10^digit
    local reNum = math.floor(num/10^digit)*10^digit
    return reNum
end
 
 
local youtubeAdress1 = "/vc-official/onecomme/youtube/comment"
local youtubeAdress2 = "/vc-official/onecomme/youtube/super"
local niconicoAdress1 = "/vc-official/onecomme/niconico/comment"
local niconicoAdress2 = "/vc-official/onecomme/niconico/gift"
 
-----------------------------------------------
--わんコメプラグインを利用したアンケートシステム
--わんコメで投票キーを受け取った場合、コメント内の先頭に近いキーを集計する
--一度投票したら、次の回答は無効(次のアンケートが始まるまで)
--VCIのオーナーが代表して処理
-----------------------------------------------
local function wankomeVote(content)
    if roomFlag then
        if switchFlag and vci.state.Get("OwnerID") == vci.vc.room.GetLocalPlayer().GetId() then
            --すでに回答しているかどうかのチェック
            local voteCheck = true
            local oscData = json.parse(content)
            for i = 1, #voteTbl do
                if oscData.userId == voteTbl[i] then
                    voteCheck = false
                end
            end
            if voteCheck then
                --コメントに含まれる投票キーチェック
                local tbl = {}
                for i = 1, 4 do
                    if string.find(oscData.comment, voteKey[i]) ~= nil then
                        table.insert(tbl, {i, string.find(oscData.comment, voteKey[i])})
                    end
                end
                --一番先頭に近い投票キー以外を除外
                while #tbl >= 2 do
                    if tbl[1][2] <= tbl[2][2] then
                        table.remove(tbl, 2)
                    else
                        table.remove(tbl, 1)
                    end
                end
                --有効票があれば、投票加算処理
                if #tbl ~= 0 then
                    if vci.state.Get("VoteResult"..tbl[1][1]) ~= nil and vci.state.Get("VoteResultSum") ~= nil then
                        local pre = vci.state.Get("VoteResult"..tbl[1][1])
                        vci.state.Set("VoteResult"..tbl[1][1], pre+1)
                        local sum = vci.state.Get("VoteResultSum")
                        vci.state.Set("VoteResultSum", sum+1)
                        table.insert(voteTbl, oscData.userId)
                    end
                end
            end
        end
    end
end
vci.osc.RegisterMethod(youtubeAdress1, wankomeVote, {ExportOscType.BlobAsUtf8})
vci.osc.RegisterMethod(youtubeAdress2, wankomeVote, {ExportOscType.BlobAsUtf8})
vci.osc.RegisterMethod(niconicoAdress1, wankomeVote, {ExportOscType.BlobAsUtf8})
--vci.osc.RegisterMethod(niconicoAdress2, wankomeHakushu, {ExportOscType.BlobAsUtf8})
 
 
--わんコメから集計されたアンケートデータのグラフ表示処理
local function graphUpdate()
    local boardSclSideMax = 100
    if vci.state.Get("VoteResultSum", 0) ~= nil then
        for i = 1, 4 do
            if vci.state.Get("VoteResult"..i) ~= nil then
                local var = vci.state.Get("VoteResult"..i)
                if var == nil then
                    var = 0
                end
                --棒の更新
                --0票の際は、少し棒が見えるように別個のスケールを適用
                if var == 0 then
                    bar[i].SetLocalScale(Vector3.__new(barZeroScl, 1, 1))
                else
                    bar[i].SetLocalScale(Vector3.__new(var*0.01, 1, 1))
                end
                --テキスト位置の更新
                voteText[i].SetLocalPosition(Vector3.__new(textZeroPos + textSlide*var, 0.27-0.18*(i-1), 0.003))
                if boardSclSideMax < var then
                    boardSclSideMax = var
                end
                --テキスト文章の更新
                local text1 = vci.state.Get("VoteResult"..i)/vci.state.Get("VoteResultSum")*100
                text1 = tostring(shiShaGoNyu(text1, -1))
                if #text1 <= 2 then
                    text1 = text1..".0"
                end
                if vci.state.Get("VoteResultSum") == 0 then
                    vci.assets.SetText("VoteText"..i, "("..vci.state.Get("VoteResult"..i).."票)")
                else
                    vci.assets.SetText("VoteText"..i, text1.."%<br>("..vci.state.Get("VoteResult"..i).."票)")
                end
            end
        end     
    end
    --100票を超える棒がある場合、グラフ用紙も伸ばす
    if boardSclSideMax <= 100 then
        board.SetLocalScale(Vector3.one*0.1)
    else
        board.SetLocalScale(Vector3.__new(0.1+(boardSclSideMax-100)*boradSclSide, 0.1, 0.1))
    end
end
 
--スイッチコライダーの追従処理
local function swColliderTransform()
    if switchCollider.IsMine then
        switchCollider.SetPosition(switch.GetPosition())
        switchCollider.SetRotation(switch.GetRotation())
        switchCollider.SetLocalScale(vci.assets.GetTransform("Questionnaire").GetLocalScale()*0.02)
    end
end
 
 
--投票受付、投票終了のテキスト更新処理
--投票受付開始の際には、投票を管理するVCIオーナーで、投票結果の初期化を行う。
local function voteSwitchTextUpdate()
    if vci.state.Get("SwitchState") ~= nil then
        if vci.state.Get("SwitchState") ~= switchFlag then
            if not(switchFlag) then
                vci.assets.SetText("SwitchText", "投票<br>終了")
                if vci.state.Get("OwnerID") == vci.vc.room.GetLocalPlayer().GetId() then
                    voteTbl = {}
                    for i = 1, 4 do
                        vci.state.Set("VoteResult"..i, 0)
                    end
                    vci.state.Set("VoteResultSum", 0)
                end
            else
                vci.assets.SetText("SwitchText", "投票<br>受付")
            end
            switchFlag = vci.state.Get("SwitchState")
        end
    end
end
 
 
 
--初期化処理
--stateの初期化
local function initialize()
    --ルーム識別処理
    --本VCIはルーム以外では動作しない
    if vci.vc.GetSpaceType() == ExportVcSpaceType.studio then
        roomFlag = false
    else
        roomFlag = true
    end
    if roomFlag and vci.assets.IsMine then
        if vci.state.Get("OwnerID") == nil then
            vci.state.Set("OwnerID", vci.vc.room.GetLocalPlayer().GetId())
            vci.state.Set("SwitchState", false)
            for i = 1, 4 do
                vci.state.Set("VoteResult"..i, 0)
            end
            vci.state.Set("VoteResultSum", 0)
        elseif vci.state.Get("OwnerID") == vci.vc.room.GetLocalPlayer().GetId() then
            vci.state.Set("SwitchState", false)
            for i = 1, 4 do
                vci.state.Set("VoteResult"..i, 0)
            end
            vci.state.Set("VoteResultSum", 0)
        end
    end
end
initialize()
 
function updateAll()
    --グラフの表示処理
    graphUpdate()
 
    --スイッチコライダーの追従処理
    swColliderTransform()
 
    --投票受付、投票終了のテキスト更新処理
    voteSwitchTextUpdate()
end
 
function onUse(use)
    if use == "SwitchCollider" then
        if vci.state.Get("SwitchState") ~= nil then
            local tempFlag = vci.state.Get("SwitchState")
            vci.state.Set("SwitchState", not(tempFlag))
        end
    end
end