Unity学习笔记--如何优雅简便地利用对象池生成游戏对象(进阶版)LRU + 对象池

这篇具有很好参考价值的文章主要介绍了Unity学习笔记--如何优雅简便地利用对象池生成游戏对象(进阶版)LRU + 对象池。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

之前写过一篇关于对象池的文章,现在来看写的并不是很好,所以来考虑优化下。

现在来看一年前写的代码,越看越不能入目hhh

Unity学习笔记–如何优雅简便地利用对象池生成游戏对象

前置知识

Unity学习笔记–使用 C# 开发一个 LRU

代码实现

PoolManager.cs

using System;
using System.Collections.Generic;
using Factory;


namespace ToolManager
{
    public class PoolManager
    {
        private Dictionary<string, LinkedListNode<Tuple<string, Pool>>> lru_dict;   // Key : pool_name == obj_name
        private LinkedList<Tuple<string, Pool>> cache;

        private int capacity;

        public PoolManager(int capacity_in = 64)
        {
            capacity = capacity_in;
            cache = new LinkedList<Tuple<string, Pool>>();
            lru_dict = new Dictionary<string, LinkedListNode<Tuple<string, Pool>>>();
        }

        public bool HasPool(string path)
        {
            return lru_dict.ContainsKey(path);
        }

        public bool AddPool(BaseFactory factory, int init_count = 0)
        {
            string pool_name = factory.GetObjPath();
            if (HasPool(pool_name))
            {
                return false;
            }
            Pool pool = new Pool(this, pool_name, factory, init_count);
            LinkedListNode<Tuple<string, Pool>> node = new LinkedListNode<Tuple<string, Pool>>(Tuple.Create(pool_name, pool));
            LRUAdd(node);
            return true;
        }

        public bool DelPool(string name)
        {
            if (!HasPool(name))
            {
                return false;
            }
            var node = lru_dict[name];
            GetPool(node).ReleasePool();
            LRURemove(node);
            return true;
        }

        public object PopOne(string name)
        {
            object res = null;
            if (HasPool(name))
            {
                var node = lru_dict[name];
                LRUChange(node);
                Pool pool = GetPool(node);
                res = pool.PopOne();
                LRURemove(node);
            }
            return res;
        }

        public object[] Pop(string name, int count)
        {
            object[] res = null;
            if (HasPool(name))
            {
                var node = lru_dict[name];
                LRUChange(node);
                Pool pool = GetPool(node);
                res = pool.Pop(count);
                LRURemove(node);
            }
            return res;
        }

        public void PushOne(string name, object obj)
        {
            if (HasPool(name))
            {
                var node = lru_dict[name];
                LRUChange(node);
                GetPool(node).PushOne(obj);
                RefreshLRU();
            }
        }

        public void Push(string name, object[] objs)
        {
            if (HasPool(name))
            {
                var node = lru_dict[name];
                LRUChange(node);
                GetPool(node).Push(objs);
                RefreshLRU();
            }
        }

        private Pool GetPool(LinkedListNode<Tuple<string, Pool>> node)
        {
            return node.Value.Item2;
        }

        // ------------------------- LRU Function -------------------------
        private void LRUChange(LinkedListNode<Tuple<string, Pool>> node)
        {
            cache.Remove(node);
            cache.AddLast(node);
        }

        private void LRUAdd(LinkedListNode<Tuple<string, Pool>> node)
        {
            lru_dict.Add(node.Value.Item1, node);
            cache.AddLast(node);
        }

        private void LRURemove(LinkedListNode<Tuple<string, Pool>> node)
        {
            cache.Remove(node);
            lru_dict.Remove(node.Value.Item1);
        }

        private void RefreshLRU()
        {
            int lru_count = LRUCacheCount;
            while (lru_count > capacity)
            {
                Pool pool = GetPool(cache.First);
                int n_objects_to_remove = Math.Min(pool.PoolCount, lru_count - capacity);
                for (int i = 0; i < n_objects_to_remove; i++)
                {
                    pool.ReleaseOne();
                }
                if(pool.PoolCount == 0)
                {
                    DelPool(pool.pool_name);
                }
                lru_count = LRUCacheCount;
            }
        }

        private int LRUCacheCount
        {
            get
            {
                int count = 0;
                foreach (var node in lru_dict.Values)
                {
                    count += node.Value.Item2.PoolCount;
                }
                return count;
            }
        }

        private class Pool
        {
            private PoolManager pool_mgr;
            private BaseFactory factory;
            private Queue<object> queue;

            public string pool_name;

            public Pool(PoolManager pool_mgr_in, string pool_name_in, BaseFactory factory_in, int init_count_in)
            {
                pool_mgr = pool_mgr_in;
                pool_name = pool_name_in;
                factory = factory_in;
                queue = new Queue<object>();

                InitPool(init_count_in);
            }

            private void InitPool(int init_count)
            {
                for (int i = 0; i < init_count; i++)
                {
                    queue.Enqueue(factory.CreateObject());
                }
            }

            public void ReleasePool()
            {
                foreach (var obj in queue)
                {
                    factory.DestroyObject(obj);
                }
                queue.Clear();
                factory.ReleaseFactory();
            }

            public object PopOne()
            {
                if (queue.Count > 0)
                {
                    object obj = queue.Dequeue();
                    factory.ResetObject(obj);
                    return obj;
                }
                return factory.CreateObject();
            }

            public object[] Pop(int count)
            {
                object[] objs = new object[count];
                for (int i = 0; i < count; i++)
                {
                    objs[i] = PopOne();
                }
                return objs;
            }

            public void PushOne(object obj)
            {
                factory.RecycleObject(obj);
                queue.Enqueue(obj);
            }

            public void Push(object[] objs)
            {
                foreach (var obj in objs)
                {
                    PushOne(obj);
                }
            }

            public void ReleaseOne()
            {
                factory.DestroyObject(queue.Dequeue());
            }

            public int PoolCount { get => queue.Count; }
        }

    }
}

BaseFactory.cs

namespace Factory
{
    public abstract class BaseFactory
    {
        protected string obj_path;
        public BaseFactory(string obj_path_in)
        {
            obj_path = obj_path_in;
        }
        public abstract object CreateObject();
        public abstract void ResetObject(object obj);
        public abstract void RecycleObject(object obj);
        public abstract void DestroyObject(object obj);
        public abstract void ReleaseFactory();
        public virtual string GetObjPath()
        {
            return obj_path;
        }
    }
}

使用

创建 Factory

using Factory;

public class BulletFactory : BaseFactory
{
    public BulletFactory(string obj_path_in) : base(obj_path_in)
    {

    }

    public override object CreateObject()
    {
        Bullet bullet = new Bullet(obj_path);
        bullet.ReuseInit();
        return bullet;
    }

    public override void DestroyObject(object obj)
    {
        ((Bullet)obj).Destroy();
    }

    public override void RecycleObject(object obj)
    {
        ((Bullet)obj).Recycle();
    }

    public override void ReleaseFactory()
    {
        
    }

    public override void ResetObject(object obj)
    {
        ((Bullet)obj).ReuseInit();
    }
}

创建 object

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

public class Bullet
{
    private GameObject go;
    private string path;
    private static GameObject prefab;
    public Bullet(string path_in)
    {
        path = path_in;
        if (prefab == null)
        {
            prefab = (GameObject) Resources.Load(path);
        }
    }

    public void ReuseInit()
    {
        if (go)
        {
            go.SetActive(true);
        }
        else
        {
            go = GameObject.Instantiate(prefab);
        }
        go.GetComponent<RecycleMe>().DelayCall(1, Func);
    }

    public void Destroy()
    {
        GameObject.Destroy(go);
    }

    public void Recycle()
    {
        go.SetActive(false);
    }

    private void Func()
    {
        BulletManager.Ins.PushOne(path, this);
    }
}

创建 BulletManager

BulletManager.cs

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


public class BulletManager : MonoBehaviour
{
    private PoolManager pool_mgr;

    private static BulletManager _ins;

    public static BulletManager Ins
    {
        get => _ins;
    }
    private void Awake()
    {
        Init();
    }

    private void Init()
    {
        _ins = this;
        pool_mgr = new PoolManager();
    }

    public void PushOne(string path, Bullet obj)
    {
        if (!pool_mgr.HasPool(path))
        {
            pool_mgr.AddPool(new BulletFactory(path));
        }
        pool_mgr.PushOne(path, obj);
    }

    public Bullet PopOne(string path)
    {
        if (!pool_mgr.HasPool(path))
        {
            pool_mgr.AddPool(new BulletFactory(path));
        }
        Bullet bullet = (Bullet)pool_mgr.PopOne(path);
        return bullet;
    }
}

验证

为了验证,我写了一个 ShootManager.cs

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

public class ShootManager : MonoBehaviour
{
    private List<Bullet> bullet_list;
    private string path = "Bullet";

    private static ShootManager _ins;

    public static ShootManager Ins
    {
        get => _ins;
    }

    private void Awake()
    {
        Init();
    }

    private void Init()
    {
        _ins = this;
        bullet_list = new List<Bullet>();
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            bullet_list.Add(BulletManager.Ins.PopOne(path));
        }
    }
}

创建之后过 1s 之后回收自己。
RecycleMe.cs

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

public class RecycleMe : MonoBehaviour
{
    public void DelayCall(float delay, Action func)
    {
        StartCoroutine(DestroyAfterDelayCoroutine(delay, func));
    }

    IEnumerator DestroyAfterDelayCoroutine(float delay, Action func)
    {
        yield return new WaitForSeconds(delay);
        func.Invoke();
    }

}

效果

LRUPool文章来源地址https://www.toymoban.com/news/detail-639796.html

到了这里,关于Unity学习笔记--如何优雅简便地利用对象池生成游戏对象(进阶版)LRU + 对象池的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【学习笔记】Unity基础(七)【uGUI基础、利用render Texture实现小地图功能】

    【学习笔记】Unity基础(七)【uGUI基础、利用render Texture实现小地图功能】

    转载请注明出处:🔗https://blog.csdn.net/weixin_44013533/article/details/130808689 本篇基本是大纲性质,参考价值不大,只有最后一小节“利用render Texture实现小地图功能”花了点时间,可以看看,不过也用到了上面的canvas、UI image等知识、以及input等脚本功能,也算一个小练手吧 倒是

    2024年02月08日
    浏览(16)
  • Unity学习笔记--如何用代码Copy Component并且Paste到其他游戏对象上?

    最近需要在编辑器模式下,用代码实现复制一个组件并且移动到另一个游戏对象上 简单来说就是剪切 通过查询Unity API可以了解到 UnityEditorInternal.ComponentUtility.CopyComponent 。 比如我们想把A游戏对象上的 Rigidbody 组件移动到B游戏对象上 有时候,我们可能需要把一个游戏对象上的

    2024年02月15日
    浏览(47)
  • Java如何优雅地判断对象是否为空

    点击下载《Java如何优雅地判断对象是否为空》 在实际项目中,我们经常需要对各种变量或对象进行判空校验。这是因为,如果不进行判空校验,当遇到空值时,可能会导致程序出现NullPointerException异常。这是一种常见的运行时异常,它会在试图访问或操作空对象引用时发生。

    2024年04月28日
    浏览(119)
  • Java中如何优雅的把Map转为对象

    在项目开发中,经常碰到map转实体对象或者对象转map的场景,工作中,很多时候我们可能比较喜欢使用第三方jar包的API对他们进行转化,而且用起来也还算方便,比如像fastJson就可以轻松实现map和对象的互转,但这里,我想通过反射的方式对他们做转化,也算是对反射的学习

    2024年02月13日
    浏览(12)
  • Unity 如何在Unity中优雅的画线

    Unity 如何在Unity中优雅的画线

    内容将会持续更新,有错误的地方欢迎指正,谢谢!   Unity 如何在Unity中优雅的画线       TechX 坚持将创新的科技带给世界! 拥有更好的学习体验 —— 不断努力,不断进步,不断探索 TechX —— 心探索、心进取! 助力快速掌握 画线 为初学者节省宝贵的学习时间,避免困惑!

    2024年02月02日
    浏览(13)
  • 【Elasticsearch学习笔记五】es常用的JAVA API、es整合SpringBoot项目中使用、利用JAVA代码操作es、RestHighLevelClient客户端对象

    目录 一、Maven项目集成Easticsearch 1)客户端对象 2)索引操作 3)文档操作 4)高级查询 二、springboot项目集成Spring Data操作Elasticsearch 1)pom文件 2)yaml 3)数据实体类 4)配置类 5)Dao数据访问对象 6)索引操作 7)文档操作 8)文档搜索 三、springboot项目集成bboss操作elasticsearch

    2023年04月09日
    浏览(16)
  • Mockito框架下如何优雅的验证调用Mock对象方法的入参

    该文章已同步至个人微信公众号[不能止步],欢迎关注。 在单元测试场景中,一种典型的场景是为了测试某一个类(Component Under Test, 简称CUT)而需要mock其依赖的的类。示例如下: 为了验证CUT业务实现的正确性,通常需要验证传给调用Mock对象的方法的参数的正确性。如果采

    2024年02月09日
    浏览(22)
  • 在线生成占位图片工具:简便快捷的设计利器

    在线生成占位图片工具:简便快捷的设计利器

    在网页开发或设计过程中,经常会遇到需要临时使用占位图片的情况。占位图片是指在设计阶段或者内容填充时使用的临时图片,用于模拟最终效果。这些占位图片通常用于展示页面布局、图片占位大小、颜色搭配等,以便设计师和开发人员更好地调整布局和设计。为了解决

    2024年04月08日
    浏览(7)
  • 【Unity】如何优雅地移动物体-8个方法

    【Unity】如何优雅地移动物体-8个方法

    在游戏开发中,如何移动物体?是我们需要思考的事情。 Unity 引擎也提供了众多的方法,每个开发者的使用习惯也各不相同,所以往往不是很清楚在这种场景下哪种方式最好的或者最有效的。 那么,这篇文章,我想分享一下移动物体的一些方法和优缺点。 仓库地址 如何优雅

    2023年04月09日
    浏览(14)
  • 用Unity3D制作FPS游戏的学习笔记————人物移动、利用鼠标实现视角转动和人物跳跃(含人物悬空不掉落修复)

    用Unity3D制作FPS游戏的学习笔记————人物移动、利用鼠标实现视角转动和人物跳跃(含人物悬空不掉落修复)

    前言: 这是我第一次发布文章,此文章仅供参考,我也是刚学习接触untiy,在制作项目的过程中将有用的写下来记一记,以便自己之后能回头看看,各位大佬轻点喷,若有错误请麻烦积极提谢谢各位。该文章参考自B站UP主蔡先森_rm-rf发布的 【第一人称射击游戏教程2.0【已完结

    2024年04月27日
    浏览(12)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包