This document is about: FUSION 1
SWITCH TO

Projectiles Advanced

Level 4

概述

拋射物進階展示了在一個射擊遊戲中,針對不同類型的拋射物來執行網路的方法。對於多重玩家拋射物進行程式設計,可能是一項艱難的工作,其中涉及平衡效能、頻寬耗用,以及精確度。它也要求平滑的轉譯,以負責處理在已模擬及已轉譯拋射物路徑(從相機發射對比從武器槍口發射)之間的任何不一致。拋射物進階目標在於稍微澄清及簡化這項工作。

為了有脈絡地說明拋射物,範例被組建為一個簡單的第一人稱射擊遊戲,其附有其他支援系統(遊戲遊玩處理、健康及損傷系統、武器),並且可以用作為組建射擊遊戲的堅實基礎。

如需取得拋射物的概述以及更多可以被輕易地複製到不同的專案的獨立示例,請參見拋射物基礎

這個範例使用主機端模式拓撲。

功能

  • 使用拋射物資料環形緩衝,在沒有單獨的NetworkObject的情況下處理拋射物
  • 從即時命中判定到自導引拋射物的多種拋射物類型
  • 武器元件系統
  • 7種不同的武器
    • 脈衝槍
    • 步槍
    • 散彈槍
    • 雷射槍
    • 狙擊槍
    • 自導引槍
    • 跳彈槍
  • 從武器槍口到真實的拋射物路徑(從相機發射)的已解決的內插補點
  • 健康與損傷系統
  • 爆炸
  • 拋射物的預測性繁衍

在您開始之前

需求:

  • Unity 2021.3
  • Fusion應用程式帳號:為了運行範例,首先在PhotonEngine儀表板中建立一個Fusion應用程式帳號,並且將它貼上到即時設定(可從Fusion選單中到達)中的App Id Fusion欄位之中。之後繼續跟隨開始遊戲章節中的指引。

下載

版本 發佈日期 下載
1.1.6 2023年4月14日 Fusion拋射物1.1.6組建182

開始遊戲

偵錯開始

開啟並遊玩Game場景(Scenes/Game)來開始一個遊戲。Fusion標準NetworkDebugStart視窗的一個稍微修改的版本將出現在可以選擇遊戲開始模式的地方。

Debug Start

多重同儕節點

選擇Start Host + 1 ClientStart Host + 2 Clients,將以多重同儕節點模式來開始遊戲。強烈建議使用這個方法來測試拋射物在代理上的行為方式。

按下數字鍵盤上的012,及3鍵來切換同儕節點。

也可以使用Runner Visibility Controls視窗(頂層選單Fusion/Windows/Runner Visibility Controls)來切換同儕節點。

Runner Visibility Controls

為了看見射擊在代理上的行為方式,只設定 客戶端A 為可見,並且只啟用 客戶端B 為一個輸入提供者。現在可以從 客戶端A 的視角來觀察您從 客戶端B 的射擊。

Runner Visibility Controls
注意事項:為了讓多重同儕節點模式順利運作,必須避免透過靜態欄位來參照場景物件(存取到UI、相機裝置、玩家資料等等),不過避免靜態一般而言也是一個良好的且建議的做法。請查看場景及場景內容章節,以取得在整個程式碼基底中存取常用物件的一個解決方案。

控制

使用WSAD 以移動,Mouse1以發射,及Mouse2以替換發射(如果可用)。可使用滑鼠滾輪或按下適當的字母數字鍵來切換武器。請查看遊戲內UI,以取得關於選取的武器及其發射的拋射物類型的資訊。

使用ENTER鍵以鎖住或釋放您的游標。

First Play

專案組織

預製件類型 位置
玩家及代理 /Prefabs
武器 /Prefabs/Weapons
拋射物 /Prefabs/Projectiles

玩家

玩家Player指令碼、Player預製件)代表一個在遊戲中的已連線同儕節點,而且其沒有視覺效果。使用玩家以同步統計資料、暱稱、選取的英雄,它們加入遊戲遊玩的期望等等。玩家也可以處理輸入。

代理PlayerAgent指令碼、Agent預製件)代表一個在遊戲中的角色,其由玩家控制,由Gameplay繁衍,具有HealthWeapons及其他常見的東西。可以根據需要來繁衍及取消繁衍。

Photon Dummy

拋射物管理器

ProjectileManager是Fusion拋射物範例的核心。它處理拋射物資料緩衝及拋射物的視覺效果代表的建立/更新/刪除。拋射物管理器存在於控制物件上(比如AgentTurret),並且負責更新該物件擁有的所有武器的拋射物。

Projectile Manager

拋射物管理器需要拋射物預製件序列,以正確地配對拋射物到特定預製件。為了簡單性,拋射物管理器直接在檢查器中參照到預製件。

注意事項:存取預製件序列的更好的解決方案將是遊戲特定的,但舉例而言它可以是一個附有設定資料的可指令碼物件。

ProjectileManager儲存ProjectileData,其用於計算拋射物軌跡及其他拋射物行為:

C#

[StructLayout(LayoutKind.Explicit)]
public struct ProjectileData : INetworkStruct
{
    public bool    IsActive          { get { return _state.IsBitSet(0); } set { _state.SetBit(0, value); } }
    public bool    IsFinished        { get { return _state.IsBitSet(1); } set { _state.SetBit(1, value); } }

    [FieldOffset(0)]
    private byte   _state;

    [FieldOffset(1)]
    public byte    PrefabId;
    [FieldOffset(2)]
    public byte    WeaponAction;
    [FieldOffset(3)]
    public int     FireTick;
    [FieldOffset(7)]
    public Vector3 FirePosition;
    [FieldOffset(19)]
    public Vector3 FireVelocity;
    [FieldOffset(31)]
    public Vector3 ImpactPosition;
    [FieldOffset(43)]
    public Vector3 ImpactNormal;

    // Custom projectile data

    [FieldOffset(55)]
    public HomingData    Homing;
    [FieldOffset(55)]
    public KinematicData Kinematic;

    public struct HomingData : INetworkStruct
    {
        public NetworkId Target;
        public Vector3   TargetPosition; // Used for position prediction
        public Vector3   Position;
        public Vector3   Direction;
    }

    public struct KinematicData : INetworkStruct
    {
        public NetworkBool HasStopped;
        public Vector3     FinishedPosition;
        public int         StartTick;
        public byte        BounceCount;
    }
}

這個架構目前相當大,這是因為在這個專案中展示了大量的拋射物功能。同時,因為正在展示多個不同的拋射物行為,且它們並不使用相同的資料值,因此資料架構使用特定拋射物資料的聯集。

在實際操作中,建議保持這個ProjectileData架構為盡可能小。對於大多數遊戲來說,所需的功能將比這裡展示的少。請查看ProjectileData的已註解的簡化版本:

C#

public struct ProjectileData : INetworkStruct
{
    public bool    IsActive          { get { return _state.IsBitSet(0); } set { _state.SetBit(0, value); } }
    public bool    IsFinished        { get { return _state.IsBitSet(1); } set { _state.SetBit(1, value); } }

    private byte   _state;

    public byte    PrefabId;
    public byte    WeaponAction;
    public int     FireTick;
    public Vector3 FirePosition;
    public Vector3 FireVelocity;
    [Networked, Accuracy(0.01f)]
    public Vector3 ImpactPosition { get; set; }
    [Networked, Accuracy(0.01f)]
    public Vector3 ImpactNormal { get; set; }
}
注意事項: 聯集的使用(= StructLayout(LayoutKind.Explicit)屬性)防止了在架構中包含屬性,並且因此防止使用已連線準確屬性。請了解如何在沒有使用聯集屬性的情況下,如何使用屬性及針對衝擊位置衝擊常規準確屬性,來節省一些頻寬。

拋射物

拋射物指令碼(預製件)有兩個用途:

1)執行GetFireDataOnFixedUpdate方法,其用於 生成及操控ProjectileData。在狀態授權及輸入授權上從FixedUpdateNetwork來調用這些方法,並且是 直接在預製件上調用,而不是在預製件執行個體上。

C#

public abstract ProjectileData GetFireData(NetworkRunner runner, Vector3 firePosition, Vector3 fireDirection);
public abstract void OnFixedUpdate(ProjectileContext context, ref ProjectileData data);
注意事項:拋射物不是一個網路行為,並且與一個網路物件沒有關聯。所以在取得已發射資料在固定更新上中使用的所有網路資料必須被包含在拋射物資料架構之中。

2)拋射物執行個體也用作為一個拋射物的視覺效果代表。這允許共享的FUN(模擬)及Render功能性,比如移動程式碼。針對拋射物執行個體來執行的方法為ActivateOnRenderDeactivate,並且是純粹的視覺效果。

C#

public void Activate(ProjectileContext context, ref ProjectileData data)
{
    PrefabId = data.PrefabId;
    IsFinished = false;

    OnActivated(context, ref data);
}

public void Deactivate(ProjectileContext context)
{
    IsFinished = true;

    OnDeactivated(context);
}

public virtual void OnRender(ProjectileContext context, ref ProjectileData data)
{
}

public virtual void Discard()
{
    IsFinished = true;
}

當在伺服器上沒有發射拋射物時,也可以針對未命中的預測的自訂行為來覆寫Discard方法(比如,為了播放溶解效果)。

每個拋射物都可以繁衍在衝擊時的視覺效果以及一個新的NetworkObject(比如爆炸)。

拋射物類型

Fusion拋射物包含了多個拋射物類型,其可能用在許多常見案例。

即時命中判定拋射物

也稱為射線即時拋射物

附有特定的最大距離的射線,其在發射輸入時立即發射,並且立即評估命中。

InstantHitscanProjectile
從武器槍口到目標位置都可以顯示視覺效果軌跡。軌跡隨著時間經過而逐漸消失。
示例武器:狙擊槍(逐漸消失的軌跡),散彈槍(立即視覺效果)

Sniper
附有從武器槍口到衝擊的軌跡的即時命中判定拋射物

FlyingHitscanProjectile
立即處理命中,但是有一個虛擬飛行拋射物以特定的速度飛向目標位置。
示例武器:步槍

Rifle
附有飛行虛擬子彈的即時命中判定拋射物

運動學的拋射物

也簡單稱為拋射物

隨著時間移動的拋射物,在每個模擬刷新時在先前的位置及新的位置之間執行短射線。

SimpleKinematicProjectile
以一個直線飛行的運動學的拋射物。
示例武器:脈衝槍

Pulse Gun
運動學的拋射物

AdvancedKinematicProjectile
可受重力影響並從牆壁及其他物件上反彈的運動學的拋射物。這個拋射物類型可以管理多種拋射物行為:

  • 落下的拋射物,並在接觸時爆炸
    示例武器:脈衝槍(替代發射——手榴彈

  • 落下及彈跳的拋射物,並在一段時間後爆炸
    示例武器:步槍(替代發射——手榴彈

  • 直線彈跳拋射物
    示例武器:跳彈槍

Ricochet Gun
跳彈槍的跳彈拋射物

HomingKinematicProjectile
主動轉向以命中目標的拋射物。它可以預測目標位置以命中移動中的目標。可以指定應該擊中的身體部位、旋轉的屬性及目標搜尋行為。
示例武器:自導引槍(主要發射快速的自導引拋射物,次要發射——火箭——來用於較慢的重新瞄準拋射物)

Homing Gun
自導引槍的自導引拋射物

射線

也稱為光線雷射

隨著時間經過而造成損傷的持續射線。使用武器元件WeaponBeam來執行射線(在武器元件章節中有更多說明),在這個專案中它並不是真正的拋射物。
示例武器:雷射槍

Laser Gun
雷射射線

獨立拋射物

可以被繁衍為一個獨立網路物件的拋射物。應該只用於一些特別的情況。也請參見選擇正確的方法章節。

DataStandaloneProjectile
針對獨立拋射物功能性的包裝函式。以類似於ProjectileManager的方法來建立並更新ProjectileData,只是只對一個拋射物來做這個方法。可以被預測性地繁衍。
示例武器:跳彈槍(次要發射——彈跳落下

拋射物內插補點

當在第一人稱遊戲中發射拋射物時,可以選擇直接從武器槍口(實際性方法)或是從相機中心(標準方法)來完成拋射物計算。

注意事項:實際性方法用於少數(硬核)遊戲。它讓發射感覺更真實,但是也較不穩定(發射位置取決於玩家動畫),並且容易造成意料外的命中(角落問題),這是因為武器從相機偏移。

Fusion拋射物使用更標準的從相機中心的發射方法。然而這個方法在已模擬路徑(源自相機)及已轉譯路徑(源自武器槍口)之間建立一個差異。在武器槍口到實際拋射物路徑之中隨著時間來內插補點拋射物位置,以解決這個問題。可以在所有運動學的拋射物上設定內插補點值(內插補點時間、內插補點容易性)。

Projectile interpolation
自上而下檢視中的拋射物內插補點
Kinematic projectile setup
運動學的拋射物設定
注意事項:只有運動學的拋射物需要拋射物內插補點。即時命中判定的拋射物不需要內插補點,這是因為我們已經知道拋射物將衝擊的位置,所以虛擬飛行物視覺效果可以直接移動到該點。

武器

概述

Fusion拋射物含有一個小的武器處理系統。它是一個基本的執行方式,其只處理武器切換。對於更精細的用途,比如武器掉落、拾取、重新裝填子彈、後座力模式、動態散佈及其他用途,請查看Fusion BR範例。

然而,為了管理所有類型的武器,包含了一個便利的武器動作—元件系統。

武器動作

一個武器動作是一組 武器元件的集合,其代表一個單一武器動作。舉例而言,一個武器動作是一個標準發射,而其他動作是一個替代發射。武器可以有各種武器動作。

Weapon Action
脈衝槍上的主要武器動作,附有所有必要的武器元件

武器元件

武器元件代表武器的一部分,其有自己的邏輯,並且可以在不同的案例中重複使用。可以使用多個元件來組裝武器,以組成所需的功能性。Fusion拋射物附有多種武器元件:

  • WeaponMagazine——提供子彈
  • WeaponTrigger——說明武器應該發射的時間(檢查玩家輸入、控制武器節奏)
  • WeaponBarrel——發射拋射物
  • WeaponFireEffect——顯示槍口、播放發射聲音、應用擊退,開始相機震動
  • WeaponBeam——發射持續光線

透過WeaponDesires架構來鬆散地結合武器元件。

注意事項:當組建各種武器時,做法是只替換一個或多個元件,同時重新使用其他的元件。一個示例是雷射槍,其中武器槍口元件替換為武器光線——彈匣仍提供子彈,扳機仍然說明何時發射,只是發射效果不同。另一個示例是一個迷你槍,其中需要時間以讓旋轉槍管在發射前獲得足夠的速度——在這個例子中,建立一個延遲扳機以替換標準扳機。

震動效果

ShakeEffect公用程式用於驅動相機震動(在Game場景中的GameplayScene/SceneCamera/Shaker物件)以回應武器發射。從WeaponFireEffects元件來觸發效果,其中可以設定位置及旋轉震動範圍。ShakeEffect公用程式支援不同的相機震動的堆疊及持續震動(持續發射)。

Camera shake
相機震動設定

健康及損傷系統

對於命中同步,使用一個類似於拋射物資料的方法。命中儲存在Hit架構的一個小的已連線的環形緩衝之中。

C#

public struct Hit : INetworkStruct
{
    public EHitAction Action;
    public float      Damage;
    [Networked, Accuracy(0.01f)]
    public Vector3    RelativePosition { get; set; }
    [Networked, Accuracy(0.1f)]
    public Vector3    Direction { get; set; }
    public PlayerRef  Instigator;
}

Hit架構開始,可以建構適當的命中回應——比如播放命中動畫,在UI中顯示命中方向,顯示針對煽動者的損傷的命中確認及數量,繁衍血液效果等等。

注意事項:請注意是命中的相對位置儲存在命中資料之中,而非一個絕對位置。由於代理的位置是在從伺服器接收到的最後兩個刷新之間進行內插補點,因此相對位置更適合用於將命中效果(比如血液飛濺)正確地放置在身體上。

遊戲遊玩元素

爆炸

簡單的已繁衍Network Object,其處理在一個特定半徑之內的損傷。

Explosion

損傷區域

損傷隨著時間而應用在這個區域之中的所有目標。使用它以測試即將來臨的損傷。

Damage Area

布偶

為了簡化性,在代理死亡時只透過啟用剛體物理來處理代理死亡動畫。請查看SimpleAgentRagdoll指令碼。

Ragdoll

炮塔

SimpleTurret用於在一定的時間間隔中繁衍獨立拋射物。沒有搜尋目標的邏輯,也沒有朝向目標的旋轉。用於測試在Agent預製件之外的武器。

Turret

遊戲核心

遊戲管理器

處理已連線玩家的加入及離開,以及繁衍Player預製件。有關儲存玩家資料以便重新連線的,關於已連線玩家的更精細的處理,請參照Fusion BR範例。

遊戲遊玩

Gameplay負責繁衍/取消繁衍Agent預製件。這個基礎執行方式作為一個無盡的殊死戰。可以被繼承和擴展,以新增不同的遊戲功能性,比如適當的殊死戰、俘虜旗幟、殲滅戰等等。

輪詢

在涉及拋射物的專案中,預期會繁衍大量的物件(拋射物、槍口效果、衝擊、命中效果等等)。由於具現化一個新的物件是一個花費龐大的操作,因此輪詢在Fusion拋射物中的所有東西。

有兩種類型的輪詢:

  • NetworkObjectPool 用於輪詢NetworkObject。為了讓網路物件輪詢順利工作,需要執行INetworkObjectPool介面,並且在NetworkRunner開始時被指派為一個開始參數(這發生在CustomNetworkDebugStart指令碼之中)。為了取得更多資訊,請查看Fusion操作手冊中的網路物件輪詢章節。

  • ObjectCache 是一個泛型GameObject輪詢,其可用於非連線物件,比如衝擊效果。它有一個方便的功能,可以以一個指定的延遲來傳回物件。

場景及場景內容

**Scene**處理場景特定的功能性及服務(SceneService),比如UI、相機、音樂、迷你地圖,及其他事項。從此處手動地更新場景服務,所以可以在需要的時候針對專案來初始化、啟用、停用,及更新它們。

SceneContext 提供安全的存取到常用服務或在程式碼庫之間所需的其他資訊,而不需使用靜態。在GameplaySceneNetworkObjectPool中,場景內容被自動地傳送到場景服務,並且被指派到已連線的物件。如果需要存取到SceneContext,需要繼承於ContextBehaviourContextSimulationBehaviour而非NetworkBehaviourSimulationBehaviour

擴展專案

新增新的武器

1)建立一個新的預製件或複製一個現有的武器。

2)確保在預製件上至少有一個WeaponAction元件及適當的武器元件。WeaponAction及武器元件可以全部在一個GameObject上(請參見Sniper預製件),或是在有多個武器動作的情況下,它需要以階層來放置(請參見Rifle預製件)。

3)在Weapon元件中設定WeaponSlot,以指定它在玩家武器序列中應該佔據的地方——第1槽是第一個可見的武器。

4)在Weapon元件中選擇性地指派武器名稱及圖示。

5)指派武器到Agent預製件上的Weapons元件中的Initial Weapons欄位。

Weapons inspector

新增新的拋射物

1)建立一個新的預製件或複製一個現有的拋射物。確保有一個繼承於Projectile的元件。

2)指派拋射物預製件到WeaponBarrel元件中的武器預製件。

WeaponBarrel inspector

3)在控制物件(比如Agent預製件)上的ProjectileManager中指派拋射物預製件,以確保它在被發射時將繁衍拋射物。

切換到第三人

Fusion拋射物被組建為一個第一人稱遊戲,但是大多數的功能性也適用於第三人稱遊戲。當在第三人稱遊戲中發射時,首先需要從相機投射射線,已找到玩家試圖射擊的點。然後,實際的拋射物投射將從角色上的一個點(靠近角色肩膀的一個固定點通常效果良好)到從相機投射中獲得的點。這裡通常涉及一些技巧(比如忽略與第二次投射的一些碰撞),這樣玩家不會太常命中意料外的物件(角落問題)。請查看Fusion BR以取得一個第三人稱處理的示例。

第三方資產

拋射物範例包含了由各自的創作者提供的多個資產。您可以在它們各自的網站上為您自己的專案取得完整的套件:

重要事項:為了在商業專案中使用它們,需要從各自的創作者購買一個授權。

Back to top