6 - Asteroids
概述
隨著飛船玩家實體的準備就緒,下一步是在小行星上生成。
小行星生成器設置
小行星以波的形式生成,每波都包含更多的小行星。用作設定檔的資產物件是存儲聲明小行星如何生成的參數的更好方法,而不是將與小行星生成相關的變數硬編碼到系統中。在QuantumUser > Simulation
資料夾中創建一個新的AsteroidGameConfig
指令碼。新增以下程式碼到它:
C#
using Photon.Deterministic;
using UnityEngine;
namespace Quantum.Asteroids
{
public class AsteroidsGameConfig: AssetObject
{
[Header("Asteroids configuration")]
[Tooltip("Prototype reference to spawn asteroids")]
public AssetRef<EntityPrototype> AsteroidPrototype;
[Tooltip("Speed applied to the asteroid when spawned")]
public FP AsteroidInitialSpeed = 8;
[Tooltip("Minimum torque applied to the asteroid when spawned")]
public FP AsteroidInitialTorqueMin = 7;
[Tooltip("Maximum torque applied to the asteroid when spawned")]
public FP AsteroidInitialTorqueMax = 20;
[Tooltip("Distance to the center of the map. This value is the radius in a random circular location where the asteroid is spawned")]
public FP AsteroidSpawnDistanceToCenter = 20;
[Tooltip("Amount of asteroids spawned in level 1. In each level, the number os asteroids spawned is increased by one")]
public int InitialAsteroidsCount = 5;
}
}
請注意,該類別繼承自AssetObject
,這將其轉換為ScriptableObject
,可以像本教學前面的MapData
和SystemConfig
資產一樣插入Quantum模擬。
AssetRef<EntityPrototype>
是一種特殊類型。AssetRef是Quantum在資產資料庫中引用AssetObjects
的管道。其他欄位是簡單的設置值,將由負責生成小行星的系統使用。
要創建資產的實例,請按右鍵點擊Resources
資料夾,然後選擇Create > Quantum > Asset.. > AsteroidsGameConfig
。將新設置資產命名為AsteroidsGameConfig
。將所有值保留為預設值,並將AsteroidLargeEntityPrototype
放入設置的AsteroidPrototype
欄位中。
插入設置
有兩種常見的方法可以存取Quantum模擬中的AssetObject
- 在場景物件或預製件上的實體元件上有一個
AssetRef
欄位。 - 透過
RuntimeConfig
將AssetObject
連結為全域物件。
在這種情況下,使用後一種方法,因為遊戲設置是一個可供許多系統使用的全域設置。
在QuantumUser > Simulation
資料夾中創建一個新指令碼,並將其命名為RuntimeConfig.Asteroids
。新增以下程式碼到它:
C#
namespace Quantum
{
public partial class RuntimeConfig
{
public AssetRef<Asteroids.AsteroidsGameConfig> GameConfig;
}
}
請注意,使用Quantum
代替Quantum.Asteroids
命名空間,因為此類別是擴展現有RuntimeConfig
類別的分部類別。
返回Unity並前往場景中的QuantumDebugRunner
遊戲物件。現在RuntimeConfig
條目上有一個新的GameConfig
欄位。放入之前創建的AsteroidGameConfig
資產。
小行星生成器系統
在QuantumUser > Simulation
資料夾中創建一個新的c#指令碼,並將其命名為AsteroidsWaveSpawnerSystem
。新增以下程式碼到它:
C#
using Photon.Deterministic;
using UnityEngine.Scripting;
namespace Quantum.Asteroids
{
[Preserve]
public unsafe class AsteroidsWaveSpawnerSystem : SystemSignalsOnly
{
public void SpawnAsteroid(Frame f, AssetRef<EntityPrototype> childPrototype)
{
AsteroidsGameConfig config = f.FindAsset(f.RuntimeConfig.GameConfig);
EntityRef asteroid = f.Create(childPrototype);
Transform2D* asteroidTransform = f.Unsafe.GetPointer<Transform2D>(asteroid);
asteroidTransform->Position = GetRandomEdgePointOnCircle(f, config.AsteroidSpawnDistanceToCenter);
asteroidTransform->Rotation = GetRandomRotation(f);
if (f.Unsafe.TryGetPointer<PhysicsBody2D>(asteroid, out var body))
{
body->Velocity = asteroidTransform->Up * config.AsteroidInitialSpeed;
body->AddTorque(f.RNG->Next(config.AsteroidInitialTorqueMin, config.AsteroidInitialTorqueMax));
}
}
public static FP GetRandomRotation(Frame f)
{
return f.RNG->Next(0, 360);
}
public static FPVector2 GetRandomEdgePointOnCircle(Frame f, FP radius)
{
return FPVector2.Rotate(FPVector2.Up * radius , f.RNG->Next() * FP.PiTimes2);
}
}
}
該系統現時只包含一個可以調用以生成小行星的函數。該函數透過查找之前連結到RuntimeConfig
的GameConfig
資產來生成小行星實體的原型。
FindAsset
非常高效,每當有小行星生成時,重複調用它是沒有問題的。
除了創建小行星實體外,該函數還使用隨機位置和旋轉以初始化小行星,並根據GameConfig
中的值對其應用速度和扭矩。
向系統新增狀態
隨著SpawnAsteroid
函數的準備就緒,是時候實作波了。小行星應該以波的形式生成,每一波都應該比前一波多產生一顆小行星。為此,有必要追蹤波計數器。
ECS中的系統是無狀態的,因此不允許向AsteroidsWaveSpawnerSystem
新增常規變數。這不僅是Quantum中的一種良好實踐,而且對於預測復原模擬的正確運行也是必要的。切勿在Quantum中將狀態置於系統上。
可以使用以下兩種方法來代替將狀態放在系統上。
- 將狀態放在全域框架上。全域框架包含所有系統都可以存取的單一變數。
- 將狀態放在單一元件上。單一元件類似於常規實體元件,但除此之外,它們可以透過方便的API輕鬆獲取。您可以在此處瞭解更多關於單一元件的資訊。
為了簡單起見,本教學中使用了全域框架。在QuantumUser > Simulation
資料夾中創建一個新的 Global.qtn
檔案。新增以下程式碼到它:
global
{
Int32 AsteroidsWaveCount;
}
這將int新增到全域框架中,從而可以透過調用frame.Global->AsteroidsWaveCount
從任何系統存取它。
新增波
在實作波計數器後,返回AsteroidWaveSpawnerSystem
並新增以下函數:
C#
private void SpawnAsteroidWave(Frame f)
{
AsteroidsGameConfig config = f.FindAsset(f.RuntimeConfig.GameConfig);
for (int i = 0; i < f.Global->AsteroidsWaveCount + config.InitialAsteroidsCount; i++)
{
SpawnAsteroid(f, config.AsteroidPrototype);
}
f.Global->AsteroidsWaveCount++;
}
此函數根據生成的波數量生成多個小行星,然後遞增計數器。
最後,為了讓第一波生成OnInit
函數,可以在模擬開始後在每個系統上調用該函數:
C#
public override void OnInit(Frame f)
{
SpawnAsteroidWave(f);
}
隨著波生成系統的實作,完全回歸Unity。要使波系統運行,還需要最後一步。將其新增到AsteroidSystemConfig
中的系統清單中。
識別船
現在進入遊玩模式時,儘管該系統根本沒有改變,但AsteroidsShipSystem
的控制台中仍有許多空的引用錯誤。原因是使用了系統篩選器:
C#
public struct Filter
{
public EntityRef Entity;
public Transform2D* Transform;
public PhysicsBody2D* Body;
}
由於飛船和小行星都有一個變換和一個物理體,篩選器會找到這兩個物件,並在每個小行星上運行飛船更新函數。解決這個問題的一個簡單方法是在船上新增一個獨特的元件。
在QuantumUser > Simulation
資料夾中創建一個新的AsteroidsShip
.qtn檔案。向其中新增一個空的元件,如下所示:
C#
component AsteroidsShip
{
}
注意: ECS中的空的元件稱為標籤元件。因為它們的用途是識別實體,就像標籤系統一樣。
返回Unity並打開 AsteroidsShip
預製件。在QuantumEntityPrototype
元件上,按Entity Components
清單上的+
按鈕,然後選擇AsteroidsShip
元件。
最後,調整AsteroidsShipSystem
中的篩選器,以包含以下元件:
C#
public struct Filter
{
public EntityRef Entity;
public Transform2D* Transform;
public PhysicsBody2D* Body;
public AsteroidsShip* AsteroidsShip;
}
返回Unity並進入遊玩模式。作為第一波的一部分,除了玩家物件外,還生成了5顆小行星。
Back to top