This document is about: FUSION 1
SWITCH TO

Fusion VR Escape Room

Level 4
Available in the Gaming Circle and Industries Circle
Circle
Fusion VR Escape Room範例目前只限訂閱Photon遊戲圈Photon行業圈的使用者可以使用。

您的遊戲圈會員資格提供所有所需的範例、SDK及支援,以在非常快速的時間內建立及啟動成功的多重玩家遊戲。對於非遊戲,我們的行業圈提供您完整的套件加上獨家的授權選項。

概述

Escape Room 範例展示了一個方法,說明如何在玩家及環境之間開發 物理互動
核心 提供了基礎的互動及移動,同時 選用的模組 提供額外的功能及互動類型作為範例執行方式。
所有模組都有它們自己的資料夾,並且如果不需要的話可以移除。請注意,在這個範例中提供的主要場景(/Scenes/EscapeRoom Full.scene)使用了所有模組及元件,並且在刪除模組時它可能中斷。
在這份文檔的結尾單獨地說明模組。

模組:

  • 物件提取
  • 拍立得
  • 白板
  • 觀察器
  • UI模組
  • 槽模組
  • 射擊模組
Fusion Escape Room Overview

技術資訊

  • 這個範例使用 伺服器/託管模式 拓撲,
  • 專案已用Unity 2020.3.37f1開發,

在您開始之前

為了運行範例:

  • PhotonEngine儀表板中建立一個Fusion應用程式帳號,並且將它貼上到即時設定(可從Fusion選單中到達)中的App Id Fusion欄位之中。

  • PhotonEngine儀表板中建立一個Voice應用程式帳號,並且將它貼上到即時設定中的App Id Voice欄位之中。

  • 然後載入Start場景並且按下Play。然後,您可以啟動完整的場景或只測試一個特定的模組。

下載

版本 發佈日期 下載
1.1.3 2022年10月20日 Fusion VR密室逃脫1.1.3組建5

處理輸入

中繼任務

  • 傳送:按下A或X按鈕,以顯示一個指標。在釋放時,您將傳送到任何已接受的目標
  • 觸碰:簡單地將您的手/手指放到一個按鈕上以切換它
  • 拿取:首先將您的手放在物件上,並且使用控制器拿取按鈕來拿取它
  • 使用:按下選擇按鈕以使用已拿取的物件

請注意,應該支援HTC Vive控制器及Valve Index控制器。

桌面

鍵盤

  • 行走:WASD
  • 上/下:空白鍵和左Shift

滑鼠

  • 旋轉:持續按下滑鼠右鍵並且移動滑鼠,以旋轉檢視點
  • UI:使用左鍵以按下一個UI按鈕
  • 拿取及使用(3D筆):將滑鼠放在物件上,並且使用滑鼠左鍵來拿取它。然後您可以使用鍵盤空白鍵來使用它

核心

範例的核心提供基於物理的與RigidbodiesArticulation bodies的互動。
剛體用於在世界中的任何可拋擲的物件,同時Articulation Bodies用於機械式系統如槓桿、轉盤、門及抽屜。
相機不是基於物理,而是只基於使用者輸入。已包含傳送移動(TeleportHandler.cs)

互動工作流程概述:

  • 輪詢及發送輸入:
    • (XRInput.csLocalController.csPCInput.cs)
  • 使用剛體及力量,基於輸入來更新頭及手位置:
    • (PlayerSystem.csXRObject.cs)
  • 手讀取輸入並且傳送它到手工具及任何IControllerInputReceiver
    • (Hand.csIControllerInputReceiver)
  • 手工具及其他元件回應輸入:
    • (HandTool.csTeleportHandler.csInstantCameraInteractable.cs)
  • 手工具檢查一個熱點是否在範圍之內,並且基於輸入來拿取/放開:
    • (HotspotCollector.csHotspot.csHighlightBase.cs)
  • 當開始/停止一個互動時,熱點告知可互動基礎及所有可互動物:
    • (InteractableBase.csGrabbableBase.cs)
  • 可拿取基礎使用力量來追蹤手位置:
    • (GrabbableBase.csGrabbableRigidbody.csGrabbableArticulation.cs)

輸入:

發送輸入

LocalInputBase.cs

它獨立於Fusion而作為一個DontDestroyOnLoad物件存在,並且在遊戲階段之間持續存在。負責收集輸入並且發送它到Runner

  • 這個的主要執行方式是XRInput
  • PCInput是一個針對更快速的迭代的偵錯輸入方法,但只有有限的功能。

接收輸入

PlayerSystem.cs

它透過XRObject.cs來處理基本的玩家物件的定位(頭及手)。
XRObject更新剛體力量以追蹤輸入。

Hand.cs

它讀取控制器輸入並且傳送其到任何已註冊的東西,以便透過IControllerInputReceiver來接受輸入
它針對基本的互動來明確傳送輸入到HandTool.cs

  • 希望接收輸入的系統可以執行IControllerInputReceiver並且透過手來註冊(比如TeleportHandler.cs
  • 已拿取物件可以暫時註冊(比如InstantCameraInteractable.cs) -> Hand.AddInputBehaviour() / Hand.RemoveInputBehaviour()

互動

手工具:

  • 針對拿取/放下來讀取輸入
  • 使用HotspotCollector以找到Hotspots並且強調顯示它們
  • 拿取/放下Hotspots

熱點收集器:

  • 基於圖層及標籤來尋找半徑之內的Hotspots
  • 篩選器順序:Layer, Tag, HighlightPriority, Distance
  • 強調顯示被懸停的熱點(HotspotCollector -> Hotspot -> HighlightBase)

熱點:

它代表互動點,HandTools可以透過它與物件互動。

  • 每個熱點一隻手,如果一個物件需要可被多隻手拿取,請新增更多熱點。如果需要的話,這些熱點可以相同。
  • 傳送開始/停止互動調用到在相同遊戲物件上的IInteractable以及上層中的InteractableBase

可互動基礎:

針對可互動物件的基礎層級。

  • 取得開始/停止互動調用
針對可拿取物件的物件層級:
  • RootInteractableBase, Rigidbody, NetworkRigidbody, Highlight, NetworkObject, BodyProperties
    • Visuals
      • Highlight Visuals
    • Collision
    • HotspotHotspot, GrabbableRigidbody / AttachmentRigidbody, Collider (Trigger)

主體屬性

指派一個BodyPropertyCollection(可指令碼物件)以控制物件被拿取時的行為方式。

主體屬性集合

它含有BodyPropertyData的一個陣列,其取決於在同一時間有多少手拿取物件(0:沒有拿取,1:一隻手拿取,n:n隻手拿取),來應用於已拿取物。
在這個方式下,物件可以安排成,對於一隻手而言太大或太重,但是對於兩隻手或多隻手而言很容易處理。

  • BodyPropertyData:
    • Mass
    • Drag
    • AngularDrag
    • JointFrictionArticulation(只適用於Articulation bodies
    • UseGravity
    • OverrideInertia(如果設定,慣性將被設定為InertiaWhenGrabbedScale * Vector3.one
    • InertiaWhenGrabbedScale(控制物件抵抗旋轉改變的程度)
    • VelocityExtrapolation(當向物件施加新的力量時,目前的速度被抵消的程度,也作為力量本身的乘數)
    • TorqueExtrapolation(當向物件施加新的力量時,目前的角速度被抵消的程度)

可拿取基礎(在熱點上):

當拿取物件時,它將物件追蹤到手的位置。

根據主體類型,來選擇適當的執行方式:

  • GrabbableRigidbody
  • GrabbableArticulation

附加剛體(在熱點遊戲物件上):

附加剛體物件到一個HandTool。這用於需要非常快速的輕量物件。(比如白板筆、拍立得照片、手槍)
為了讓這個順利工作,物件需要一個特定的架構:

  • Root
    • Visuals
    • Collision/Logic
      • Colliders
      • Hotspot: AttachmentRigidbody, Trigger Collider

在拿取時,CollisionVisuals GameObjects被直接地附加到Hand,並且如同它們是它的一部分一樣。

聚焦點

視覺效果確認,一個可互動對象在手的範圍之內,並且可以與之互動。

值提供器/讀取器

一個value provider是一個一般性元件,以將資訊從一個系統傳輸到另一個系統,並且在沒有專用元件的情況下建立簡單的邏輯鏈。

示例:

  1. 從一個連接主體來讀取一個值(ArticulationBodyValueReaderFloat.cs)
  2. 將它和一個閾值比較(ValueLogicIntCompare.cs)
  3. 使用該值以驅動其他東西(ArticulationBodyDriverSetLimits.cs)

串流材質管理器

針對模組所需。系統使用OnReliableData回調來透過網路來發送材質資料。需要與Runner位於同一個遊戲物件上。

忽略碰撞

有時候需要在特定物件之間使用Physics.IgnoreCollision API來忽略碰撞。

  • IgnoreCollision.cs:靜態忽略。在遊戲遊玩時不會改變。附有指令碼的遊戲物件上的碰撞器忽略所有清單中的碰撞器。
  • NetworkColliderCollection.cs:可以忽略的碰撞器的群組。
  • NetworkIgnoreCollision.cs:使用AddIgnore()RemoveIgnore()以忽略針對所有已指派的NetworkColliderCollections的本機碰撞器。

連接主體

這個範例大量使用Articulation bodies。它們是一個穩定的方法來在Unity中模擬已連線主體,並且在這裡用於槓桿、按鈕、轉盤及抽屜之類的東西。
NetworkArticulationBody的執行方式在這個範例中不是完整的功能。
請參照https://docs.unity3d.com/2020.3/Documentation/ScriptReference/ArticulationBody.html

核心元件

  • NetworkArticulationBodyRoot放置於Root
  • NetworkArticulationBody放置於所有下層Articulation bodies上。
    • NetworkedArticulationDriveArticulation body的驅動屬性連線。
    • ArticulationBodyValueReaderSingleAxis可以讀取將在值提供器系統中使用的一個Articulation body的值。
    • ArticulationBodySingleAxisSoftSnap動態地設定驅動屬性以貼齊到特定點。比如:轉盤上的凹口、抽屜上的緩衝關閉、槓桿上的固定有效位置。

本機內插補點

NetworkArticulationBody繼承於NetworkTransform並且提供一個穩定的本機內插補點。為了讓這個工作如預期進行,需要設定Interpolation targets,並且必須鏡像Articulation bodies的階層。

架構

  • RootNetworkObject, ArticulationBody, NetworkArticulationBodyRoot, InteractableBase
    • Visuals:跟隨相同於Articulation system的階層。
    • ChildArticulationBody, NetworkArticulationBody,(選擇性:BodyProperties* ArticulationBodySoftSnap, ArticulationBodyValueReaderSingleAxis
      • Child:(選擇性,與上述相同的元件)
        • HotspotHotspot, Trigger Collider, GrabbableArticulation

Hotspot之下至少需要BodyProperties元件一次。各個Hotspot將在其上層中搜尋第一個。

連接一個連接主體到一個剛體

如果一個Articulation需要被附加到一個rigidbody,它需要透過一個Joint(比如一個ConfigurableJoint)來完成。

已知問題

  • 請勿使用Articulation bodies上的Compute Parent Anchor:當客戶端不是在初始狀態時,它們將在客戶端上有所不同。
  • Articulation bodies中的錯誤導致對於連接階層的不同的索引。我們需要它們在客戶端之間保持一致,以適當地同步它們。在NetworkArticulationBodyRoot.Spawned()中執行暫時性修復。這個將重新排序它們為正確的順序。
    • 這個「駭客修復」遺憾地中斷連接任何在rigidbodiesarticulation bodies之間可設定的接點(比如射擊模組中的手槍)。因此針對這個物件,停用重新排序。

模組

物件拉取

按住拿取按鈕,指向物件並向上輕彈手,以將物件拉向您。

要求:

  • HandTool上的ObjectPullCollector預製件
  • 在一個Hotspot上的ObjectPullBody元件,也需要一個GrabbableBase元件(GrabbableRigidbody)

拍立得

拍立得顯示了更複雜的可互動物件(額外輸入)以及OnReliableData回調,以透過網路發送更大的資料。

  • InstantCameraInteractable:透過擷取相機轉譯材質來拍照。針對該材質來繁衍一個列印成品。
  • InstantCameraPrintout:等待材質到達,直到它使用一個著色器淡出。此外,它被重新發送給在一開始拍照之後加入的客戶端。
  • InstantCameraPicture.shader:簡單的表面著色器,以在接收照片之後淡出照片

白板

可在上面繪畫的白板。

  • WhiteboardSurface:可在上面繪畫的表面。將其目前的狀態儲存為一個Rendertexture
  • WhiteboardMarker:可互動物。查看表面(邊界)並且告知其在關閉時畫一個筆劃。

著色器

  • WhiteboardFill:以一個給定的材質來初始化白板
  • WhiteboardStroke:在轉譯材質上畫一條直線
  • WhiteboardStrokeEraser:在轉譯材質上擦除出一條直線

觀察器

滑鼠/鍵盤控制器,以觀察VR玩家及與世界互動。

要求:

  • 觀察器使用一個不同的輸入裝置及玩家預製件(請參見StartModulebutton.cs
  • 新增IObserverable元件到您希望操控的物件
    • ObserverableGrabRigidbody以拖動剛體
    • ObservableArticulationBodyButton新增一個持續的力量(可以被切換)
    • ObservableArticulationBodyDrawer新增一個在一段時間內持續的力量並且保持布林值狀態(當再次被按下時翻轉力量)
    • ObservableArticulationBodyLever在按住時新增一個力量
    • ObservableValueProviderOverride直接地設定浮點值(透過覆寫切換)。必須被插入到邏輯鏈之中,以產生一個效果。

將使用CreateObserverUi()來針對所有IObserverable元件自動地建立浮動UI視窗。在這裡可以執行自訂UI。在UI_ObserverItem預製件中定義預設元件。

觀察器輸入

可觀察物件的操控直接地被作為輸入來發送。(請參見ObserverInput / ObserverInputHandler.cs
輸入的組成包含:

  • NetworkBehaviourId以識別被修改的元件。
  • Value(目前只有浮點、布林值及向量3)

UI模組

基本的已連線游標及UI互動。它使用Unity的「已追蹤裝置射線投射器」及「輸入系統UI輸入模組」以在本機註冊畫布互動並且發送其為輸入。
為與PC裝置使用,也需要呈現「圖形射線投射器」。

  • LocalController.OnInputUi()

    • 儲存被指向的畫布到InputDataController.CanvasBehaviour (NetworkBehaviourId)
    • 儲存與畫布碰撞的指標的世界位置到InputDataController.CursorPosition
    • 如果指標命中附有一個NetworkedUiButton元件的遊戲物件,它被儲存到InputDataController.UiInteractionBehaviour (NetworkBehaviourId)
  • UiPointerHandler

    • 讀取輸入並且發送指標位置及互動到相應的NetworkedCanvasNetworkedUiButton

槽模組

可開槽的系統用於將物件平滑地引導到預定位置/方向。想一想:插槽、按鍵、拼圖塊、磁帶匣等等。
為了完成這個,GrabbableBase.cs有各種`elegates及回調,以覆寫物件在被拿取時想要到達的目標位置。

  • RotationDelegate GetRotationMethod
  • GrabAndTargetPositionDelegate GetGrabAndTargetPositionMethod
  • UnityAction PreTrackCallback
  • UnityAction PostTrackCallback

可開槽的

Slottable元件覆寫這些回調,並且取決於與Slot相關的目前目標,來改變所需的位置及旋轉。

  • PreTrack:檢查是否距離一個被影響的槽足夠近,並且計算兩個要素以供之後使用

    • _slotFactorHand:手到槽的距離。這用於決定物件應該採用的目標位置及旋轉。
    • _slotFactorObject:物件到槽的距離。這用於決定物件是否被放入槽內並且應該被放開,物件是否仍然可以被旋轉(>RotationLockThreshold)
  • PostTrack:檢查物件是否應該被卸除。

物件要素是物件的實際位置,而手要素是在應用任何力量之前根據手的輸入為止來確定。

Slottable取決於_slotFactorHand_slotFactorObject,來取得所需位置/旋轉形式Slot

額外元件:

  • GrabbableRidgidbody
  • HotspotCollector以找出有效的槽。
  • (選擇性)NetworkColliderCollection:指派在靠近Slot時忽略的colliders(如果設定的話,針對槽中設定的碰撞器,以及與熱點互動的手來忽略)

Slot元件含有物件在範圍內應有的行為的資料。
Curves決定從物件位置到所需槽位置的位置/旋轉的改變的突然程度。
需要至少一個標記為觸發程序的碰撞器,且該碰撞器具有正確的圖層,以便由Slottables HotspotCollector拾取。

HotspotsToIgnoreHandCollisionWhenGrabbed可用於忽略拿取熱點的手。
當空間很緊密,並且您希望忽略拿取Slot的手時,這將很有用。
示例:一隻手抓著手槍,彈匣和彈匣槽離手很近,因此在正常情況下彈匣會與手碰撞。
也在這裡新增手柄的熱點以忽略手碰撞。
UseLineForRange可以設定為使用線段來作為可開槽的目標,而非使用一個點。

DropType決定當一個物件被成功地放入槽時,應該如何處理物件。

  • Kinematic:用於將物件放入靜態等級幾何的槽。物件成為運動學的,並且除非再次被拿取,否則無法移動。
  • Destroy:物件被取消繁衍
  • TeleportOffsite:還沒有被良好的測試,可用於在剛體上被放入槽的物件,這樣在再次拿取它們時可以立即重新定位它們。將需要在接收端有一些魔法,以轉譯可開槽物到位置上。)

Slots決定Slottable是否可以被放入槽,其檢查各種參數:

  • SlotType符合該槽
  • 沒有已出現其他Slottable(或是否已設定AllowMultipleObjects
  • 可以在(Slot.CanSlot())中新增更多限制

元件:

  • NetworkIgnoreCollision(選擇性):可以針對已放入槽的物件來忽略被指派的碰撞器。這可以用於讓Slottable可以穿過牆,而手本身或其他不符合槽的物件無法穿過。

射擊模組

如何完成類似於槍的可互動物的範例執行方式。提供兩個示例。

  • 散彈槍

    • 一次發射多顆子彈
    • 使用GrabbableRigidbody的較大的物理主體
    • 重新裝填單一彈殼
  • 手槍

    • 使用連接主體的手動扳機
    • 重新裝填完整的彈匣
    • 使用AttachmentRigidbody拿取

須知事項

場景設定

Connector.csLocalRigSpawner.cs在每個場景中出現。如果在場景中沒有繁衍或預先定義或本機裝置,它將繁衍一個(xr或pc)並且建立一個執行器及連線。
針對Start.scene,執行器以單一玩家模式開始。這樣做,我們可以完整存取到我們的遊戲碼,而不需要額外的工作。

手及物件視覺效果內插補點:

在不同的情況下,NetworkRigidobdy的常規內插補點在Render()中被覆寫

  • 如果手沒有拿取或碰撞任何東西,則設定本機控制器位置。這避免了使用力量(XRObject.cs, UpdateRender())來移動手物件時發生的任何延遲。
  • 如果手正在拿取一個物件,針對視覺效果手位置,該物件有實際授權。手的位置是相對於被拿取物件的位置,並考慮當互動開始時的初始位移(GrabbableBase.cs Render())。
  • 如果放開物件,視覺效果手被拉回實際位置(HandTool.cs Render())

常見問題

  • 我的可拿取物件到處飛來飛去/怪異地旋轉:檢查下列設定,以確保力量不會積聚或振蕩。在遊玩時可以在編輯器中調整它們。

  • BodyProperties:各個可拿取物件有一個BodyProperties元件,其中設定及同步物理屬性。屬性本身是可指令碼的物件,並且可以在相似的物件上重複使用。調整值以取得您希望物件有的重量及感覺。當物件失去控制時,它可能是位置或旋轉元件振蕩。在GrabbableBase元件中,您可以切換是否要追蹤位置和/或旋轉,以找出造成問題的原因並且相應地進行調整。

    • 位置:質量、拖曳。使用重力k、速度外推
    • 旋轉:質量、角拖曳、慣性、扭力外推
  • GrabbableRidgidbody,「將質量中心設定為拿取點」:在Grabbable Rigidbody元件中,您可以切換是否將質量中心設定為在拿取時的拿取點。這對於物件的旋轉特性有重大的影響,並且可能需要不同的BodyProperties。如果具有相同的BodyProperties的類似物件的行為不同,這可能是問題的來源。

Back to top