This document is about: QUANTUM 3
SWITCH TO

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,可以像本教學前面的MapDataSystemConfig資產一樣插入Quantum模擬。

AssetRef<EntityPrototype>是一種特殊類型。AssetRef是Quantum在資產資料庫中引用AssetObjects的管道。其他欄位是簡單的設置值,將由負責生成小行星的系統使用。

要創建資產的實例,請按右鍵點擊Resources資料夾,然後選擇Create > Quantum > Asset.. > AsteroidsGameConfig。將新設置資產命名為AsteroidsGameConfig。將所有值保留為預設值,並將AsteroidLargeEntityPrototype放入設置的AsteroidPrototype欄位中。

The AsteroidGameConfig

插入設置

有兩種常見的方法可以存取Quantum模擬中的AssetObject

  1. 在場景物件或預製件上的實體元件上有一個AssetRef欄位。
  2. 透過RuntimeConfigAssetObject連結為全域物件。

在這種情況下,使用後一種方法,因為遊戲設置是一個可供許多系統使用的全域設置。

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資產。

Linking the Game Config

小行星生成器系統

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);
        }
    }
}

該系統現時只包含一個可以調用以生成小行星的函數。該函數透過查找之前連結到RuntimeConfigGameConfig資產來生成小行星實體的原型。

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元件。

Add AsteroidsShip Component

最後,調整AsteroidsShipSystem中的篩選器,以包含以下元件:

C#

public struct Filter
{
    public EntityRef Entity;
    public Transform2D* Transform;
    public PhysicsBody2D* Body;
    public AsteroidsShip* AsteroidsShip;
}

返回Unity並進入遊玩模式。作為第一波的一部分,除了玩家物件外,還生成了5顆小行星。

Asteroid Wave in Play Mode GIF
Back to top