基於Unity2019最新ECS架構開發MMO遊戲筆記1
中文版一圖讀懂ECS
前言
在上一篇基於Unity2019最新ECS架構開發MMO遊戲筆記0中講了官方的第一個案例,通過圖文並茂的分析,相信各位大佬已經對ECS有了一定的認識,這一篇會繼續分析官方案例。
關於源碼,如果有意想深入瞭解的,請看大鵬的專欄!
官方案例解析2
開始之前的準備工作:
0下載Unity編輯器(2019.1.0f1 or 更新的版本),if(已經下載了)continue;
1下載官方案例,打開Git Shell輸入:
git clone https://github.com/Unity-Technologies/EntityComponentSystemSamples.git --recurse
or 點擊Unity官方ECS示例下載代碼
if(已經下載了)continue;
2用Unity Hub打開官方的項目:ECSSamples
3在Assets目錄下找到HelloCube/2. IJobForEach ,並打開IJobForEach 場景
2. IJobForEach
和第一個案例1. JobForEach中的場景一樣,裏面僅有四個遊戲對象,那麼這個案例究竟有啥子不同呢?下面一探究竟:
- Main Camera ……主攝像機
- Directional Light……光源
- RotatingCube……旋轉的方塊
- ChildCube……子方塊
和案例1一樣RotatingCube上同樣掛了ConvertToEntity腳本,它將Unity的遊戲對象GameObject轉化成Entity,從而讓遊戲運行更加高效,腳本的工作原理已經在上一篇講過了,此處跳過。
RotatingCube上還掛了另外一個腳本RotationSpeedAuthoring_IJobForEach,下面我們來看一下這個腳本:
/// <summary>
/// 這就是ECS中的E了,它將數據交給C
/// </summary>
[RequiresEntityConversion]//必須實體轉化
public class RotationSpeedAuthoring_IJobForEach : MonoBehaviour, IConvertGameObjectToEntity
{//繼承接口IConvertGameObjectToEntity,並實現Convert
public float DegreesPerSecond = 360;
/// <summary>
/// 這個方法上一篇講過,通過該方法,實體將數據交給組件儲存起來
/// </summary>
/// <param name="entity">實體</param>
/// <param name="dstManager">目標實體管理器</param>
/// <param name="conversionSystem">轉化系統</param>
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
var data = new RotationSpeed_IJobForEach { RadiansPerSecond = math.radians(DegreesPerSecond) };
dstManager.AddComponentData(entity, data);
}
}
代碼和上一篇的腳本RotationSpeedAuthoring_ForEach幾乎一毛一樣,區別在於IJob關鍵字上了,我猜後面一定會使用C#的Job系統,來充分利用多線程。按照流程,Entity把數據通過Convert方法傳給Component組件了,下面我們來看RotationSpeed_IJobForEach 腳本:
/// <summary>
/// 我啥也不幹,就放數據
/// </summary>
[Serializable]
public struct RotationSpeed_IJobForEach : IComponentData
{
public float RadiansPerSecond;
}
這裏提一下IComponentData,它就是一個空接口而已,作用只是表面自己是Component的身份,從而讓System識別,非常純粹的一個腳本。下面是這個案例的重點RotationSpeedSystem_IJobForEach:
// This system updates all entities in the scene with both a RotationSpeed_IJobForEach and Rotation component.
/// <summary>
/// 這裏利用了Jobs和Burst編譯器,它們和ECS共同組成DOTS,使代碼運行更加高效
/// </summary>
public class RotationSpeedSystem_IJobForEach : JobComponentSystem
{//通過繼承JobComponentSystem來利用Jobs多線程的特性
// Use the [BurstCompile] attribute to compile a job with Burst. You may see significant speed ups, so try it!
[BurstCompile]//使用這個定語來利用Burst編譯器,需要在Unity編輯器菜單欄Jobs-》Burst-》Enable Compilition來激活編譯器
struct RotationSpeedJob : IJobForEach<Rotation, RotationSpeed_IJobForEach>
{
public float DeltaTime;
// The [ReadOnly] attribute tells the job scheduler that this job will not write to rotSpeedIJobForEach
/// <summary>
/// 該方法會在OnUpdate中每幀執行
/// </summary>
/// <param name="rotation">旋轉</param>
/// <param name="rotSpeedIJobForEach">[ReadOnly]定語告訴Jobs任務系統預定器這項任務不需要寫入,這樣會更快速</param>
public void Execute(ref Rotation rotation, [ReadOnly] ref RotationSpeed_IJobForEach rotSpeedIJobForEach)
{
// Rotate something about its up vector at the speed given by RotationSpeed_IJobForEach.
//Component的數據在這裏使用,使方塊旋轉起來
rotation.Value = math.mul(math.normalize(rotation.Value), quaternion.AxisAngle(math.up(), rotSpeedIJobForEach.RadiansPerSecond * DeltaTime));
}
}
// OnUpdate runs on the main thread.
/// <summary>
/// OnUpdate在主線程上運行,上面寫的旋轉任務會在這裏加入到計劃當中
/// </summary>
/// <param name="inputDependencies">輸入依賴</param>
/// <returns></returns>
protected override JobHandle OnUpdate(JobHandle inputDependencies)
{
var job = new RotationSpeedJob
{
DeltaTime = Time.deltaTime
};
return job.Schedule(this, inputDependencies);
}
}
和第一個案例大同小異,不過更加先進了,從1到2的過程是循序漸進的,註釋還算明瞭吧?
下面還是按照老規格理清一下思路好了!
小結
我們來對比案例一:
ECS | Scripts | 繼承 |
---|---|---|
Entity | RotationSpeedAuthoring_ForEach | IConvertGameObjectToEntity |
Component | RotationSpeed_ForEach | IComponentData |
System | RotationSpeedSystem_ForEach | ComponentSystem |
案例二:
ECS | Scripts | Inherit |
---|---|---|
Entity | RotationSpeedAuthoring_IJobForEach | IConvertGameObjectToEntity |
Component | RotationSpeed_IJobForEach | IComponentData |
System | RotationSpeedSystem_IJobForEach | JobComponentSystem |
通過上面兩個對照表是不是理清開發思路了?區別在於System的迭代進化,充分利用了Jobs和Burst編譯器,因此會跑得更快!
DOTS 邏輯圖表
上面大概表現了幾者的關係,我是從表象上這麼理解的,至於底層怎麼弄的,I don‘t care。流程大體如下:
更新計劃
作者的話
如果喜歡我的文章可以點贊支持一下,謝謝鼓勵!如果有什麼疑問可以給我留言,有錯漏的地方請批評指證!
如果有技術難題需要討論,可以加入開發者聯盟:566189328(付費羣)爲您提供有限的技術支持,以及,心靈雞湯!
當然,不需要技術支持也歡迎加入進來,隨時可以請我喝咖啡、茶和果汁!( ̄┰ ̄*)