-------------------------------------------------------------- ---立体コメント落下VCI --- ---機能 ---わんコメプラグインより、画像URLがOSCにて送信されると、コメントの内容を立体コメントとして落下する --- ---機能詳細 --- ●本VCIはわんコメプラグイン(Ver.1.2.0以上)と連携して動作するVCIである --- ●自分自身のわんコメのOSCと、自身のVCIの組み合わせのみ動作する --- ●OSCにてコメント情報を受信すると立体コメントを落下させる --- ●落下させる立体コメントの寿命は15秒 --- ●立体コメントの色は、選択されたカラーパレットによって決まる --- ●プレーン君を操作することで、立体コメントの落下位置を調整することができる --- ●プレーン君の数値操作は、アイテムオーナーのみが可能 --- ●オーナー以外は、設定値(吹き出し)は非アクティブ --- ●1秒以上のUSEで、落下基準点の切り替え(「プレイヤー中心」と「スイッチ中心」) --- ●1秒未満のUSEで、落下位置操作切り替え(「範囲」と「オフセット」) --- ●プレーン君の拡縮操作で、「範囲」または「オフセット」の数値操作 --- ●上記の位置は、ローカルストリームカメラ、または、モニタ、の方向を向くような基準となる --- ●上記の向きの基準は、ローカルストリームカメラが出ている場合はそちらを基準に、出てない場合はモニタが基準となる --- ●設定吹き出しのパレットマークをUseすると、カラーパレットの選択画面のON/OFFが操作できる --- ●表示された選択画面の、カラーパレットをUseすると、そのカラーパレットを選択できる -------------------------------------------------------------- local displayModule = require("planeKunDisplay") local solidComment = require("SolidComment") local myId local ownerId local switchFlag = false local switchUseFlag = false local switchGrabFlag = false local switchUseStartTime = 0 local switchIntervalTime = 1 local dropRange = {"2.00","0.00","0.50"} local dropOffset = {"0.00","3.00","0.00"} local preScl = Vector3.one local switchFase = 1 local nxtState = {0,0,0} local switchCollider = vci.assets.GetTransform("ButtonRootCollider") local switch = vci.assets.GetTransform("ButtonRoot") local queueMax = 15 local queueOutInterval = 0.3 --キューチェックのインターバル local queueOutPreTime = 0 --前回のキューチェックの時間 local commentQueueTbl = {} --キューテーブル local heightOffset = 0 ---OSCアドレス local commonAdress = "/vc-official/onecomme/common" --- --------------------------------------------------------- --- OSC受信時の処理 --- --------------------------------------------------------- --- OSC受信データをバッファ用テーブルに保存する。 --- メッセージの流量を制限するため、バッファを設けている。 --- 保存時、設定した保存限界を超えたデータは、古いものから削除する。 --- @param content table @OSCからの取得データ local function commentDrop(content) if ownerId ~= nil then if ownerId == myId then local oscData = json.parse(content) --文字数制限処理 if #oscData.comment > 15 then oscData.comment = oscData.comment:sub(1, 15) end table.insert(commentQueueTbl, oscData.comment) --キューに貯まりすぎないよう、上限を超えたら古いコメントを削除 while #commentQueueTbl > queueMax do table.remove(commentQueueTbl, 1) print("キュー上限を超えたので、キュー内の古いコメントを削除しました") end end end end vci.osc.RegisterMethod(commonAdress, commentDrop, {ExportOscType.BlobAsUtf8}) --- キューから、立体コメントを生成する処理 local function outputFromQueue() if #commentQueueTbl ~= 0 and os.time() - queueOutPreTime > queueOutInterval then local spawnPos = switch.GetPosition() --スイッチがオーナー基準の場合、オーナーの位置を取得 if not(switchFlag) then spawnPos = vci.vc.room.GetLocalPlayer().GetPosition() end --ランダム化の位置設定 local randomPos = Vector3.__new( (math.random()-0.5)*2*dropRange[1] + dropOffset[1], (math.random()-0.5)*2*dropRange[2] + dropOffset[2], (math.random()-0.5)*2*dropRange[3] + dropOffset[3] ) --基準向きの取得 local spawnRot = Quaternion.identity --ローカルストリームカメラの有無のチェック local camera = vci.vc.room.streamCamera.GetLocalStreamCameraByPlayerId(ownerId) local monitor = vci.vc.room.monitorCamera if camera.IsAvailable() then local tempRot = camera.GetRotation().eulerAngles tempRot.x = 0 tempRot.z = 0 spawnRot = Quaternion.Euler(tempRot)*Quaternion.Euler(0,180,0) elseif monitor.GetRotation() ~= nil then local tempRot = monitor.GetRotation().eulerAngles tempRot.x = 0 tempRot.z = 0 spawnRot = Quaternion.Euler(tempRot)*Quaternion.Euler(0,180,0) end --コメント落下位置の、カメラの向き基準でのランダム化処理 spawnPos = spawnPos + spawnRot*randomPos --コメントのスケールのランダム設定 local solidScl = 0.2*(math.random()-0.5) + 0.35 --コメントの生成処理 solidComment.commentDrop(spawnPos, spawnRot, solidScl, commentQueueTbl[1]) --生成したコメントの、キューからの削除 table.remove(commentQueueTbl, 1) queueOutPreTime = os.time() end end ------------------------------------------------------------ ---Initialize処理 ------------------------------------------------------------ --- スタジオでは、オブジェクトを非アクティブに local function initialize() --ルームの識別 if vci.vc.GetSpaceType() == ExportVcSpaceType.Studio then vci.assets.GetTransform("/ButtonRoot/FukidashiObj").SetActive(false) vci.assets.GetTransform("Yajirushi").SetActive(false) vci.assets.GetTransform("planekun").GetSkinnedMeshRenderer().SetBlendShapeWeight(7, 100) --パレットオブジェクトの非アクティブ化 solidComment.inactive() elseif vci.vc.GetSpaceType() == ExportVcSpaceType.Room then myId = vci.vc.room.GetLocalPlayer().GetId() --パレットオブジェクトの非アクティブ化 solidComment.inactive() if vci.assets.IsMine then if vci.state.Get("OwnerID") == nil then --stateの初期化処理 vci.state.Set("OwnerID", myId) vci.state.Set("Range", dropRange) vci.state.Set("Offset", dropOffset) vci.state.Set("Switch", false) displayModule.textUpdate(switchFase, switchFlag, true) ownerId = myId --カラーパレット用のスイッチのアクティブ化 solidComment.paletteSwitchActive(true) elseif vci.state.Get("OwnerID") == myId then switchFlag = vci.state.Get("Switch") dropRange = vci.state.Get("Range") dropOffset = vci.state.Get("Offset") displayModule.textUpdate(switchFase, switchFlag, true) ownerId = myId --カラーパレット用のスイッチのアクティブ化 solidComment.paletteSwitchActive(true) --カラーパレットの番号の読み出し処理 solidComment.readState() else vci.assets.GetTransform("/ButtonRoot/FukidashiObj").SetActive(false) vci.assets.GetTransform("Yajirushi").SetActive(false) end else vci.assets.GetTransform("/ButtonRoot/FukidashiObj").SetActive(false) vci.assets.GetTransform("Yajirushi").SetActive(false) end --プレーン君の表情切り替え vci.assets.GetTransform("planekun").GetSkinnedMeshRenderer().SetBlendShapeWeight(0, 100) end end initialize() function updateAll() --スイッチのコライダーの追従処理 if switchCollider.IsMine then switch.SetPosition(switchCollider.GetPosition()) switch.SetRotation(switchCollider.GetRotation()) end --スイッチ操作 if ownerId == myId then outputFromQueue() if switchGrabFlag then nxtState = displayModule.textUpdateGrabbing(switchFase, preScl) end end solidComment.updateAll() end function onGrab(item) if ownerId ~= nil then --プレーン君の操作 if item == "ButtonRootCollider" and ownerId == myId then switchGrabFlag = true --数値操作用のスケールの用意 preScl = { switchCollider.GetLocalScale().x, switchCollider.GetLocalScale().y, switchCollider.GetLocalScale().z } end end end function onUngrab(item) if ownerId ~= nil then --プレーン君の操作 if item == "ButtonRootCollider" and ownerId == myId then switchGrabFlag = false --数値操作用のコライダーリセット switchCollider.SetLocalScale(Vector3.one) --範囲・オフセットの上書き処理 if switchFase == 1 then dropRange = nxtState vci.state.Set("Range", dropRange) vci.message.EmitToSelf("ThumbnailDropRangeSend", dropRange) else dropOffset = nxtState vci.state.Set("Offset", dropOffset) vci.message.EmitToSelf("ThumbnailDropOffsetSend", dropOffset) end end end end function onUse(use) if ownerId ~= nil then --プレーン君の操作 --長押し・短押しの判定用のカウント開始 if use == "ButtonRootCollider" and ownerId == myId then if not(switchUseFlag) then switchUseFlag = true switchUseStartTime = os.time() end end solidComment.onUse(use) end end function onUnuse(use) if ownerId ~= nil then --プレーン君の操作 --1秒以上「USE」長押し:基準の切り替え --1秒未満「USE」:範囲とオフセットの切り替え if use == "ButtonRootCollider" and ownerId == myId then if switchUseFlag and os.time() - switchUseStartTime >= switchIntervalTime then switchFlag = not(switchFlag) if switchFlag then heightOffset = switch.GetPosition().y - vci.vc.room.GetLocalPlayer().GetPosition().y if heightOffset < 0 then heightOffset = 0 end end dropOffset[2] = displayModule.baseSwitchHeightAdjust(switchFlag, switchFase, heightOffset) vci.state.Set("Offset", dropOffset) vci.state.Set("Switch", switchFlag) vci.message.EmitToSelf("ThumbnailSwitchChange", {switchFlag, dropOffset}) displayModule.textUpdate(switchFase, switchFlag, false) else if switchFase == 1 then switchFase = 2 else switchFase = 1 end displayModule.textUpdate(switchFase, switchFlag, false) end switchUseFlag = false end end end function onTriggerEnter(item, collider) if ownerId ~= nil then solidComment.onTriggerEnter(item, collider) end end function onTriggerExit(item, collider) if ownerId ~= nil then solidComment.onTriggerExit(item, collider) end end