国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Unity DOTS技術(shù)

這篇具有很好參考價值的文章主要介紹了Unity DOTS技術(shù)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

目錄

一.概述

二.DOTS詳解

1.開發(fā)環(huán)境搭建

2.簡單ECS程序

?2.調(diào)試功能

3.常用API

?4.系統(tǒng)之間的互相干擾

5.實(shí)體Entity的創(chuàng)建查找刪除

6.使用批處理Gpu Instancing優(yōu)化性能

7.World,System,Group

1)World

2)System

3)Group

8.組件Component介紹

1)組件Component的添加修改刪除

2)ShareComponent

3)狀態(tài)組件

4)BufferElement

5)ChunkComponent介紹


一.概述

傳統(tǒng)方式問題

1.數(shù)據(jù)冗余:unity腳本含有大量的冗余信息,比如說我們?nèi)绻獙⒛_本掛載在物體上,腳本需要繼承自MonoBehaviour類,而MonoBehaviour類中有很多的函數(shù)調(diào)用,其中相當(dāng)一部分我們并不需要。

2.單線程處理:Unity中的腳本大多都是在主線程運(yùn)行的,無法發(fā)揮cpu多核的優(yōu)勢

3.編譯器問題:unity對于c#的代碼調(diào)用是相對低效的。

DOTS技術(shù)

為了解決上述問題,unity推出了DOTS技術(shù)(Data-Oriented Technology Stack),中文名稱:數(shù)據(jù)導(dǎo)向型技術(shù)堆棧。它主要包括一下三點(diǎn)

1.ECS(Entity Component System):數(shù)據(jù)和行為分離

2.Job System:多線程,充分發(fā)揮多核cpu的特性

3.Burst complier:編譯生成高效的代碼

二.DOTS詳解

1.開發(fā)環(huán)境搭建

PackManager中安裝Entites和Hybrid Renderer,若當(dāng)前unity版本沒有此安裝包請查看預(yù)覽包。

2.簡單ECS程序

ECS(E:實(shí)體,C:組件,S:系統(tǒng)),ECS實(shí)際上是將數(shù)據(jù)和方法實(shí)現(xiàn)分離,數(shù)據(jù)放在組件里,具體實(shí)現(xiàn)的方法放在系統(tǒng)里,組件掛載在實(shí)體上,系統(tǒng)通過實(shí)體找到組件。

下面通過代碼實(shí)現(xiàn)向Console打印的效果

//DataComponent.cs
//存儲數(shù)據(jù)組件
using Unity.Entities;

public struct DataComponent:IComponentData
{
    public float printData;
}
//DataSystem.cs
//數(shù)據(jù)系統(tǒng)
using UnityEngine;
using Unity.Entities;

public class DataSystem : ComponentSystem
{
    /// <summary>
    /// 相當(dāng)于update
    /// </summary>
    protected override void OnUpdate()
    {
        //獲取所有DataCompoent類
        Entities.ForEach((ref DataComponent datacomponent) =>
        {
            Debug.Log(datacomponent.printData);
        });
    }
}
//DataMono.cs
//掛載在物體上
using UnityEngine;
using Unity.Entities;

public class DataMono : MonoBehaviour, IConvertGameObjectToEntity
{
    /// <summary>
    /// 當(dāng)前物體轉(zhuǎn)化為實(shí)體時會被調(diào)用一次
    /// </summary>
    /// <param name="entity"></param>
    /// <param name="dstManager"></param>
    /// <param name="conversionSystem"></param>
    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        //entity需要掛載的實(shí)體,new DataComponent():需要掛載的組件
        dstManager.AddComponentData(entity, new DataComponent());
    }
}

Unity DOTS技術(shù),unity,游戲引擎

Convert To Entity組件,將物體轉(zhuǎn)換為實(shí)體。

Console輸出如下圖所示

Unity DOTS技術(shù),unity,游戲引擎

?2.調(diào)試功能

菜單欄Window->Analysis->Entity Debugger

Unity DOTS技術(shù),unity,游戲引擎

?左邊表示系統(tǒng)中有哪些正在運(yùn)行的系統(tǒng)。All Entityes(Default World)點(diǎn)擊后中間顯示場景中所有的實(shí)體。右邊Chunk Utiilization表示場景中所有實(shí)體的組件

3.常用API

using Unity.Transforms;

Translation

成員變量

Translation.value 物體的位置相當(dāng)于position

RotationEulerXYZ

成員變量

RotationEulerXYZ.value 控制物體的旋轉(zhuǎn)

4.系統(tǒng)之間的互相干擾

[DisaleAutoCreation]??????? 避免其他場景的系統(tǒng)的干擾

5.實(shí)體Entity的創(chuàng)建查找刪除

1.創(chuàng)建

創(chuàng)建10000個物體

//ESCPrefabCreator.cs
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;

public class ESCPrefabCreator : MonoBehaviour
{
    public GameObject cube;
    private void Start()
    {
        //獲得當(dāng)前世界的設(shè)置
        GameObjectConversionSettings tempSettings = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, null);
        //將cube轉(zhuǎn)換為實(shí)體存儲下來
        Entity tempEntityPrefab = GameObjectConversionUtility.ConvertGameObjectHierarchy(cube, tempSettings);
        //獲得實(shí)體管理器
        EntityManager tempEntityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
        //設(shè)置位置
        Translation translation = new Translation();
        //實(shí)例化10000個實(shí)體   
        for (int i = 0;i < 100;i++)
        {
            translation.Value.x = 0;
            for (int j = 0;j < 100;j++)
            {
                Entity tempCube = tempEntityManager.Instantiate(tempEntityPrefab);
                //設(shè)置組件的值
                tempEntityManager.SetComponentData(tempCube, translation);
                translation.Value.x += 2;
            }
            translation.Value.y += 2;
        }
    }
}

上面是通過代碼轉(zhuǎn)化實(shí)體,那么我們改如何將場景里存在的物體轉(zhuǎn)換成實(shí)體呢?我在上面說過給物體添加Convert To Entity組件即可進(jìn)行轉(zhuǎn)換,但通常場景中會包含著大量物體,給每一個物體手動添加Convert To Entity不太現(xiàn)實(shí),于是Unity設(shè)計了一個Subscene的方法批量轉(zhuǎn)換實(shí)體。

操作:將需要被轉(zhuǎn)化的物體設(shè)置一個父物體,右鍵創(chuàng)建一個Subscene即可

Unity DOTS技術(shù),unity,游戲引擎Unity DOTS技術(shù),unity,游戲引擎

介紹完如何轉(zhuǎn)化實(shí)體,下面我來介紹從0開始創(chuàng)建實(shí)體

//CreateSinglon.cs
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;

public class CreateSinglon : MonoBehaviour
{
    void Start()
    {
        //創(chuàng)建一個實(shí)體
        Entity tempEntity = World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntity(typeof(DataComponent), typeof(RotationEulerXYZ));
        //通過一個實(shí)體再創(chuàng)建一個實(shí)體
        World.DefaultGameObjectInjectionWorld.EntityManager.Instantiate(tempEntity);

    }
}

?我們通過這串代碼創(chuàng)建了兩個實(shí)體,如果我們想大批量創(chuàng)建實(shí)體怎么辦?

接下來我們引入一個概念Chunk

chunk相當(dāng)于一個塊,ECS會將相同組件的實(shí)體添加到同一個chunk中,例如Entity1,Entity2都有A,B組件,Entity3,Entity4都有C組件,那么Entity1,2放置在Chunk1中,Entity3,4放置在Chunk2中。chunk具有一定的容量,當(dāng)chunk放滿時ECS會再開一個chunk放置實(shí)體,新開的塊和原來的塊在類型上是相同的,我們將同種類型的Chunk稱之為ArchType(原型),我們可通過ArchType訪問相同類型的塊。ECS這樣做的目的是為了提高創(chuàng)建和訪問實(shí)體的性能。

//CreateEntites.cs
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
using Unity.Collections;

public class CreateEntites : MonoBehaviour
{
    void Start()
    {
        //創(chuàng)建一個實(shí)體
        Entity tempEntity = World.DefaultGameObjectInjectionWorld.EntityManager.
            CreateEntity(typeof(DataComponent), typeof(RotationEulerXYZ));
        //通過一個實(shí)體再創(chuàng)建一個實(shí)體
        World.DefaultGameObjectInjectionWorld.EntityManager.Instantiate(tempEntity);

        //創(chuàng)建一個原型,包括DataCompont和RotationXYZ組件
        EntityArchetype tempEntityArchetype = World.DefaultGameObjectInjectionWorld.EntityManager.
            CreateArchetype(typeof(DataComponent), typeof(RotationEulerXYZ));
        //創(chuàng)建一個NativeArray,將實(shí)體添加到數(shù)組中,Allocator決定實(shí)體存儲的模式
        //NativeArray和數(shù)組差不多,用來存儲物體,而JobSystem多線程無法使用普通數(shù)組,于是用NativeArray代替
        NativeArray<Entity> tempNativeArray = new NativeArray<Entity>(5, Allocator.Temp);
        //通過原型創(chuàng)建5個實(shí)體
        World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntity(tempEntityArchetype, tempNativeArray);
        //通過實(shí)體創(chuàng)建5個實(shí)體
        World.DefaultGameObjectInjectionWorld.EntityManager.Instantiate(tempEntity, tempNativeArray);

    }
}

?2.查找

//FindEntities.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
using Unity.Collections;

public class FindEntities : MonoBehaviour
{
    void Start()
    {
        #region 創(chuàng)建
        /*和CreateEntites創(chuàng)建代碼相同*/
        #endregion

        #region 查找
        //方法1
        //獲得世界全部的實(shí)體
        NativeArray<Entity> tempEntits = World.DefaultGameObjectInjectionWorld.EntityManager.GetAllEntities();
        foreach(var item in tempEntits)
        {
            //打印實(shí)體的序號和名字
            Debug.Log(item.Index + World.DefaultGameObjectInjectionWorld.EntityManager.GetName(item));
        }
        //方法2
        //根據(jù)該組建創(chuàng)建一個實(shí)體的查詢
        EntityQuery tempEntityQuery = World.DefaultGameObjectInjectionWorld.EntityManager.
            CreateEntityQuery(typeof(DataComponent), typeof(RotationEulerXYZ));
       //創(chuàng)建一個NativeArray存儲所有的查詢結(jié)果
        NativeArray<Entity> tempEntits2 = tempEntityQuery.ToEntityArray(Allocator.TempJob);
        foreach(var item in tempEntits2)
        {
            Debug.Log(item.Index + World.DefaultGameObjectInjectionWorld.EntityManager.GetName(item));
        }
        //釋放NativeArray
        tempEntits2.Dispose();
        #endregion
    }
}

3.刪除

//刪除
//方法1:刪除單個物體
World.DefaultGameObjectInjectionWorld.EntityManager.DestroyEntity(tempEntity);
//方法2:通過NativeArray刪除
World.DefaultGameObjectInjectionWorld.EntityManager.DestroyEntity(tempEntityNativeArray);
//方法3:通EntityQuery刪除
World.DefaultGameObjectInjectionWorld.EntityManager.DestroyEntity(tempEntityQuery);

6.使用批處理Gpu Instancing優(yōu)化性能

Unity DOTS技術(shù),unity,游戲引擎

?勾選材質(zhì)里的Enable GPU Instancing

7.World,System,Group

World:相當(dāng)于對ECS進(jìn)行一個全局管理,場景里可以擁有多個world但是world之間無法進(jìn)行通信。

System:只能存在與一個世界,同一世界不能有重復(fù)的系統(tǒng)

Group:一個特殊的系統(tǒng),用來給系統(tǒng)做分類或者改變系統(tǒng)的執(zhí)行順序

1)World

構(gòu)造函數(shù)

World(string) 創(chuàng)建一個名字為string的新世界

靜態(tài)變量

World.DefaultGameObjectInjectionWorld 返回默認(rèn)世界
World.All 返回所有世界的集合

成員變量

World.Name 獲得該世界的名字
World.Systems 返回當(dāng)前世界的所有系統(tǒng)

成員函數(shù)

World.Dispose() 銷毀世界
World.GetOrCreateSystem<T>() 尋找世界里有沒有該系統(tǒng),若沒有重新創(chuàng)建一個
World.AddSystem<T>(T:ComponentSystemBase) 添加系統(tǒng)
World.DestroySystem(ComponentSystemBase) 刪除系統(tǒng)
World.GetExistingSystem<T>() 獲得該系統(tǒng)

2)System

系統(tǒng)包括:SystemBase,ComponentSystem,JobComponentSystem,其中ComponentSystem只能在主線程上運(yùn)行,JobComponentSytem可以提供多線程,但是需要手動管理JOB依賴,容易出錯,SystemBase可以兼容以上兩種,unity推薦使用SystemBase來進(jìn)行管理

(1)三種系統(tǒng)聲明

ComponentSystem

//DataSystem.cs
//數(shù)據(jù)系統(tǒng)
using UnityEngine;
using Unity.Entities;

public class DataSystem : ComponentSystem
{
    /// <summary>
    /// 相當(dāng)于update
    /// </summary>
    protected override void OnUpdate()
    {
        //獲取所有DataCompoent類
        Entities.ForEach((ref DataComponent datacomponent) =>
        {
            Debug.Log(datacomponent.printData);
        });
    }
}

JobSytem和Burst編譯器優(yōu)化性能

//JobSystem.cs
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
using Unity.Entities;

public class JobSystem : JobComponentSystem
{
    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        //使用JobSystem的方法修改物體的角度,WithBurst()用上Burst編譯器,Schedule用上JobSystem
        JobHandle tempJobHandle = Entities.ForEach((ref RotationEulerXYZ rotation) =>
        {
            rotation.Value = new float3(0, 45, 0);
        }).WithBurst().Schedule(inputDeps);

        return tempJobHandle;
    }
}

?SystemBase

//SystemBaseTest.cs
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;

public class SystemBaseTest : SystemBase
{
    protected override void OnUpdate()
    {
        Entities.ForEach((ref Translation trans) =>
        {
            trans.Value = new float3(1, 1, 1);
        }).Schedule();
    }
}
?(2)系統(tǒng)的生命周期

OnCreate->OnStartRunning->OnUpdate->OnStopRunning->OnDestroy

//SystemBaseTest.cs
using Unity.Entities;

public class SystemBaseTest : SystemBase
{

    //創(chuàng)建時調(diào)用一次
    protected override void OnCreate()
    {

    }
    //開始運(yùn)行時調(diào)用一次
    protected override void OnStartRunning()
    {
        
    }
    //持續(xù)調(diào)用
    protected override void OnUpdate()
    {

    }
    //停止運(yùn)行時創(chuàng)建一次
    protected override void OnStopRunning()
    {
        
    }

    //摧毀時調(diào)用一次
    protected override void OnDestroy()
    {
        
    }
}
(3)系統(tǒng)對組件,實(shí)體的操控

1.World.EntityManager進(jìn)行操控

2.Sytem自帶方法

3.System成員變量Entites來訪問

(4)SystemBase對實(shí)體進(jìn)行修改等操作簡述
    EntityQuery entityQuery;
    //持續(xù)調(diào)用
    protected override void OnUpdate()
    {
        //ref :讀寫
        //in : 只讀
        Entities.ForEach((ref Translation trans, in DataComponent data) =>
        {
            Debug.Log(trans.Value + " " + data.printData);//在ECS里面少用unity里面的操作
        }).WithAll<DataComponent, Rotation>()//對含有DataCompoent,Rotation的實(shí)體進(jìn)行操作,可以對篩選的組件做限制,<>可以繼續(xù)添加
        .WithAll<DataComponent, Rotation>()//篩選只要包含這兩個組件當(dāng)中任何一個的實(shí)體,可以在<>繼續(xù)擴(kuò)展
        .WithNone<DataComponent>()//篩選不包含這個組件的實(shí)體,同樣可以擴(kuò)展
        .WithChangeFilter<DataComponent>() //對參數(shù)值發(fā)生變化的實(shí)體做篩選,可以擴(kuò)展
                                           //使用這個篩選里面的組件必須在ForEach()里進(jìn)行聲明,比如說in DataComponent data
        .WithSharedComponentFilter(new ShareComponent() { data = 3 })     //選出具有特定共享組件的實(shí)體
        .WithStoreEntityQueryInField(ref entityQuery) //將查詢結(jié)果存儲在一個變量上
        //.Run();           //在主線程上運(yùn)行
        //.Schedule();      //多開一個線程運(yùn)行
        .WithBurst()         //支持Burst編譯器
        .ScheduleParallel();    //多線程運(yùn)行,在Burst編譯器下運(yùn)行效果好
    }

?多線程訪問共享數(shù)據(jù)介紹

當(dāng)ECS開啟多線程時會涉及到對數(shù)據(jù)的讀寫沖突,假如說1號線程在讀,這時2號線程修改了數(shù)據(jù),這樣就會導(dǎo)致1號數(shù)據(jù)讀取異常。在傳統(tǒng)方法中Unity采用了鎖的方式來解決這個問題,但是在ECS中并不是這樣處理的。ECS提供了一個Native Container容器的方法,其中包含了四種容器,NativeArray,NativeHashMap,NativeMultiHashMap,NativeQueue這四個容器類似與c#的傳統(tǒng)容器,但是不同的是在創(chuàng)建這四種容器時會創(chuàng)建分配器(Temp,JobTemp,Persistent),這三個分配器生命周期Temp<JobTemp <Persistent,性能Temp > JobTemp > Persistent,Temp使用與1幀內(nèi)進(jìn)行銷毀,JobTemp適用于四幀內(nèi)進(jìn)行銷毀,Persistent適合長久存在

多線程訪問共享數(shù)據(jù)實(shí)操

NativeArray

方法1:通過WithDeallovateOnJobCompletion進(jìn)行釋放

    protected override void OnUpdate()
    {
        NativeArray<int> tempInt = new NativeArray<int>(5, Allocator.TempJob);
        Entities.ForEach((ref Translation trans, in DataComponent data) =>
        {
            tempInt[0] = 5;
        })
        .WithDeallocateOnJobCompletion(tempInt) //線程運(yùn)行完自動釋放
        .WithBurst()         //支持Burst編譯器
        .ScheduleParallel();    //多線程運(yùn)行,在Burst編譯器下運(yùn)行效果好
    }

?方法二:通過CompleteDependency將線程阻塞到CompleteDependency之前,只有線程完成后才可以通過

    protected override void OnUpdate()
    {
        NativeArray<int> tempInt = new NativeArray<int>(5, Allocator.TempJob);
        //ref :讀寫
        //in : 只讀
        Entities.ForEach((ref Translation trans, in DataComponent data) =>
        {
            tempInt[0] = 5;
        })
        .WithBurst()         //支持Burst編譯器
        .ScheduleParallel();    //多線程運(yùn)行,在Burst編譯器下運(yùn)行效果好

        CompleteDependency();
        tempInt.Dispose();//釋放
    }

Entites中對實(shí)體進(jìn)行操作

方法1:直接修改

    protected override void OnUpdate()
    {
        Entities.ForEach((Entity entity, in DataComponent data) =>
        {
            EntityManager.AddComponentData(entity, new DataComponent() { printData = 3 });
        })
        .WithStructuralChanges()  //修改實(shí)體時需要加上這個
        .WithoutBurst()
        .Run();
    }

?方法2:通過EntityCommandBuffer進(jìn)行修改,性能更高,推薦使用

    protected override void OnUpdate()
    {
        EntityCommandBuffer entityCommandBuffer = new EntityCommandBuffer(Allocator.TempJob);
        Entities.ForEach((Entity entity, in DataComponent data) =>
        {
            entityCommandBuffer.AddComponent(entity, new DataComponent() { printData = 3 });
        })
        .WithoutBurst()
        .Run();

        entityCommandBuffer.Playback(EntityManager); //在Foreach里設(shè)置命令,用這句代碼進(jìn)行執(zhí)行
        entityCommandBuffer.Dispose();
    }

?JobWithCode的使用

用法和Entities類似,很多函數(shù)功能名字相同

    protected override void OnUpdate()
    {
        Job.WithCode(() =>
        {

        })
        .Schedule();
    }
?(5)ComponentSystem和JobCompentSytem調(diào)用實(shí)體簡述

ComponentSystem中沒有JobWithCode只有Entities,且沒有限制修飾等其他操作

    protected override void OnUpdate()
    {
        Entities.ForEach((Entity entity) =>
        {

        });
    }

JobSystem中OnUpdate存在參數(shù)和返回值

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        JobHandle value = Entities.ForEach((Entity entity) =>
        { 
            
        }).Schedule(inputDeps);
        return value;
    }
(6)Job接口使用

Job相當(dāng)與一個線程

//JobTest.cs
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Burst;

public class JobTest : MonoBehaviour
{
    /// <summary>
    /// 一個Job代表一個線程
    /// </summary>
    [BurstCompile]  //使用Busrt編譯器
    public struct Job1 : IJob
    {
        public int i, j;
        public int result;
        public void Execute()
        {
            result = i * j;
        }
    }

    void Update()
    {
        NativeList<JobHandle> jobHandlesList = new NativeList<JobHandle>(Allocator.Temp);
        for (int i = 0;i <10;i++)
        {
            Job1 job1 = new Job1 { i = 6, j = 7 };
            JobHandle jobHandle = job1.Schedule();
            jobHandlesList.Add(jobHandle);
        }


        //阻塞線程,等待所有線程完成
        JobHandle.CompleteAll(jobHandlesList);

        jobHandlesList.Dispose();
    }
}

?運(yùn)行結(jié)果

Unity DOTS技術(shù),unity,游戲引擎

?上述代碼只創(chuàng)建了一個線程,那么我們?nèi)绾蝿?chuàng)建多個線程呢?我們可以通過一個容器將所有線程存儲起來進(jìn)行遍歷或者釋放

//JobTest.cs
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;

public class JobTest : MonoBehaviour
{
    /// <summary>
    /// 一個Job代表一個線程
    /// </summary>
    public struct Job1 : IJob
    {
        public int i, j;
        public int result;
        public void Execute()
        {
            result = i * j;
        }
    }

    void Update()
    {
        NativeList<JobHandle> jobHandlesList = new NativeList<JobHandle>(Allocator.Temp);
        for (int i = 0;i <10;i++)
        {
            Job1 job1 = new Job1 { i = 6, j = 7 };
            JobHandle jobHandle = job1.Schedule();
            jobHandlesList.Add(jobHandle);
        }

        //阻塞線程,等待所有線程完成
        JobHandle.CompleteAll(jobHandlesList);

        jobHandlesList.Dispose();
    }
}
?(7)ParallelJbob

如果場景里有很多物體,我們要修改物體每次都需要遍歷,而遍歷是unity中非常常用的操作,于是Unity設(shè)計了一個IJobParallelFor接口來解決這個問題

經(jīng)過測試,在場景中創(chuàng)建1000個物體并控制旋轉(zhuǎn),傳統(tǒng)方法幀率穩(wěn)定在50-60,使用上ParallelJob和Burst編譯器后幀率穩(wěn)定在230以上,性能提升非常明顯

//JobTest.cs
using System.Collections.Generic;
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Burst;
using Unity.Mathematics;

public class JobTest : MonoBehaviour
{
    public float interval;
    public GameObject cubePrefab;
    private List<GameObject> goList = new List<GameObject>();

    private void Start()
    {
        //在start函數(shù)中創(chuàng)建1000個物體
        Vector3 tempVector3 = new Vector3(-interval, 0, 0);
        for (int i = 0;i <100;i++)
        {
            for (int j = 0;j <10;j++)
            {
                GameObject tempCube = GameObject.Instantiate(cubePrefab);
                goList.Add(tempCube);

                tempVector3.x += interval;
                tempCube.transform.position = tempVector3;
            }
            tempVector3.x = -interval;
            tempVector3.y += interval;
        }
    }

    void Update()
    {
        ParallelJob parallelJob = new ParallelJob();
        NativeArray<float3> eulerAngles = new NativeArray<float3>(goList.Count,Allocator.TempJob);
        //初始化
        for (int i = 0;i < goList.Count;i++)
        {
            eulerAngles[i] = goList[i].transform.eulerAngles;
        }
        parallelJob.eulerAngles = eulerAngles;
        parallelJob.daltaTime = Time.deltaTime;

        //第二個參數(shù)是批處理數(shù)量,批處理計數(shù)控制你將獲得多少個Job
        //以及線程之間的工作量新分配的細(xì)化程度如何.
        //擁有較低的批處理數(shù)量,會使你在線程之間進(jìn)行更均勻的工作分配.
        //但是它會帶來一些開銷,因此在某先情況下,稍微增加批次數(shù)量會更好
        JobHandle jobHandle = parallelJob.Schedule(goList.Count, 10);
        jobHandle.Complete();
        
        //將更改的角度賦值給物體,控制物體旋轉(zhuǎn)
        for (int i = 0; i < goList.Count; i++)
        {
            goList[i].transform.eulerAngles = eulerAngles[i];
        }
        eulerAngles.Dispose();
    }

    [BurstCompile]
    public struct ParallelJob : IJobParallelFor
    {
        public NativeArray<float3> eulerAngles;
        public float daltaTime;
        /// <summary>
        /// 將創(chuàng)建好ParalelJob后,就會并行處理數(shù)組或者一些操作
        /// </summary>
        /// <param name="index"></param>
        public void Execute(int index)
        {
            //更改數(shù)組的角度
            eulerAngles[index] += new float3(0, 30 * daltaTime, 0);
        }
    }

}

3)Group

[UpdateInGroup(typeof(系統(tǒng)))] 用來給系統(tǒng)分類,默認(rèn)SimulationSystemGroup

注意:關(guān)于刪除系統(tǒng)的一個坑,刪除系統(tǒng)前需要將系統(tǒng)移除Group

//TestWorld.cs
using UnityEngine;
using Unity.Entities;

public class TestWorld : MonoBehaviour
{
    void Start()
    {
        World tempWorld = new World("new");
        //獲取默認(rèn)世界的一個系統(tǒng)
        DataSystem dataSystem = World.DefaultGameObjectInjectionWorld.GetExistingSystem<DataSystem>();
        //添加該系統(tǒng)到新世界
        tempWorld.AddSystem(dataSystem);
        //找到組
        InitializationSystemGroup group = World.DefaultGameObjectInjectionWorld.GetExistingSystem<InitializationSystemGroup>();
        //從組中移除系統(tǒng)
        group.RemoveSystemFromUpdateList(dataSystem);
        //銷毀系統(tǒng)
        tempWorld.DestroySystem(dataSystem);
    }
}

8.組件Component介紹

1)組件Component的添加修改刪除

添加

//為單個實(shí)體添加組件
//方法1
World.DefaultGameObjectInjectionWorld.EntityManager.AddComponent(tempEntity, typeof(DataComponent));
//方法2
World.DefaultGameObjectInjectionWorld.EntityManager.AddComponent<DataComponent>(tempEntity);
//批量添加組件
//方法1:通過NativeArray
World.DefaultGameObjectInjectionWorld.EntityManager.AddComponent<DataComponent>(tempNativeArray);
//方法2:通過EntityQuery
World.DefaultGameObjectInjectionWorld.EntityManager.AddComponent<DataComponent>(tempEntityQuery);
//為一個實(shí)體添加多個組件
World.DefaultGameObjectInjectionWorld.EntityManager.AddComponents(tempEntity,
            new ComponentTypes(typeof(DataComponent), typeof(RotationEulerXYZ)));

數(shù)據(jù)初始化

數(shù)據(jù)初始化有兩個方法,一是通過AddComponentData通過代碼在添加組件的同時初始化,二是為組件類添加[GenerateAuthoringComponent]特性,這樣該組件就可以被掛載在物體上通過Inspector面板賦值

World.DefaultGameObjectInjectionWorld.EntityManager.AddComponentData(entity, new DataComponent()
{
    printData = 5;
});

組件的獲取和修改

//組件獲取
RotationEulerXYZ rotationEulerXYZ = World.DefaultGameObjectInjectionWorld.EntityManager.GetComponentData<RotationEulerXYZ>(tempEntity);
//設(shè)置組件的值
World.DefaultGameObjectInjectionWorld.EntityManager.SetComponentData(tempEntity,
            new RotationEulerXYZ()
            {
                Value = new float3(1, 1, 1)
            });

組件的刪除

World.DefaultGameObjectInjectionWorld.EntityManager.RemoveComponent<RotationEulerXYZ>(tempEntity);
World.DefaultGameObjectInjectionWorld.EntityManager.RemoveComponent<RotationEulerXYZ>(tempEntityNativeArray);
World.DefaultGameObjectInjectionWorld.EntityManager.RemoveComponent<RotationEulerXYZ>(tempEntityQuery);
World.DefaultGameObjectInjectionWorld.EntityManager.RemoveComponent(tempEntityQuery,
                new ComponentTypes(typeof(RotationEulerXYZ)));

2)ShareComponent

在創(chuàng)建實(shí)體的時候我們可能創(chuàng)建的實(shí)體擁有的組件相同,而組件時繼承ICompoentData接口,相當(dāng)于聲明了兩個一模一樣的實(shí)體,為了避免這種情況提高性能,unity設(shè)計了一個ShareComponent組件。

ShareCompoent的簡單使用

聲明一個ShareComponent組件

//ShareComponent.cs
using Unity.Entities;
using System;
//添加ISharedComponentData接口,必須實(shí)現(xiàn)IEquatable:判斷相等接口
public struct ShareComponent : ISharedComponentData,IEquatable<ShareComponent>
{
    public int data;

    public bool Equals(ShareComponent other)
    {
        return data == other.data;
    }
    //Hash算法
    public override int GetHashCode()
    {
        int tempHash = 0;
        tempHash ^= data.GetHashCode();

        return tempHash;
    }
}

?聲明一個代理掛載在含有Convert To Entity組件的物體上

//ShareMono.cs
using UnityEngine;
using Unity.Entities;

public class ShareMono : MonoBehaviour, IConvertGameObjectToEntity
{
    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        dstManager.AddSharedComponentData(entity, new ShareComponent() { data = 5 });
    }
}

基本操作

//添加組件
World.DefaultGameObjectInjectionWorld.EntityManager.AddSharedComponentData(tempEntities);
//設(shè)置組件
World.DefaultGameObjectInjectionWorld.EntityManager.SetSharedComponentData(tempEntities,
            new ShareComponent() { data = 10 });
//刪除組件
World.DefaultGameObjectInjectionWorld.EntityManager.RemoveComponent<ShareComponent>(tempEntities);
//查找組件
ShareComponent shareComponent = World.DefaultGameObjectInjectionWorld.EntityManager.GetSharedComponentData<ShareComponent>(tempEntities);

注意1:使用共享組件時我們要盡量選擇哪些不會經(jīng)常變動的組件作為共享組件,因?yàn)樾薷膶?shí)體共享組件的值,會導(dǎo)致這個實(shí)體被移動到新的塊中,這種移動塊的操作是比較消耗時間的(修改普通組件的是是不會改變塊的實(shí)體)。共享實(shí)體可以節(jié)省內(nèi)存,特別是要創(chuàng)建大量相同物體時,也不要濫用,否則有可能降低效率

注意2:一旦修改了實(shí)體的共享組件的值,則該實(shí)體會被存放到一個新的塊中,因?yàn)樗墓蚕斫M件發(fā)生了變化,相當(dāng)于使用了新的共享組件

3)狀態(tài)組件

ECS系統(tǒng)中沒有回調(diào),這就意味著Entity銷毀時不會發(fā)出任何通知,我們?nèi)绻獙?shí)現(xiàn)一些銷毀后的操作就比較麻煩,所以unity設(shè)計了一個狀態(tài)組件ISystemStateComponentData,當(dāng)實(shí)體被銷毀時狀態(tài)組件不會被銷毀,所以我們就可以在Entity銷毀時在ISystemStateComponentData中留下一些實(shí)體銷毀的信息。ISystemStateComponentData需要手動進(jìn)行銷毀

//Statement.cs
using Unity.Entities;

public struct StateComponent : ISystemStateComponentData
{
    public int data;
}
//StateMono
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
public class StateMono : MonoBehaviour
{
    void Start()
    {   
        //創(chuàng)建一個實(shí)體,添加三個組件
        Entity tempEntity = World.DefaultGameObjectInjectionWorld.EntityManager.
            CreateEntity(typeof(StateComponent),typeof(RotationEulerXYZ),typeof(DataComponent));
        //刪除實(shí)體
        World.DefaultGameObjectInjectionWorld.EntityManager.DestroyEntity(tempEntity);
        //為StateCompent修改值
        World.DefaultGameObjectInjectionWorld.EntityManager.SetComponentData(tempEntity,
            new StateComponent() { data = 10 });
        //刪除StateCompoent后實(shí)體就被完全刪除了
        World.DefaultGameObjectInjectionWorld.EntityManager.RemoveComponent<StateComponent>(tempEntity);
    }
}

當(dāng)我們刪除實(shí)體操作沒有進(jìn)行的時候

Unity DOTS技術(shù),unity,游戲引擎

?可以從分析面板看出該實(shí)體掛在了三個組件

當(dāng)我們執(zhí)行刪除實(shí)體后

Unity DOTS技術(shù),unity,游戲引擎

?可以看出實(shí)體并沒有完全被刪除,上面添加了CleanupEntity組件代表未完全刪除實(shí)體,還保留了StateComponent組件用來保留一些數(shù)據(jù),我們可以通過更改StateComponent里面的數(shù)據(jù)來判斷該實(shí)體是否被銷毀。

如果要完全刪除實(shí)體,在刪除實(shí)體后再刪除StateCompoent,就能完全刪除.

4)BufferElement

介紹

上面我們說過一個Entity不能創(chuàng)建相同的組件,那如果我們想創(chuàng)建多個相同的組件怎么辦?unity設(shè)計了一個接口IBuffElementData(動態(tài)緩沖區(qū))來存儲很多組件,其中可以包含相同的,這個緩沖區(qū)可以類比與List集合

//BufferComponent.cs
using Unity.Entities;

[GenerateAuthoringComponent]
public struct BufferComponent : IBufferElementData
{
    public int data;
}

Unity DOTS技術(shù),unity,游戲引擎

Unity DOTS技術(shù),unity,游戲引擎

?Values里Element的值對應(yīng)的就是BufferComponent里的data,總共創(chuàng)建了3個data

可以看出運(yùn)行時該實(shí)體被添加了一個BufferComponent組件

通過[GenerateAuthoringComponent]特性的方法掛載組件,組件里面只能寫一個變量,如果我們想寫多個變量怎么辦,那我們只能自己寫代理了

//BufferMono.cs
using UnityEngine;
using Unity.Entities;

public class BufferMono : MonoBehaviour, IConvertGameObjectToEntity
{
    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        DynamicBuffer<BufferComponent> tempBuffer = dstManager.AddBuffer<BufferComponent>(entity);
        tempBuffer.Add(new BufferComponent() { data = 1,data2 = 3 });
        tempBuffer.Add(new BufferComponent() { data = 2,data2 = 5});
        tempBuffer.Add(new BufferComponent() { data = 3 });
    }
}

上述代碼往實(shí)體里面添加了三個相同的BuffeCompoent組件并且進(jìn)行了賦值

BufferElement常用操作

//BufferTest
using UnityEngine;
using Unity.Entities;

public class BufferTest : MonoBehaviour
{
    private void Start()
    {
        //創(chuàng)建一個實(shí)體
        Entity tempEntity = World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntity();
        //添加三個buffercomponent組件
        DynamicBuffer<BufferComponent> tempBuffer = World.DefaultGameObjectInjectionWorld.EntityManager.AddBuffer<BufferComponent>(tempEntity);
        tempBuffer.Add(new BufferComponent() { data = 1, data2 = 3 });
        tempBuffer.Add(new BufferComponent() { data = 2, data2 = 5 });
        tempBuffer.Add(new BufferComponent() { data = 3 });
        //獲得該實(shí)體的所有BufferComponent
        DynamicBuffer<BufferComponent> bufferComponents = World.DefaultGameObjectInjectionWorld.EntityManager.
            GetBuffer<BufferComponent>(tempEntity);
        //遍歷集合內(nèi)容
        foreach(var item in bufferComponents)
        {
            Debug.Log(item.data + ":" + item.data2);
        }
        //刪除第0個組件
        tempBuffer.RemoveAt(0);
        //插入新的組件
        tempBuffer.Insert(0, new BufferComponent() { data = 11, data2 = 12 });
    }
}

5)ChunkComponent介紹

作用與共享組件類似,區(qū)別是對塊組件修改時并不會像共享組件一樣創(chuàng)建一個新的組件

//ChunkCompoent.cs
using Unity.Entities;
using UnityEngine;

public class ChunkComponent : IComponentData
{
    public int data;
}
//ChunkTest.cs
using UnityEngine;
using Unity.Entities;

public class ChunkTest : MonoBehaviour
{

    void Start()
    {
        //創(chuàng)建原型
        EntityArchetype entityArchetype = World.DefaultGameObjectInjectionWorld.EntityManager.
            CreateArchetype(ComponentType.ChunkComponent(typeof(ChunkComponent)));
        //用原型創(chuàng)建實(shí)體
        Entity entity = World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntity(entityArchetype);
        //創(chuàng)建第二個實(shí)體
        World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntity(entityArchetype);
        //獲得ArchtypeChunk并且修改值
        ArchetypeChunk tempChunk = World.DefaultGameObjectInjectionWorld.EntityManager.GetChunk(entity);
        World.DefaultGameObjectInjectionWorld.EntityManager.SetChunkComponentData(tempChunk,
            new ChunkComponent() { data = 10 });
        //移除組件
        World.DefaultGameObjectInjectionWorld.EntityManager.RemoveChunkComponent<ChunkComponent>(entity);
        //獲得ChunkComponent
        World.DefaultGameObjectInjectionWorld.EntityManager.GetChunkComponentData<ChunkComponent>(tempChunk);
        //給實(shí)體添加ChunkComponent
        World.DefaultGameObjectInjectionWorld.EntityManager.AddChunkComponentData<ChunkComponent>(entity);
        //實(shí)體存不存在ChunkComponent
        World.DefaultGameObjectInjectionWorld.EntityManager.HasChunkComponent<ChunkComponent>(entity);
    }
}

9.總結(jié)

到這里DOTS的教學(xué)已經(jīng)完結(jié)了,下面附上一個我用于測試的實(shí)例

三.DOTS測試案例

案例1:1萬個小球下落

準(zhǔn)備工作

在Package Manager中安裝Unity Physics包,安裝好后重啟unity

制作小球預(yù)制體,掛載上Physics Shape(ECS中的碰撞器),Physics Body(ECS中的物理碰撞系統(tǒng)),Convert To Entity

Unity DOTS技術(shù),unity,游戲引擎

?設(shè)置Physics Shape的彈力值,Resitiution值越大彈力越大

在場景中掛載代碼,并在Inspector面板賦值

//SphereManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;

public class SphereManager : MonoBehaviour
{
    public GameObject spb;   //球體預(yù)制體
    public int nums;        //生成的球體數(shù)量
    public float interval;   //球體間隔比例
    private BlobAssetStore blobAssetStore;
    private void Start()
    {
        //將小球轉(zhuǎn)化為實(shí)體
        blobAssetStore = new BlobAssetStore();
        GameObjectConversionSettings setting = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, blobAssetStore);
        Entity entity = GameObjectConversionUtility.ConvertGameObjectHierarchy(spb, setting);

        Translation translation = new Translation();
        //生成1萬個小球
        for (int i = 0;i < nums;i++)
        {
            EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
            Entity spbEntity = entityManager.Instantiate(entity);
            translation.Value = new float3(i % 16 *interval + UnityEngine.Random.Range(-0.1f,0.1f) ,
                i / (16 * 16) * interval + UnityEngine.Random.Range(-0.1f, 0.1f), 
                i / 16 % 16 * interval + UnityEngine.Random.Range(-0.1f, 0.1f));
            entityManager.SetComponentData(spbEntity, translation);
        }


    }

    private void OnDestroy()
    {
        blobAssetStore.Dispose();
    }
}

Unity DOTS技術(shù),unity,游戲引擎

效果圖 ,運(yùn)行時記得開Burst編譯器優(yōu)化性能

?Unity DOTS技術(shù),unity,游戲引擎

?案例2:魚群移動

10000個魚的魚群移動,幀率穩(wěn)定在150幀

//FishManager.cs
using System.Collections;
using System.Collections.Generic;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;

public class FishManager : MonoBehaviour
{
    public GameObject fishPrb;
    public int sum,radius;
    private BlobAssetStore blobAssetStore;
    public Transform center;
    EntityManager entityManager;

    private void Start()
    {
        //將小球轉(zhuǎn)化為實(shí)體
        blobAssetStore = new BlobAssetStore();
        GameObjectConversionSettings setting = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, blobAssetStore);
        Entity fishentity = GameObjectConversionUtility.ConvertGameObjectHierarchy(fishPrb, setting);
        Translation translation = new Translation();
        entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
        //生產(chǎn)球形魚群
        for (int i = 0;i < sum;i++)
        {          
            Entity fish = entityManager.Instantiate(fishentity);
            Vector3 tempDir = Vector3.Normalize(new Vector3(UnityEngine.Random.Range(-1f, 1f),
                UnityEngine.Random.Range(-1f, 1f),
                UnityEngine.Random.Range(-1f, 1f))) * radius;

            Vector3 final = center.position + tempDir;
            translation.Value = new float3(final.x, final.y, final.z);
            entityManager.SetComponentData(fish, translation);

            //設(shè)置每個魚的位置
            Rotation rotation = new Rotation();
            rotation.Value = quaternion.LookRotationSafe(tempDir, math.up());
            entityManager.SetComponentData(fish, rotation);
        }

    }

    private void OnDestroy()
    {
        blobAssetStore.Dispose();
    }
}
//TargetComponent.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;

[GenerateAuthoringComponent]
public struct TargetComponent : IComponentData
{
}
//FishComponent.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;

[GenerateAuthoringComponent]
public struct FishComponent : IComponentData
{
    public float fishMoveSpeed, fishRotationSpeed;
    public float targetDirWeight, farAwayWeight, centerWeight;
}
//BoidMoveSystem.cs
using System.Collections;
using System.Collections.Generic;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;

public class BoidMoveSystem : SystemBase
{

    protected override void OnUpdate()
    {
        float3 tempSumPos = float3.zero;
        float3 tempCenterPos = float3.zero;
        float3 tempTargetPos = float3.zero;
        float tempTime = Time.DeltaTime;
        int tempSumFish = 0;
        Entities.ForEach((Entity pEntity, ref Translation translation,ref Rotation rotation, ref FishComponent pfishComponent) =>
        {
            tempSumPos += translation.Value;
            tempSumFish++;
        }).Run();
        Entities.ForEach((Entity pEntity, ref Translation translation, ref Rotation rotation, ref TargetComponent targetComponent) =>
        {
            tempTargetPos = translation.Value;
        }).Run();
        tempCenterPos = tempSumPos / tempSumFish;

        Entities.ForEach((Entity pEntity, ref Translation translation, ref Rotation rotation, ref LocalToWorld pLocalToWorldComponentData, ref FishComponent pfishComponent) =>
        {
            pLocalToWorldComponentData.Value = float4x4.TRS(translation.Value,rotation.Value,new float3(1, 1, 1));

            float3 tempTargetDir = math.normalize(tempTargetPos - pLocalToWorldComponentData.Position);
            float3 tempFarAwayDir = math.normalize(tempSumFish * pLocalToWorldComponentData.Position - tempSumPos);
            float3 tempCenterDir = math.normalize(tempCenterPos - pLocalToWorldComponentData.Position);
            float3 tempSumDir = math.normalize(tempTargetDir * pfishComponent.targetDirWeight +
                                               tempFarAwayDir * pfishComponent.farAwayWeight +
                                               tempCenterDir * pfishComponent.centerWeight);

            float3 tempOffsetRotation = math.normalize(tempSumDir - pLocalToWorldComponentData.Forward);
            pLocalToWorldComponentData.Value = float4x4.TRS(pLocalToWorldComponentData.Position + pLocalToWorldComponentData.Forward * pfishComponent.fishMoveSpeed * tempTime,
                                     quaternion.LookRotationSafe(pLocalToWorldComponentData.Forward + tempOffsetRotation * pfishComponent.fishRotationSpeed * tempTime, math.up()),
                                     new float3(1, 1, 1));
            translation.Value = pLocalToWorldComponentData.Position;
            rotation.Value = pLocalToWorldComponentData.Rotation;

        }).ScheduleParallel();
    }
}

Unity DOTS技術(shù),unity,游戲引擎

?文章來源地址http://www.zghlxwxcb.cn/news/detail-743338.html

到了這里,關(guān)于Unity DOTS技術(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • DOTS介紹+Unity DOTS-MAN小游戲項(xiàng)目實(shí)戰(zhàn)

    DOTS介紹+Unity DOTS-MAN小游戲項(xiàng)目實(shí)戰(zhàn)

    DOTS是Unity在17年左右提出的一個概念,其核心是ECS。 提示:以下是本篇文章正文內(nèi)容,下面案例可供參考 全稱:(Multi-Thread)Data-Oriented-Tech-Stack (多線程式)數(shù)據(jù)導(dǎo)向型技術(shù)堆棧 實(shí)體組件系統(tǒng)(ECS) - 提供使用面向數(shù)據(jù)的方法進(jìn)行編碼的框架。在Unity中它通過Entities軟件包進(jìn)行分發(fā),

    2023年04月13日
    瀏覽(27)
  • Unity DOTS技術(shù)

    Unity DOTS技術(shù)

    目錄 一.概述 二.DOTS詳解 1.開發(fā)環(huán)境搭建 2.簡單ECS程序 ?2.調(diào)試功能 3.常用API ?4.系統(tǒng)之間的互相干擾 5.實(shí)體Entity的創(chuàng)建查找刪除 6.使用批處理Gpu Instancing優(yōu)化性能 7.World,System,Group 1)World 2)System 3)Group 8.組件Component介紹 1)組件Component的添加修改刪除 2)ShareComponent 3)狀態(tài)

    2024年02月05日
    瀏覽(13)
  • Unity項(xiàng)目技術(shù)方案Dots架構(gòu)方案簡介

    Unity項(xiàng)目技術(shù)方案Dots架構(gòu)方案簡介

    DOTS全稱是Data-Oriented Tech Stack,翻譯過來就是多線程式數(shù)據(jù)導(dǎo)向型技術(shù)堆棧(DOTS),它由任務(wù)系統(tǒng)(Job System)、實(shí)體組件系統(tǒng)(ECS)、Burst Compiler編譯器三部分組成。 ECS + JobSystem + BurstCompile = 高性能 + 多線程 + ?編譯層面優(yōu)化 DOTS保證相同類型組件在內(nèi)存中都是順序排列,極大

    2023年04月09日
    瀏覽(21)
  • 【Unity】十萬人同屏尋路? 基于Dots技術(shù)的多線程RVO2避障

    博文介紹了最基本的實(shí)現(xiàn)原理,有些老板懶得折騰,所以特意熬了幾個禿頭的夜把RVO、BRG、GPU動畫、海量物體目標(biāo)搜索等高度封裝成了開箱即用的插件。 劃重點(diǎn)??!此方案是繞開Entities(ECS),不用寫一行ECS代碼,現(xiàn)有MonoBehavior開發(fā)工作流享受Entities渲染的性能。已有項(xiàng)目也能使

    2024年02月08日
    瀏覽(23)
  • 十八、Unity游戲引擎入門

    十八、Unity游戲引擎入門

    1、下載 ?? ?首先需要下載Unity Hub,下載網(wǎng)址:https://unity.com/cn。 ?? ?然后在其中下載Unity編輯器并安裝,可選擇最新版本。 ?? ?接著需要選擇適合的開發(fā)環(huán)境,例如Android Studio或Xcode,以便進(jìn)行手機(jī)游戲開發(fā)。在安裝完Unity后,需要根據(jù)項(xiàng)目需求下載對應(yīng)的模塊和插件,例

    2024年02月16日
    瀏覽(117)
  • 使用團(tuán)結(jié)引擎開發(fā)Unity 3D射擊游戲

    使用團(tuán)結(jié)引擎開發(fā)Unity 3D射擊游戲

    ? ? ? ?本案例是初級案例,意在引導(dǎo)想使用unity的初級開發(fā)者能較快的入門,體驗(yàn)unity開發(fā)的方便性和簡易性能。 ? ? ? 本次我們將使用團(tuán)結(jié)引擎進(jìn)行開發(fā),幫助想體驗(yàn)團(tuán)結(jié)引擎的入門開發(fā)者進(jìn)行較快的環(huán)境熟悉。 ? ? ?本游戲是一個俯視角度的射擊游戲。主角始終位于屏幕

    2024年01月19日
    瀏覽(110)
  • Unity、UE、Cocos游戲開發(fā)引擎的區(qū)別

    Unity、Unreal Engine(UE)和Cocos引擎是三個常用的游戲開發(fā)引擎,它們在功能和特性上有一些區(qū)別。以下是它們之間的主要區(qū)別: 編程語言:Unity使用C#作為主要的編程語言,開發(fā)者可以使用C#腳本進(jìn)行游戲邏輯編寫。Unreal Engine主要使用C++作為編程語言,但也支持藍(lán)圖系統(tǒng),允許

    2024年02月22日
    瀏覽(99)
  • Unity vs Godot :哪個游戲引擎更適合你?

    Unity vs Godot :哪個游戲引擎更適合你?

    游戲引擎的選擇對開發(fā)過程和最終產(chǎn)品質(zhì)量有著重大影響。近年來,Godot和Unity這兩款引擎受到廣泛關(guān)注。本文將從多個維度對兩者進(jìn)行比較,以期為開發(fā)者提供正確的選擇建議。 Godot和Unity都有各自的優(yōu)勢,沒有絕對的好壞之分。Godot開源免費(fèi),上手簡單,更適合2D和小型游戲

    2024年01月23日
    瀏覽(106)
  • 30分鐘了解所有引擎組件,132個Unity 游戲引擎組件速通!【收藏 == 學(xué)會】

    30分鐘了解所有引擎組件,132個Unity 游戲引擎組件速通!【收藏 == 學(xué)會】

    ?? 博客主頁:https://xiaoy.blog.csdn.net ?? 本文由 呆呆敲代碼的小Y 原創(chuàng),首發(fā)于 CSDN ?? ?? 學(xué)習(xí)專欄推薦:Unity系統(tǒng)學(xué)習(xí)專欄 ?? 游戲制作專欄推薦:游戲制作 ??Unity實(shí)戰(zhàn)100例專欄推薦:Unity 實(shí)戰(zhàn)100例 教程 ?? 歡迎點(diǎn)贊 ?? 收藏 ?留言 ?? 如有錯誤敬請指正! ?? 未來很長

    2024年02月11日
    瀏覽(130)
  • Unity Physics2D 2d物理引擎游戲 筆記

    Unity Physics2D 2d物理引擎游戲 筆記

    2d 材質(zhì) 里面可以設(shè)置 摩擦力 和 彈力 Simulated:是否在當(dāng)前的物理環(huán)境中模擬,取消勾選該框類似于Disable Rigidbody,但使用這個參數(shù)更加高效,因?yàn)镈isable會銷毀內(nèi)部產(chǎn)生的GameObject,而取消勾選Simulated只是禁用。 Kinematic 動力學(xué)剛體 動力學(xué)剛體不受重力和力的影響,而受用戶的

    2023年04月24日
    瀏覽(93)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包