Brick Builder Sample
下載
| 版本 | 發佈日期 | 下載 | |
|---|---|---|---|
概述
預設下,Quantum Map是在編輯或構建時創建的,因為它是一個靜態資產,不允許在運行時進行更改。將大部分碰撞幾何體作為靜態碰撞體對於運行高性能的碰撞檢測非常重要。
此技術示例顯示了如何擴展Quantum Map的常見用途的選項,並作為關卡編輯器呈現,允許玩家以三種方式創建和修改地圖。
- 下載地圖 - 在運行時,在Quantum遊戲聲明之前,從自定義後端下載Quantum地圖。
- 程序生成 - 在遊戲開始之前的運行時按程序生成地圖。
- 關卡編輯器 - 使用**DynamicMap** API在運行時合作更改地圖。
場景
從後端下載
此場景顯示了如何在啟動模擬之前將從外部源獲得的資產(在本例中為地圖)保存到模擬中。
當遊戲有地圖共享系統時,通常會使用這種技術,例如,玩家可以將自己的創作保存到遊戲的後端伺服器。
模擬後端
為了保持示例的通用性,使用MockBackend類別來偽造從Resources資料夾下載地圖。該類別實現了IBackend介面,允許開發人員插入自己的後端。
IBackend介面有兩種方法:
- DownloadMapAsync - 從後端非同步下載地圖。
- 此版本在真實遊戲中使用,以便在下載地圖時不會凍結遊戲。
 
- DownloadMap - 從後端同步下載地圖。
- 此版本僅在編輯器中調試時使用。
- 這是因為Debug Runner啟動回調是同步的。
 
這些方法傳回一個DownloadedMap類型的結構體,其中包含Map資產以及包含地圖碰撞幾何體的二進位資料資產。
此資料在覆寫連接行為中啟動Quantum之前被消耗。請參閱:覆寫預設選單行為
為了使此示例與真正的後端一起工作,需要實現IBackend介面,並且必須用調用自定義後端API的程式碼替換MockBackend。
ServerMapDownloader
ServerMapDownloader類別從MockBackend下載地圖,並使用QuantumUnityDB.Global.AddAsset方法將其添加到資產資源中。
此類別有三種方法:
- 下載 - 從後端同步下載地圖並將其添加到資產資料庫中。
- DownloadAsync - 從後端非同步下載地圖並將其添加到資產資料庫中。
- AddAsset - 將資產添加到資產資料庫中。這是前兩種方法都使用的。
- 如果不在資產資料庫中註冊資產,將無法透過模擬中的FindAssetAPI存取資產。
 
- 如果不在資產資料庫中註冊資產,將無法透過模擬中的
AddAsset透過使用QuantumUnityDB.Global.AddAsset方法來工作,並將提供的資產添加到資產資料庫中。
例子:
C#
var asset = AssetObject.Create<MyAssetType>();
asset.Guid = SomeDeterministicGuid;
QuantumUnityDB.Global.AddAsset(asset);
在這種情況下SomeDeterministicGuid是基於資產物件生成的確定性Guid。請參閱:生成確定性Guid
將資產添加到資產資料庫後,它實際上與在編輯器中創建和添加資產相同。
然而,這僅在遊戲尚未開始時有效。遊戲開始後,不應更改靜態資產資料庫。
如果您需要在遊戲過程中添加或更改資產,則必須使用DynamicDB API。這在關卡編輯器一節中有所介紹。
確定性Guid
在運行時添加資產時,資產具有確定性的Guid非常重要,否則可能會導致遊戲不同步。
有兩種方法可以生成確定性Guid:
- 使用常數:
- 這是獲得確定性Guid的最簡單方法。
- 您必須確保其他資產沒有被分配相同的Guid。
- 只要您有固定數量的資產要添加,並且您確信相同的資產將始終被分配相同的Guid,這就很好。
- 關卡編輯器場景使用這種方法。另請參見:LevelEditorConsts
 
- 生成:
- QuantumUnityDB.CreateRuntimeDeterministicGuid方法提供了一個生成Guid的API。
- 它使用資產物件的名稱作為種子來生成確定性Guid。
- 如果需要添加的資產數量不固定,則應使用此方法。
 
使用:
C#
// create any asset
var assetObject = AssetObject.Create<MyAssetObjectType>();
// set it's name
assetObject.name = "Generated Map";
// get a deterministic guid
var guid = QuantumUnityDB.CreateRuntimeDeterministicGuid(assetObject);
// add the asset to the asset database
QuantumUnityDB.Global.AddAsset(assetObject);
// set the guid
assetObject.Guid = guid;
程序生成
資產也可以在運行時在應用程式中的每個用戶端上按程序生成(前提是該方法是確定性的),並在遊戲開始前添加到資料庫中。
在這種情況下也可以使用DynamicDB API,但它不是最佳的,因為後期加入的用戶端必須在開始之前下載地圖。如果地圖非常大,這可能是一個問題,導致在等待下載完成時超時。
一般來說,如果可以在本機生成,那麼避免下載任何東西是一個很好的優化步驟。
DeterministicBrickMapGenerator
此類別使用兩個資產進行程序生成:
- 基礎地圖 - 用於生成地圖的基礎地圖資產。
- 這只是一個空地圖,用作生成地圖的基礎。
 
- TextAsset物件 - 這是一個包含兩個序列化資產的文字資產。
- 地圖 - 一張包含一棵由磚塊製成的樹的地圖。
- 二進位資料 - 包含樹的碰撞幾何形狀的二進位資料資產。
 
這個類別有幾個方法:
- GenerateAndSetMapGuid - 生成地圖,將其添加到資產資料庫中,並設定提供的RuntimeConfig地圖欄位。- 這在編輯器調試期間使用。 它在調試運行器啟動時被調用。
 
- 生成 - 生成地圖和二進位資料資產,然後將其添加到資產資料庫中。
- 這是運行時使用的主要方法。示例:生成示例
 
- MergeMaps - 這在生成過程中用於將基礎地圖與隨機定位的樹地圖合併。
- MergeMapEntities - 在生成過程中使用此選項將基礎地圖的實體與樹地圖的實體合併。
- 這是必要的,因為關卡編輯器利用實體來顯示磚塊的視覺表示。請參見:磚視覺
 
- MergeStaticColliders3D - 這在生成過程中用於將基礎地圖的靜態碰撞器與樹地圖的靜態碰撞器合併。
- 當靜態碰撞器三角形被讀入記憶體時,它們被存儲在非託管數組中。
 因此,三角形需要轉換為託管數組,然後才能重新保存為新的二進位資料資產。
 這是透過使用提供的公用方法Utils.FromUnManagedTriangleBuffer來完成。
 
- 當靜態碰撞器三角形被讀入記憶體時,它們被存儲在非託管數組中。
- WriteBinaryData - 將組合的三角形資訊寫入ByteStream,然後將其保存到創建的二進位資料中。
- DuplicateMap - 這複製了提供的地圖資產。
- 這是為了避免在組合基礎地圖和樹地圖時修改它們。
 
生成示例:
要使用DeterministicBrickMapGenerator類別,請在遊戲開始前調用Generate方法,如下所示:
C#
var generator = GetComponent<DeterministicBrickMapGenerator>();
generator.Generate(seed);
這將生成一張地圖,並將其確定性地添加到資產資料庫中。
關卡編輯器
此場景演示透過使用DynamicDB API和DynamicMap API在運行時添加和更改資產。
DynamicDB是一個運行時資料庫,允許在運行時添加和修改資產。請參閱:DynamicDB
DynamicMap API是Map類別的擴展,它覆寫地圖的預設行為以允許運行時
對地圖的動態更改。具體來說,靜態碰撞器。
這種方法通常在遊戲過程中需要以某種方式對地圖進行修改時使用。
注意:DynamicMap不能替代Map。它受設計限制,只能在運行時在編輯器中使用。
為什麼不使用動態碰撞器?
靜態碰撞器不會移動,因此物理引擎不需要不斷重新計算它們的位置、速度或加速度。這大大降低了物理引擎的計算負載。
輸入
此示例場景使用命令而不是正常輸入。請參閱:命令
這是因為地圖編輯不是在每一幀都發生的。
當執行這些命令時,它會調用由BrickBuildingSystem消耗的相應訊號。 參見:磚砌建築系統
PlaceBrickCommand
此命令用於在地圖上放置磚塊。它包含位置、旋轉和要放置的磚資產。
DeleteBrickCommand
此命令用於從地圖中刪除磚塊。它包含應拆除的磚塊的靜態碰撞器索引。
ClearBricksCommand
此命令用於清除地圖上的所有磚塊。它實際上與DeleteBrickCommand相同,但它一次刪除所有磚塊。
BrickBuildingSystem
這是處理輸入並將更改應用於地圖的主要系統。
首先,在OnInit中,系統使用DynamicMap.FromStaticMap創建一個可以變異的複製。然後,它被添加到DynamicDB中。
系統會監聽PlaceBrickCommand、DeleteBrickCommand和ClearBricksCommand訊號。
當接收到訊號時,系統使用以下方法應用更改,並使用DynamicMap API更新地圖。
- BrickPlaced - 在地圖上放置磚塊。
- 此方法首先在資產資料庫中查找磚塊,然後檢查它是否可以放置在所需的位置。
- 如果可以放置磚塊,則使用DynamicMapAPI將其添加到地圖中。
- 根據碰撞器類型,磚塊將使用AddMeshCollider(表示網格碰撞器)或AddCollider3D(表示普通碰撞器)添加到地圖中。
- 最後,它使用BrickVisual類別創建磚塊的視覺表示。請參見:磚視覺
 
- BrickDeleted - 從地圖中移除磚塊。
- 此方法使用磚塊的靜態碰撞器索引將其從地圖中移除。
- 如果找到磚塊,則根據碰撞器類型,使用RemoveMeshCollider或RemoveCollider3D將其從地圖中移除。- 需要注意的一點是,當從地圖中移除一個碰撞器時,碰撞器索引會重新分配給地圖中的最後一個碰撞器。
- 這樣做是為了保持物理引擎的碰撞器索引連續。
 
- 最後,如果前面的所有步驟都成功,磚的視覺表示也將被移除。
 
調試地圖
BrickBuildingSystem還有一個調試模式,可以透過啟用RuntimeConfig中的DebugDrawBrickGrid欄位來切換。
 
啟用此選項後,系統將在場景視圖中繪製地圖的網格。
磚塊
磚塊是地圖的構建方塊的資產。它們包含有關網格大小、網格碰撞器類型以及生成時使用的視覺預製件的資訊。
磚視覺
此示例使用一個預製件來表示地圖中的所有磚塊。
這是透過從關聯的磚資產中讀取網格並在運行時在預製件上設定它來實現的。
BrickRotation
BrickRotation枚舉用於表示磚塊的旋轉。這是因為磚塊只有四種可能的旋轉。
磚網格
BrickGrid類別用於表示包含所有磚塊的網格。
它將磚塊存儲在字典中,其中的關鍵是磚塊在網格中的位置。
由於BrickGrid的潜在大小,在模擬中序列化網格是不可行的。
因此,網格被序列化並存儲在FrameContext中。
創建磚塊
要創建磚塊,您需要:
- 在Bricks資料夾中創建一個新的ScriptableObject資產。
- 用必要的資料填充資產,例如要使用的網格、網格大小和任何變體。
- 將磚塊添加到AllBricks資產中。- 這只是一個包含玩家可用的所有磚塊清單的資產。
 
磚塊現在將顯示在編輯器場景中,並可以放置在地圖中。
檔案I/O
LevelEditorFileController類別用於將地圖保存到檔案和從檔案載入地圖。它只是將磚塊資訊序列化
為BitStream,並將其寫入Application.persistentDatapath中的檔案。
額外資訊
覆寫預設選單行為
LevelEditorConnectionBehaviour類別覆寫了演示選單的ConnectionBehaviour類別中的ConnectAsync方法,以允許關卡編輯器在連接到伺服器之前
執行操作。
它可以做兩件事:
上一版本
此示例是Quantum 2.1關卡編輯器的後續版本。它已更新到Quantum 3.0並在許多領域得到了
改進,例如:
- 箱式碰撞器支架
- 在之前的版本中,示例僅支持網格碰撞器。
- 由於這個限制,舊示例無法支持很多物件。
 
- 不規則網格
- 在之前的版本中,網格物件的大小只能為1x1x1。
- 在此版本中,您可以擁有任何大小的網格物件。
 
- DynamicMap
- 我們現在使用新的DynamicMapAPI,而不是從頭開始編寫靜態碰撞器編輯。
 
- 我們現在使用新的
- 下載靜態資產
- 在Quantum 2.1中,在運行時下載新的靜態資產非常複雜。
- 在Quantum 3.0中,透過使用新的QuantumUnityDB.Global.AddSourceAPI簡化了這一過程。
 
第三方資產
此示例包括第三方免費和CC0資產。您可以在各自的網站上為自己的專案獲取完整的套裝軟體:
- Kenney的Brick Kit