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

[Unity命名空間教程]介紹Unity新自帶的命名空間UnityEngine.Pool

這篇具有很好參考價(jià)值的文章主要介紹了[Unity命名空間教程]介紹Unity新自帶的命名空間UnityEngine.Pool。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

學(xué)習(xí)目標(biāo):

? 大家都知道在一些游戲中常常要創(chuàng)建大量的游戲?qū)ο?,如果這些對象長期占用一些內(nèi)存而沒有觸發(fā)垃圾回收機(jī)制(以下簡稱GC)或者過于頻繁的觸發(fā)GC就會導(dǎo)致游戲的幀數(shù)暴跌,在移動設(shè)備直接造成卡死的現(xiàn)象,那引用對象池的概念,能讓這些游戲?qū)ο笤趧傞_始的時(shí)候就被初始實(shí)例化而不會在游戲中頻繁生成也不用觸發(fā)垃圾回收機(jī)制,相當(dāng)于對性能極大的提升,這些都是Unity非常經(jīng)典的模式,那么在Unity2021.2以后的版本Unity終于自己創(chuàng)了一個(gè)新的命名空間UnityEngine.Pool不用玩家再自己造輪子了,下面跟著B站一位大佬Up學(xué)習(xí)了如何引用該命名空間,

這里貼個(gè)連接:

【Unity 2021】對象池API | 對象池模式 | Unity提高教程 | Object Pool_嗶哩嗶哩_bilibili

Github:GitHub - https://github.com/AtCloudStudio/UnityObjectPoolTutorial

官方的API:Unity - Scripting API: ObjectPool<T0>?


學(xué)習(xí)內(nèi)容:

?進(jìn)入官網(wǎng)的API可以看到這個(gè)命名空間包含了多個(gè)數(shù)據(jù)結(jié)構(gòu)的對象池,

[Unity命名空間教程]介紹Unity新自帶的命名空間UnityEngine.Pool

這里就用最常用的ObjectPool<T>吧,

然后選擇一個(gè)2021.2之后的版本,我用的是長期支持的LTS3.8[Unity命名空間教程]介紹Unity新自帶的命名空間UnityEngine.Pool

創(chuàng)建一個(gè)項(xiàng)目進(jìn)入后然后把素材導(dǎo)進(jìn)來,如果你想自己動手做的話Scripts里面的就別放進(jìn)來了,然后把無法識別的腳本的組件都刪了,因?yàn)槲覀円獎邮指罄凶鲆槐椋?/p>

?我們先創(chuàng)建一個(gè)名字叫Gem的腳本,然后掛載到Gem Base的父預(yù)制體,這樣其它的寶石預(yù)制體都會掛載他。

創(chuàng)建一個(gè)委托以及一個(gè)計(jì)時(shí)器要來記錄什么時(shí)候執(zhí)行委托,當(dāng)碰到標(biāo)簽為Floor的地板后就觸發(fā)開始計(jì)時(shí)器的bool

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Gem : MonoBehaviour
{
    [SerializeField] private float lifeAfterLanding = 2f; //著陸后過了兩秒就自動消除
    private float deactiveTimer;
    private bool hasLanded;
    System.Action<Gem> deactiveAcion;
   
    void Update()
    {
        if (!hasLanded)
            return;
        deactiveTimer += Time.deltaTime;
        if(deactiveTimer >= lifeAfterLanding)
        {
            deactiveTimer = 0;
            deactiveAcion.Invoke(this); // 執(zhí)行這個(gè)委托
        }

    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Floor"))
        {
            hasLanded = true;
        }
    }

    public void SetDeactiveAction(System.Action<Gem> deactiveAcion)
    {
        this.deactiveAcion = deactiveAcion;
    }
}

再創(chuàng)建一個(gè)叫GemSpawnNormalVersion的腳本

這個(gè)用來控制生成寶石的。別忘了在生成寶石的函數(shù)最后訂閱這個(gè)委托并給它要執(zhí)行的事件

using UnityEngine;

public class GemSpawnNormalVersion : MonoBehaviour
{
    [SerializeField] private Gem[] gemPrefabs;
    [SerializeField] private int spawnAmounts = 50;
    [SerializeField] private float gemSpawnInterval;
    private float gemSpawnTimer;

    private void Update()
    {
        gemSpawnTimer += Time.deltaTime;

        if(gemSpawnTimer >= gemSpawnInterval)
        {
            gemSpawnTimer = 0;
            Spawn();
        }
    }

    private void Spawn()
    {
        for (int i = 0; i < spawnAmounts; i++)
        {
            var randomIndex = Random.Range(0, gemPrefabs.Length);
            var prefab = gemPrefabs[randomIndex]; //隨機(jī)生成某種類型的寶石
            var gem = Instantiate(prefab, transform); //把這個(gè)寶石生成器對象作為生成寶石的腳本

            gem.transform.position = transform.position + Random.insideUnitSphere * 2;
            gem.SetDeactiveAction(delegate { Destroy(gameObject);});
        }
    }
}

再窗口配置好后,

[Unity命名空間教程]介紹Unity新自帶的命名空間UnityEngine.Pool


[Unity命名空間教程]介紹Unity新自帶的命名空間UnityEngine.Pool?

?這時(shí)候運(yùn)行游戲,沒問題12鐘寶石隨機(jī)生成,在地面過了兩秒后觸發(fā)垃圾回收機(jī)制GC,但你的電腦有沒有紅溫呢,反正我筆記本電腦溫度高的一批,我就不截圖了怕我電腦燒了。

?這時(shí)候就到了使用對象池的時(shí)間了

?我們創(chuàng)建一個(gè)GemPool的腳本掛載上去。

請結(jié)合代碼看我的解釋,我們引用新命名空間,using UnityEngine.Pool;

然后創(chuàng)建一個(gè)ObjectPool<T>泛型T里面是Gem類,然后再Awake函數(shù)初始化,這里需要幾個(gè)委托函數(shù),第一個(gè)用于先創(chuàng)建也就是該類型的游戲?qū)ο筮@里我們是Gem類的要先實(shí)例化!,然后返回這個(gè)游戲?qū)ο?,第二個(gè)是用于當(dāng)我們調(diào)用對象池的Get函數(shù)索要執(zhí)行的功能也就是啟用這個(gè)對象,第三個(gè)則是調(diào)用Release()也就是返回這個(gè)對象池要執(zhí)行的功能,第四個(gè)則是當(dāng)對象池尺寸不足以容納這么多游戲?qū)ο蟮臅r(shí)候就會銷毀無法返回對象池的游戲?qū)ο螅谖鍌€(gè)則是一個(gè)bool的,用來自動檢測對象池是否超尺寸,由于這個(gè)對象池本質(zhì)是一個(gè)棧的數(shù)據(jù)結(jié)構(gòu),所以當(dāng)尺寸小于實(shí)際產(chǎn)生的游戲?qū)ο螅蜁筛嗟挠螒驅(qū)ο髞頂U(kuò)大尺寸(但會產(chǎn)生GC),第六個(gè)則是對象池的默認(rèn)尺寸,第七個(gè)是對象池能容忍的最大尺寸。

[Unity命名空間教程]介紹Unity新自帶的命名空間UnityEngine.Pool

?

using UnityEngine;
using UnityEngine.Pool;

public class GemPool : MonoBehaviour
{
    [SerializeField] private Gem prefab;
    [SerializeField] private int minCapcitySize =10;//這兩個(gè)變量用來定義對象池也就是棧的存儲空間
    [SerializeField] private int maxCapcitySize = 100;
    [SerializeField] private int activeCount => pool.CountActive;
    [SerializeField] private int inacitveCount => pool.CountInactive;
    [SerializeField] private int totalCount => pool.CountAll;
    ObjectPool<Gem> pool;
    //對象池僅僅發(fā)生激活和非激活狀態(tài)之間的切換,只有調(diào)用ObjectPool.Clear()或者Dispose()才會清除對象池中的元素
    private void Awake()
    {
        pool = new ObjectPool<Gem>(OnCreatePoolItem, OnGetPoolItem, OnReleasePoolItem, OnDestoryPoolItem, true, minCapcitySize, maxCapcitySize);
    }
    private void Update()
    {
        var gem = pool.Get();
        gem.transform.position = transform.position + Random.insideUnitSphere * 2;
    }

    private void OnDestoryPoolItem(Gem obj)
    {
        Destroy(obj.gameObject);
    }

    private void OnReleasePoolItem(Gem obj)
    {
        obj.gameObject.SetActive(false);
    }

    private void OnGetPoolItem(Gem obj)
    {
        obj.gameObject.SetActive(true);
    }

    private Gem OnCreatePoolItem()
    {
        var gem = Instantiate(prefab, transform);
        gem.SetDeactiveAction(delegate { pool.Release(gem); }); //在實(shí)例化寶石后再調(diào)用release函數(shù)回收這個(gè)寶石

        return gem;
    }
}

別忘了調(diào)用委托SetDeactiveAction先讓實(shí)例化的對象返回對象池中。

?

[Unity命名空間教程]介紹Unity新自帶的命名空間UnityEngine.Pool

這里隨機(jī)選擇一個(gè)預(yù)制體,運(yùn)行游戲可以看到有一部分就在禁用狀態(tài)。

那么我們怎么推廣所有寶石預(yù)制體呢?很簡單,只需要用數(shù)組給Gem類加個(gè)數(shù)組用foreach依次生成即可,那對于游戲中所有要用到的預(yù)制體呢,他們可沒有用Gem這個(gè)類。

這樣我們要造新輪子寫個(gè)基類讓所有要用到對象池的游戲?qū)ο罄^承使用即可,

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;

public class BasePool<T> : MonoBehaviour where T : Component
{
    [SerializeField] protected T prefab;
    [SerializeField] int minSize =100;
    [SerializeField] int maxSize = 500;
    public int activeCount => pool.CountActive;
    public int inacitveCount => pool.CountInactive;
    public int totalCount => pool.CountAll;

    ObjectPool<T> pool;

    public void Initialize(bool checkPoolSize = true)
    {
        pool = new ObjectPool<T>(OnCreatePoolItem, OnGetPoolItem, OnReleasePoolItem, OnDestoryPoolItem, checkPoolSize, minSize, maxSize);
    }

    protected virtual void OnDestoryPoolItem(T obj)
    {
        Destroy(obj.gameObject);
    }

    protected virtual void OnReleasePoolItem(T obj)
    {
        obj.gameObject.SetActive(false);
    }

    protected virtual void OnGetPoolItem(T obj)
    {
        obj.gameObject.SetActive(true);
    }

    protected virtual T OnCreatePoolItem() => Instantiate(prefab, transform);

    public void Get() => pool.Get();
    public void Release(T obj) => pool.Release(obj);

    public void Clear() => pool.Clear();
    
}

可能你對這些Public的函數(shù)Lamada表達(dá)式后半部分的功能不太了解,其實(shí)官方API都有標(biāo)明他們的功能

這樣回到GemPool的腳本只需要繼承這個(gè)類再重寫兩個(gè)函數(shù)即可?

using UnityEngine;
using UnityEngine.Pool;

public class GemPool : BasePool<Gem>
{
    
    private void Awake()
    {
        Initialize();
    }
    private void Update()
    {
        Get();
    }
    protected override Gem OnCreatePoolItem()
    {
        var gem = base.OnCreatePoolItem();
        gem.SetDeactiveAction(delegate { Release(gem); }); //在實(shí)例化寶石后再調(diào)用release函數(shù)回收這個(gè)寶石

        return gem;
    }

    protected override void OnGetPoolItem(Gem gem)
    {
        base.OnGetPoolItem(gem);
        gem.transform.position = transform.position + Random.insideUnitSphere * 2;
    }

    public void SetGemPrefab(Gem prefab)
    {
        this.prefab = prefab;
    }
}

最后的擴(kuò)展:

其實(shí)這還不算是最好的性能,當(dāng)游戲?qū)ο筮€是太多的時(shí)候,游戲幀數(shù)就會慢慢降到個(gè)位數(shù)直到卡死,接下來要介紹更好的運(yùn)用ObjectPool性能

創(chuàng)建一個(gè)新腳本叫GemSpawnNormalVersion

首先是Gem【】數(shù)組用來管理每一種寶石的生成,在Start函數(shù)中為他們每個(gè)創(chuàng)造一個(gè)父對象poolHolder,這樣方便管理各個(gè)種類的寶石,然后直到poolHolder掛載GemPool腳本并且為這個(gè)腳本上設(shè)置好它專屬的Gem類(不然為空會報(bào)錯)就可以激活它了,別忘了賦在我們的鏈表List<GemPool>上,最后在Spawn函數(shù)中,我們隨機(jī)選擇某種類型的寶石并在鏈表中取出來,并調(diào)用它GemPool腳本的Get()函數(shù)。

[Unity命名空間教程]介紹Unity新自帶的命名空間UnityEngine.Pool

?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GemSpawnPoolVersion : MonoBehaviour
{
    [SerializeField] private Gem[] gemPrefabs;
    [SerializeField] private int spawnAmounts =50;
    [SerializeField] private float gemSpawnInterval;
    private float gemSpawnTimer;

    List<GemPool> gemPools = new List<GemPool>();
    private void Start()
    {
        foreach (var gemPrefab in gemPrefabs)
        {
            var poolHolder = new GameObject($"Pool:{gemPrefab.name}");

            poolHolder.transform.parent = transform;
            poolHolder.transform.position = transform.position;
            poolHolder.SetActive(false);

            var pool = poolHolder.AddComponent<GemPool>();

            pool.SetGemPrefab(gemPrefab);
            poolHolder.SetActive(true);
            gemPools.Add(pool);
        }
    }

    private void Update()
    {
        gemSpawnTimer += Time.deltaTime;

        if (gemSpawnTimer >= gemSpawnInterval)
        {
            gemSpawnTimer = 0;
            Spawn();
        }
    }

    private void Spawn()
    {
        for (int i = 0; i < spawnAmounts; i++)
        {
            var randomIndex = Random.Range(0, gemPrefabs.Length);
            var pool = gemPools[randomIndex];
            pool.Get();
        }
    }
}

[Unity命名空間教程]介紹Unity新自帶的命名空間UnityEngine.Pool

?掛載后運(yùn)行,無論你的SpawnAmounts調(diào)的多離譜都會幀數(shù)穩(wěn)定很多了。(30幀左右吧)

這樣性能就能妥善解決了大性能小號穩(wěn)定


學(xué)習(xí)產(chǎn)出:

學(xué)習(xí)了怎么使用新命名空間UnityEngine.Pool,并且了探討了更加優(yōu)化版本的正確對象池使用。文章來源地址http://www.zghlxwxcb.cn/news/detail-410198.html

到了這里,關(guān)于[Unity命名空間教程]介紹Unity新自帶的命名空間UnityEngine.Pool的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(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)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

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

相關(guān)文章

  • unity學(xué)習(xí)(16)——服務(wù)器組裝(3)命名空間問題

    unity學(xué)習(xí)(16)——服務(wù)器組裝(3)命名空間問題

    using GameServer.logic; using GameServer.NetModel; 代碼中這兩句存在命名空間的引用問題,c#和c++不一樣,用的的using和命名空間,之前的慣性思維都是include和文件路徑。 錯誤:直接把逆向文件夾粘到項(xiàng)目文件夾中,這樣做vs的資源管理器根本沒反應(yīng): 正確:在資源管理器中點(diǎn)擊GameSe

    2024年02月21日
    瀏覽(23)
  • 【C++雜貨鋪】C++介紹、命名空間、輸入輸出

    【C++雜貨鋪】C++介紹、命名空間、輸入輸出

    ?C語言是 結(jié)構(gòu)化 和 模塊化 的語言,適合處理 較小規(guī)模 的程序。對于復(fù)雜的問題,規(guī)模較大的程序,需要高度的抽象和建模時(shí),C語言則不合適。為了解決軟件危機(jī),20世紀(jì)80年代,計(jì)算機(jī)界提出了 OOP (object oriented programming: 面向?qū)ο?)思想,支持面向?qū)ο蟮某绦蛟O(shè)計(jì)語言應(yīng)

    2024年02月16日
    瀏覽(31)
  • 【C++初階】C++入門——C++介紹、命名空間、輸入輸出

    【C++初階】C++入門——C++介紹、命名空間、輸入輸出

    ?C語言是 結(jié)構(gòu)化 和 模塊化 的語言,適合處理 較小規(guī)模 的程序。對于復(fù)雜的問題,規(guī)模較大的程序,需要高度的抽象和建模時(shí),C語言則不合適。為了解決軟件危機(jī),20世紀(jì)80年代,計(jì)算機(jī)界提出了 OOP (object oriented programming: 面向?qū)ο?)思想,支持面向?qū)ο蟮某绦蛟O(shè)計(jì)語言應(yīng)

    2024年02月11日
    瀏覽(16)
  • Unity導(dǎo)入google.protobuf失敗,無法找到google命名空間

    Unity導(dǎo)入google.protobuf失敗,無法找到google命名空間

    1.剛開始把protobuf的文件夾直接從其他項(xiàng)目里(unity2021)里復(fù)制到unity(2020)版本,當(dāng)時(shí)報(bào)錯protobuf.dll的依賴項(xiàng)system.memory版本不對。 2.沒有使用原來的protobuf文件了。使用vs2019的NuGet管理包來下載Google.Protobuf ,仍然報(bào)錯找不到Google 3.找到Google后,報(bào)錯說該platform存在多個(gè)Assembly。 1.解

    2024年01月16日
    瀏覽(41)
  • unity的C#學(xué)習(xí)——命名空間的定義與訪問、using語句的常見用法

    在C#中,命名空間(Namespace)是一種 將類和其他相關(guān)類型組織在一起的方式 ??梢詫⒚臻g看作是一個(gè)容器,用于管理和組織類和其他類型。通過將相關(guān)的類型組織在一起,可以使代碼更加清晰和易于維護(hù)。 命名空間的主要目的是為了避免名稱沖突,使得開發(fā)人員可以 使

    2024年02月11日
    瀏覽(27)
  • Unity報(bào)錯命名空間System.IO.Ports不存在解決方法SerialPort

    Unity報(bào)錯命名空間System.IO.Ports不存在解決方法SerialPort

    嘗試解決方法:工具–Nuget包管理器(N)–管理解決方案的Nuget程序包(N)搜索SerialPort,重新下載System.IO.Ports,報(bào)錯仍然存在; 發(fā)現(xiàn)問題在于設(shè)定,使用這個(gè)包的時(shí)候必須將Project Settings?– Player?– Other settings?– Configuration?– API Compatibility Level 從 .NET standard 2.1 改成 .NET

    2024年04月17日
    瀏覽(26)
  • ## 在unity中無法使用RegistryKey類,引用了Microsoft.Win32命名空間也不行

    ## 在unity中無法使用RegistryKey類,引用了Microsoft.Win32命名空間也不行

    解決方法: 把unity api兼容級別改成.net framework

    2024年02月11日
    瀏覽(24)
  • C# 圖解教程 第5版 —— 第22章 命名空間和程序集

    C# 圖解教程 第5版 —— 第22章 命名空間和程序集

    ? 在許多項(xiàng)目中,會使用其他程序集的類或類型,而不僅僅是自己聲明的。這些程序集(稱為類庫)可能來自 BCL 或第三方供應(yīng)商,也可以是自己創(chuàng)建的。通常這些程序集文件的名稱以 .dll 擴(kuò)展名結(jié)尾,而不是 .exe。 圖22.1 SuperLib 源代碼和結(jié)果程序集 ? 假設(shè)還要寫一個(gè)名為

    2024年01月18日
    瀏覽(20)
  • 虹科教程 | Linux網(wǎng)絡(luò)命名空間與虹科PROFINET協(xié)議棧的GOAL中間件結(jié)合使用

    虹科教程 | Linux網(wǎng)絡(luò)命名空間與虹科PROFINET協(xié)議棧的GOAL中間件結(jié)合使用

    PROFINET是由PI推出的開放式工業(yè)以太網(wǎng)標(biāo)準(zhǔn),它使用TCP/IP等IT標(biāo)準(zhǔn),并由IEC 61158和IEC 61784 標(biāo)準(zhǔn)化,具有實(shí)時(shí)功能,并能夠無縫集成到現(xiàn)場總線系統(tǒng)中。憑借其技術(shù)的開放性、靈活性和性能優(yōu)勢,PROFINET可應(yīng)用于過程/工廠自動化、運(yùn)動控制等領(lǐng)域。通過PROFINET,可實(shí)現(xiàn)確定性響應(yīng)

    2024年02月13日
    瀏覽(25)
  • 【C++】命名空間 namespace 與 標(biāo)準(zhǔn)流 iostream ( 命名空間概念簡介 | 命名空間定義 | 命名空間使用 | iostream 中的命名空間分析 )

    【C++】命名空間 namespace 與 標(biāo)準(zhǔn)流 iostream ( 命名空間概念簡介 | 命名空間定義 | 命名空間使用 | iostream 中的命名空間分析 )

    命名空間 namespace 又稱為 名字空間 , 名稱空間 , 名域 , 作用域 , 是 C++ 語言 對 C 語言 的擴(kuò)展 之一 ; C++ 中的 命名空間 namespace 指的是 標(biāo)識符 的 可見范圍 , C++ 標(biāo)準(zhǔn)庫中的 所有 標(biāo)識符 , 都定義在 std 命名空間中 ; 命名空間 英文名稱是 \\\" namespace \\\" , name 是 名字 , 名稱 的意思 ,

    2024年02月12日
    瀏覽(29)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包