❤️UNITY 実戦 Advanced-ObjectPool オブジェクトプール-4

  • 序文

        プレーヤーを作成するとき、ネットワーク イメージをロードする必要があります。多くの場合、UnityWebRequest を使用してロードします。

UnityWebRequest www = new UnityWebRequest(networkPath);
DownloadHandlerTexture download = new DownloadHandlerTexture(true);
www.downloadHandler = download;
yield return www.SendWebRequest();
while (!www.isDone || www.isNetworkError)
    yield return new WaitForEndOfFrame();
if (img != null)
{
    if (download.texture != null)
    {
        img.sprite = (Sprite.Create(download.texture, new Rect(0, 0, download.texture.width, download.texture.height), new Vector2(0.5f, 0.5f)));
    }
    else
    {
        img.sprite = null;
    }
}
www.Dispose();

多くの学生はリサイクルに関係なく単にそれを使用し、ロードされたすべての画像をメモリにロードするため、メモリの使用量がますます大きくなり、深刻なゲームラグが発生します。オブジェクト プールの概念を導入する必要があります。


  • オブジェクトプールとは 

        オブジェクト プールには、事前に準備されたいくつかのインスタンスが含まれており、必要に応じてオブジェクト プールから抽出され、不要になった場合はオブジェクト プールに戻されます。
        オブジェクト プールを使用すると、インスタンス オブジェクトを頻繁に生成したり破棄したりする必要がなく、オブジェクト プールに十分なインスタンスがない場合でも、プログラムはインスタンスを生成し続けるため、パフォーマンスが大幅に節約されます。
        栗を取る:
        私は飛行機を持っています、私は弾丸を持っています、あ〜、飛行機が弾丸を発射しました

        航空機から弾丸を発射する最初の方法
        は、弾丸を継続的にインスタンス化し、条件が満たされたときに弾丸を破壊することです。
        方法 2: 最初に N 個の弾丸を作成し、コンテナに入れます。使用するときに未使用の弾丸を取り出し、使用済みの弾丸を未使用状態に設定し、同時にコンテナに入れます。コンテナ内で使用されているものをインスタンス化して、新しいコンテナに入れて使用します。
        方法 3 は、方法 2 に合わせてオブジェクトの有効期限とオブジェクトの上限を追加し、オブジェクトが有効期限を超えて使用されない場合はオブジェクトを破棄してメモリ サイズを確保します。


  •  オブジェクトプールの使用

        ここでは、ネットワーク上にロードしたスプライト画像をオブジェクトプールに入れて利用し、ローカルに保存し、
        プールオブジェクトの上限、プールオブジェクトの有効期限、プールオブジェクトの優先度を設定します。
        

 (1). ローカルストレージパスにある写真を取得します。

private string FolderPath
{
    get
    {
        return Path.Combine(Application.persistentDataPath, "YourFileName");
        //return string.Format("{0}/{1}", Application.persistentDataPath, "YourFileName");
    }
}

public FileInfo[] GetFolderChildsPath(string folderPath, string pngSuffix, string jpgSuffix)
{
    if (!Directory.Exists(folderPath))
    {
        Directory.CreateDirectory(folderPath);
    }
    DirectoryInfo di = new DirectoryInfo(folderPath);
    FileInfo[] files = di.GetFiles();
    string fileName;
    List<FileInfo> list = new List<FileInfo>();
    for (int i = 0; i < files.Length; i++)
    {
        fileName = files[i].Name.ToLower();
        if (fileName.EndsWith(pngSuffix) || fileName.EndsWith(jpgSuffix))
        {
            list.Add(files[i]);
        }
    }
    return list.ToArray();
}

//初始化获取
public void FileRecv()
{
    //存名字用于判断本地是否有这张图片
    m_PersistentAllName.Clear();
    Log.Info(FolderPath);
    FileInfo[] completePath = GetFolderChildsPath(FolderPath, PNGFileSuffix, JPGFileSuffix);
    for (int i = 0; i < completePath.Length; i++)
    {
        //Debug.LogWarning("图片完整路径: " + completePath[i].Name);
        m_PersistentAllName.Add(completePath[i].Name);
    }
}

m_PersistentAllName ; //この画像がローカルに存在するかどうかを判断するために名前を保存します

(2). GFのObjectPoolを作成する

1. プール オブジェクトは ObjectBase 基本クラスから継承する必要があります。

public class SpriteItemObject : ObjectBase
{
    public static SpriteItemObject Create(string name, object target)
    {
        SpriteItemObject hpBarItemObject = new SpriteItemObject(name, target);
        return hpBarItemObject;
    }

    public SpriteItemObject(string name, object target) : base(name, target)
    {
    }

    protected override void Release(bool isShutdown)
    {
        Sprite sprite = (Sprite)Target;
        if (sprite == null)
        {
            return;
        }
        Object.Destroy(sprite);
    }
}

オブジェクトの基本クラスについては、GameFramework.ObjectPool.ObjectBase を参照してください。

2. オブジェクトプールを作成する

private IObjectPool<SpriteItemObject> m_SpriteObjectPool = null;

m_SpriteObjectPool = GameEntry.ObjectPool.CreateSingleSpawnObjectPool<SpriteItemObject>(
    "NetworkSprites", 
    m_InstancePoolCapacity,
    m_InstancePoolExpireTime, 
    m_InstancePoolPriority);

簡単な一文です オブジェクトプールが作成されます
詳細なコードはUnityGameFramework.Runtime.ObjectPoolComponentを参照してください
プールの作成には2種類あります
        1) 複数回プールオブジェクトを取得可能 CreateMultiSpawnObjectPool
        2) プールオブジェクトを複数回取得可能CreateSingleSpawnObjectPool
オブジェクト プール マネージャーを取得するには、GameFramework.ObjectPool.ObjectPoolManager を参照してください。

(3). オブジェクトプールの破棄

管理クラスのリリース関数で、作成されたオブジェクト プールを忘れずに破棄してください。

 if (m_SpriteObjectPool != null)
 {
     GameEntry.ObjectPool.DestroyObjectPool(m_SpriteObjectPool);
     m_SpriteObjectPool = null;
 }

(4). オブジェクトプール内のSpriteオブジェクトを取得する

private Sprite CreateSprite(string fullname, string filename, Texture2D download = null)
{
    //从对象池中取出一个对象
    SpriteItemObject spriteItemObject = m_SpriteObjectPool.Spawn(filename);
    Sprite sprite;
    //对象是否为空
    if (spriteItemObject != null)
    {
        //对象不为空直接获取
        sprite = (Sprite)spriteItemObject.Target;
    }
    else
    {
        //对象为空,并且没有下载的图片数据,直接从本地加载
        if (download == null)
            download = TextureUtility.LoadTexture(fullname);
        //创建sprite
        sprite = (Sprite.Create(download, new Rect(0, 0, download.width, download.height), new Vector2(0.5f, 0.5f)));
        //sprite放入到SpriteItemObject.Target中存入m_SpriteObjectPool,并设置该对象已被获取
        m_SpriteObjectPool.Register(SpriteItemObject.Create(filename, sprite), true);
    }
    return sprite;
}

(5).オブジェクトプール内のSpriteオブジェクトを再利用する

if (m_SpriteObjectPool == null) 
    return;
m_SpriteObjectPool.Unspawn(target);

(6). LoadNetworkImageの併用と再利用

public IEnumerator LoadSprites(string networkPath, Image img, string appointName)
{
    string fileName;
    //指定一个名字
    if (string.IsNullOrEmpty(appointName))
    {
        fileName = networkPath.Substring(networkPath.LastIndexOf('/') + 1);
    }
    else
    {
        fileName = ReplaceName(appointName, "/", "_"); ;
    }
    //本地存在这个名字 
    if (FindName(fileName))
    {
        Sprite sprite;
        //从本地加载图片,塞入到对象池中
        yield return sprite = CreateSprite(Path.Combine(FolderPath, fileName), fileName, null);
        if (img)
        {
            //回收之前img上引用的sprite对象
            UnspawnReference(img.sprite);
            //重新赋值
            img.sprite = sprite;
        }
    }
    //下载保存本地
    else
    {
        if (string.IsNullOrEmpty(networkPath))
        {
            if (img != null)
            {
                UnspawnReference(img.sprite);
                img.sprite = null;
            }
            yield break;
        }
        UnityWebRequest www = new UnityWebRequest(networkPath);
        DownloadHandlerTexture download = new DownloadHandlerTexture(true);
        www.downloadHandler = download;
        yield return www.SendWebRequest();
        while (!www.isDone || www.isNetworkError)
            yield return new WaitForEndOfFrame();
        if (img != null)
        {
            if (download.texture != null)
            {
                //回收之前img上引用的sprite对象
                UnspawnReference(img.sprite);
                string full_path = Path.Combine(FolderPath, fileName);
                //获取的网络图片塞到对象池中
                yield return img.sprite = CreateSprite(full_path, fileName, download.texture);
                //保存到本地
                CreatePNG(full_path, download.data, fileName);
            }
            else
            {
                img = null;
            }
        }
        www.Dispose();
    }
}

  • 効果

 左下隅に動的に読み込まれた画像に注目してください。

 オブジェクト プール内のすべてのスプライト オブジェクトを表示する

1. 名前 2. ロックされているかどうか 3. 使用中かどうか 4. 優先度 5. このオブジェクトが最後に使用されたときのタイムスタンプ

3 番目が false の場合、オブジェクトが解放へのカウントダウンを開始したことを意味し、期間内に使用されなかった場合は自動的に破棄されます。

1. ユーザーアバター 2. プレイリストアバター 3. 現在の曲アバター の 3 つのスプライトが使用されています。
1 つのスプライトを解放できます。

このバージョン以降のGFのオブジェクトプールのオブジェクト基本クラスは、参照プールのオブジェクト基本クラスを継承しているため、使用上も大きな変更があります

    public class SpriteItemObject : ObjectBase
    {
        public static SpriteItemObject Create(object target)
        {
            SpriteItemObject spriteObject = ReferencePool.Acquire<SpriteItemObject>();
            spriteObject.Initialize(target);
            return spriteObject;
        }

        protected override void Release(bool isShutdown)
        {
           Sprite sprite = (Sprite)Target;
            if (sprite == null)
            {
                return;
            }
            Object.Destroy(sprite);
        }
    }

 興味のある友達は波に注目してください

 o(* ̄▽ ̄*)ブ

おすすめ

転載: blog.csdn.net/flj135792468/article/details/120363721