Projectiles Advanced
概述
拋射物進階展示了在一個射擊遊戲中,針對不同類型的拋射物來執行網路的方法。對於多重玩家拋射物進行程式設計,可能是一項艱難的工作,其中涉及平衡效能、頻寬耗用,以及精確度。它也要求平滑的轉譯,以負責處理在已模擬及已轉譯拋射物路徑(從相機發射對比從武器槍口發射)之間的任何不一致。拋射物進階目標在於稍微澄清及簡化這項工作。
為了有脈絡地說明拋射物,範例被組建為一個簡單的第一人稱射擊遊戲,其附有其他支援系統(遊戲遊玩處理、健康及損傷系統、武器),並且可以用作為組建射擊遊戲的堅實基礎。
如需取得拋射物的概述以及更多可以被輕易地複製到不同的專案的獨立示例,請參見拋射物基礎。
主機端模式
拓撲。功能
- 使用拋射物資料環形緩衝,在沒有單獨的
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
視窗的一個稍微修改的版本將出現在可以選擇遊戲開始模式的地方。
多重同儕節點
選擇Start Host + 1 Client
或Start Host + 2 Clients
,將以多重同儕節點模式來開始遊戲。強烈建議使用這個方法來測試拋射物在代理上的行為方式。
按下數字鍵盤上的0
、1
、2
,及3
鍵來切換同儕節點。
也可以使用Runner Visibility Controls
視窗(頂層選單Fusion/Windows/Runner Visibility Controls
)來切換同儕節點。
為了看見射擊在代理上的行為方式,只設定 客戶端A 為可見,並且只啟用 客戶端B 為一個輸入提供者。現在可以從 客戶端A 的視角來觀察您從 客戶端B 的射擊。
控制
使用W
、S
、A
、D
以移動,Mouse1
以發射,及Mouse2
以替換發射(如果可用)。可使用滑鼠滾輪或按下適當的字母數字鍵來切換武器。請查看遊戲內UI,以取得關於選取的武器及其發射的拋射物類型的資訊。
使用ENTER
鍵以鎖住或釋放您的游標。
專案組織
預製件類型 | 位置 |
---|---|
玩家及代理 | /Prefabs |
武器 | /Prefabs/Weapons |
拋射物 | /Prefabs/Projectiles |
玩家
玩家(Player
指令碼、Player
預製件)代表一個在遊戲中的已連線同儕節點,而且其沒有視覺效果。使用玩家以同步統計資料、暱稱、選取的英雄,它們加入遊戲遊玩的期望等等。玩家也可以處理輸入。
代理(PlayerAgent
指令碼、Agent
預製件)代表一個在遊戲中的角色,其由玩家控制,由Gameplay
繁衍,具有Health
、Weapons
及其他常見的東西。可以根據需要來繁衍及取消繁衍。
拋射物管理器
ProjectileManager
是Fusion拋射物範例的核心。它處理拋射物資料緩衝及拋射物的視覺效果代表的建立/更新/刪除。拋射物管理器存在於控制物件上(比如Agent
、Turret
),並且負責更新該物件擁有的所有武器的拋射物。
拋射物管理器需要拋射物預製件序列,以正確地配對拋射物到特定預製件。為了簡單性,拋射物管理器直接在檢查器中參照到預製件。
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)執行GetFireData
及OnFixedUpdate
方法,其用於 生成及操控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
功能性,比如移動程式碼。針對拋射物執行個體來執行的方法為Activate
、OnRender
及Deactivate
,並且是純粹的視覺效果。
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
從武器槍口到目標位置都可以顯示視覺效果軌跡。軌跡隨著時間經過而逐漸消失。
示例武器:狙擊槍(逐漸消失的軌跡),散彈槍(立即視覺效果)
FlyingHitscanProjectile
立即處理命中,但是有一個虛擬飛行拋射物以特定的速度飛向目標位置。
示例武器:步槍
運動學的拋射物
隨著時間移動的拋射物,在每個模擬刷新時在先前的位置及新的位置之間執行短射線。
SimpleKinematicProjectile
以一個直線飛行的運動學的拋射物。
示例武器:脈衝槍
AdvancedKinematicProjectile
可受重力影響並從牆壁及其他物件上反彈的運動學的拋射物。這個拋射物類型可以管理多種拋射物行為:
落下的拋射物,並在接觸時爆炸
示例武器:脈衝槍(替代發射——手榴彈)落下及彈跳的拋射物,並在一段時間後爆炸
示例武器:步槍(替代發射——手榴彈)直線彈跳拋射物
示例武器:跳彈槍
HomingKinematicProjectile
主動轉向以命中目標的拋射物。它可以預測目標位置以命中移動中的目標。可以指定應該擊中的身體部位、旋轉的屬性及目標搜尋行為。
示例武器:自導引槍(主要發射快速的自導引拋射物,次要發射——火箭——來用於較慢的重新瞄準拋射物)
射線
隨著時間經過而造成損傷的持續射線。使用武器元件WeaponBeam
來執行射線(在武器元件章節中有更多說明),在這個專案中它並不是真正的拋射物。
示例武器:雷射槍
獨立拋射物
可以被繁衍為一個獨立網路物件的拋射物。應該只用於一些特別的情況。也請參見選擇正確的方法章節。
DataStandaloneProjectile
針對獨立拋射物功能性的包裝函式。以類似於ProjectileManager
的方法來建立並更新ProjectileData
,只是只對一個拋射物來做這個方法。可以被預測性地繁衍。
示例武器:跳彈槍(次要發射——彈跳落下)
拋射物內插補點
當在第一人稱遊戲中發射拋射物時,可以選擇直接從武器槍口(實際性方法)或是從相機中心(標準方法)來完成拋射物計算。
Fusion拋射物使用更標準的從相機中心的發射方法。然而這個方法在已模擬路徑(源自相機)及已轉譯路徑(源自武器槍口)之間建立一個差異。在武器槍口到實際拋射物路徑之中隨著時間來內插補點拋射物位置,以解決這個問題。可以在所有運動學的拋射物上設定內插補點值(內插補點時間、內插補點容易性)。
武器
概述
Fusion拋射物含有一個小的武器處理系統。它是一個基本的執行方式,其只處理武器切換。對於更精細的用途,比如武器掉落、拾取、重新裝填子彈、後座力模式、動態散佈及其他用途,請查看Fusion BR範例。
然而,為了管理所有類型的武器,包含了一個便利的武器動作—元件系統。
武器動作
一個武器動作是一組 武器元件的集合,其代表一個單一武器動作。舉例而言,一個武器動作是一個標準發射,而其他動作是一個替代發射。武器可以有各種武器動作。
武器元件
武器元件代表武器的一部分,其有自己的邏輯,並且可以在不同的案例中重複使用。可以使用多個元件來組裝武器,以組成所需的功能性。Fusion拋射物附有多種武器元件:
WeaponMagazine
——提供子彈WeaponTrigger
——說明武器應該發射的時間(檢查玩家輸入、控制武器節奏)WeaponBarrel
——發射拋射物WeaponFireEffect
——顯示槍口、播放發射聲音、應用擊退,開始相機震動WeaponBeam
——發射持續光線
透過WeaponDesires
架構來鬆散地結合武器元件。
武器槍口
元件替換為武器光線
——彈匣仍提供子彈,扳機仍然說明何時發射,只是發射效果不同。另一個示例是一個迷你槍,其中需要時間以讓旋轉槍管在發射前獲得足夠的速度——在這個例子中,建立一個延遲扳機
以替換標準扳機。
震動效果
ShakeEffect
公用程式用於驅動相機震動(在Game
場景中的GameplayScene/SceneCamera/Shaker
物件)以回應武器發射。從WeaponFireEffects
元件來觸發效果,其中可以設定位置及旋轉震動範圍。ShakeEffect
公用程式支援不同的相機震動的堆疊及持續震動(持續發射)。
健康及損傷系統
對於命中同步,使用一個類似於拋射物資料的方法。命中儲存在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
,其處理在一個特定半徑之內的損傷。
損傷區域
損傷隨著時間而應用在這個區域之中的所有目標。使用它以測試即將來臨的損傷。
布偶
為了簡化性,在代理死亡時只透過啟用剛體物理來處理代理死亡動畫。請查看SimpleAgentRagdoll
指令碼。
炮塔
SimpleTurret
用於在一定的時間間隔中繁衍獨立拋射物。沒有搜尋目標的邏輯,也沒有朝向目標的旋轉。用於測試在Agent
預製件之外的武器。
遊戲核心
遊戲管理器
處理已連線玩家的加入及離開,以及繁衍Player
預製件。有關儲存玩家資料以便重新連線的,關於已連線玩家的更精細的處理,請參照Fusion BR範例。
遊戲遊玩
Gameplay
負責繁衍/取消繁衍Agent
預製件。這個基礎執行方式作為一個無盡的殊死戰。可以被繼承和擴展,以新增不同的遊戲功能性,比如適當的殊死戰、俘虜旗幟、殲滅戰等等。
輪詢
在涉及拋射物的專案中,預期會繁衍大量的物件(拋射物、槍口效果、衝擊、命中效果等等)。由於具現化一個新的物件是一個花費龐大的操作,因此輪詢在Fusion拋射物中的所有東西。
有兩種類型的輪詢:
NetworkObjectPool
用於輪詢NetworkObject
。為了讓網路物件輪詢順利工作,需要執行INetworkObjectPool
介面,並且在NetworkRunner
開始時被指派為一個開始參數(這發生在CustomNetworkDebugStart
指令碼之中)。為了取得更多資訊,請查看Fusion操作手冊中的網路物件輪詢章節。ObjectCache
是一個泛型GameObject
輪詢,其可用於非連線物件,比如衝擊效果。它有一個方便的功能,可以以一個指定的延遲來傳回物件。
場景及場景內容
**Scene
**處理場景特定的功能性及服務(SceneService
),比如UI、相機、音樂、迷你地圖,及其他事項。從此處手動地更新場景服務,所以可以在需要的時候針對專案來初始化、啟用、停用,及更新它們。
SceneContext
提供安全的存取到常用服務或在程式碼庫之間所需的其他資訊,而不需使用靜態。在GameplayScene
及NetworkObjectPool
中,場景內容被自動地傳送到場景服務,並且被指派到已連線的物件。如果需要存取到SceneContext
,需要繼承於ContextBehaviour
及ContextSimulationBehaviour
而非NetworkBehaviour
及SimulationBehaviour
。
擴展專案
新增新的武器
1)建立一個新的預製件或複製一個現有的武器。
2)確保在預製件上至少有一個WeaponAction
元件及適當的武器元件。WeaponAction
及武器元件可以全部在一個GameObject
上(請參見Sniper
預製件),或是在有多個武器動作的情況下,它需要以階層來放置(請參見Rifle
預製件)。
3)在Weapon
元件中設定WeaponSlot
,以指定它在玩家武器序列中應該佔據的地方——第1槽是第一個可見的武器。
4)在Weapon
元件中選擇性地指派武器名稱及圖示。
5)指派武器到Agent
預製件上的Weapons
元件中的Initial Weapons
欄位。
新增新的拋射物
1)建立一個新的預製件或複製一個現有的拋射物。確保有一個繼承於Projectile
的元件。
2)指派拋射物預製件到WeaponBarrel
元件中的武器預製件。
3)在控制物件(比如Agent
預製件)上的ProjectileManager
中指派拋射物預製件,以確保它在被發射時將繁衍拋射物。
切換到第三人
Fusion拋射物被組建為一個第一人稱遊戲,但是大多數的功能性也適用於第三人稱遊戲。當在第三人稱遊戲中發射時,首先需要從相機投射射線,已找到玩家試圖射擊的點。然後,實際的拋射物投射將從角色上的一個點(靠近角色肩膀的一個固定點通常效果良好)到從相機投射中獲得的點。這裡通常涉及一些技巧(比如忽略與第二次投射的一些碰撞),這樣玩家不會太常命中意料外的物件(角落問題)。請查看Fusion BR以取得一個第三人稱處理的示例。
第三方資產
拋射物範例包含了由各自的創作者提供的多個資產。您可以在它們各自的網站上為您自己的專案取得完整的套件:
- Archanor VFX的Polygon Arsenal
重要事項:為了在商業專案中使用它們,需要從各自的創作者購買一個授權。
Back to top