您的位置:首页 > 娱乐 > 八卦 > 人力资源和社会保障部令第48号_揭阳模板网站建站_广东seo推广费用_怎么做互联网推广

人力资源和社会保障部令第48号_揭阳模板网站建站_广东seo推广费用_怎么做互联网推广

2024/10/5 4:46:07 来源:https://blog.csdn.net/hgf1037882434/article/details/142674951  浏览:    关键词:人力资源和社会保障部令第48号_揭阳模板网站建站_广东seo推广费用_怎么做互联网推广
人力资源和社会保障部令第48号_揭阳模板网站建站_广东seo推广费用_怎么做互联网推广

前言

对象池技术在游戏开发中的应用非常普遍,它是一种高效管理对象实例的技术,能够避免频繁和重复创建对象所带来的性能开销。本篇文章我们就来探索一下如何在游戏开发中设计通用对象池,使之易于使用和扩展。

代码

代码目录结构
  • ObjectPool
    • Base
    • Interface
    • Settings

ObjectPool作为本模块的根目录,用于存储模块子目录和具体的对象池脚本。Base目录用于存储对象池抽象基类,用于规范对象池的设计。Interface目录用于存储对象池相关的接口,用于未来扩展。Settings目录用于存储创建对象池的参数脚本以及对象池的设置。

Base目录

BasePool.cs

using System;
using System.Collections.Generic;/// <summary>
/// 对象池基类
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
public abstract class BasePool<T>
{/// <summary>/// 对象池所生产对象的总数量/// </summary>public int totalCount { get; protected set; }/// <summary>/// 对象池当前空闲对象的数量/// </summary>public int freeCount => _pool.Count;/// <summary>/// 是否为固定容量的对象池/// <para>默认值:False</para>/// </summary>public readonly bool isFixed;/// <summary>/// 对象池容量/// <para>默认值:PoolConstant.DEFAULT_CAPACITY</para>/// </summary>public readonly int capacity;/// <summary>/// 对象创建逻辑/// <para>提示:用来自定义对象的创建逻辑</para>/// </summary>public Func<T> overrideCreate;/// <summary>/// 对象重置逻辑/// <para>提示:用来自定义对象的重置逻辑</para>/// </summary>public Func<T, T> overrideReset;/// <summary>/// 池对象/// </summary>protected readonly Stack<T> _pool;/// <summary>/// 对象类型是否为可释放对象类型/// </summary>protected static bool _isDisposable => _staticIsDisposable;static readonly bool _staticIsDisposable = typeof(IDisposable).IsAssignableFrom(typeof(T));/// <summary>/// 对象类型名称/// </summary>protected static string _typeName => _staticTypeName;static readonly string _staticTypeName = typeof(T).Name;protected BasePool(){_pool = new Stack<T>(PoolConstant.DEFAULT_CAPACITY);capacity = PoolConstant.DEFAULT_CAPACITY;}protected BasePool(int capacity){if (capacity <= 0) throw new ArgumentException("Pool:The capacity is not allowed to be less than or equal to zero for the pool.");_pool = new Stack<T>(capacity);this.capacity = capacity;}protected BasePool(int capacity, bool isFixed){if (capacity <= 0) throw new ArgumentException("Pool:The capacity is not allowed to be less than or equal to zero for the pool.");_pool = new Stack<T>(capacity);this.capacity = capacity;this.isFixed = isFixed;}/// <summary>/// 重置对象并返回/// </summary>protected abstract T Reset(T item);/// <summary>/// 创建对象/// </summary>protected abstract T Create();/// <summary>/// 获取对象/// </summary>public abstract T Get();/// <summary>/// 释放对象/// </summary>public abstract void Release(T item);/// <summary>/// 清空对象池/// </summary>public abstract void Clear();
}
Interface目录

......

Settings目录

PoolConstant.cs

public static class PoolConstant
{// 对象池默认容量public const int DEFAULT_CAPACITY = 10;
}

UnityObjectPoolSettings.cs

using UnityEngine;/// <summary>
/// Unity对象池设置
/// </summary>
public class UnityObjectPoolSettings<T> where T : Object
{/// <summary>/// 对象池初始容量/// </summary>public int capacity = PoolConstant.DEFAULT_CAPACITY;/// <summary>/// 对象池是否持久化/// </summary>public bool isPersistant = true;/// <summary>/// 对象池是否固定容量/// </summary>public bool isFixed;/// <summary>/// 对象池容器/// </summary>public GameObject container;/// <summary>/// 对象原型/// </summary>public T original;/// <summary>/// 对象默认名称/// </summary>public string defaultName;/// <summary>/// 获取时激活对象/// </summary>public bool activeWhenGet = true;
}
具体的对象池 

ClassPool.cs

using System;/// <summary>
/// Class 类型对象池
/// </summary>
/// <typeparam name="T">具体的 Class 类型</typeparam>
public class ClassPool<T> : BasePool<T>
where T : class
{public ClassPool() { }public ClassPool(int capacity) : base(capacity) { }public ClassPool(int capacity, bool isFixed) : base(capacity, isFixed) { }public override void Clear(){if (_isDisposable){while (_pool.Count > 0){if (_pool.Pop() is IDisposable ds)ds?.Dispose();}}else _pool.Clear();totalCount = 0;}public override T Get(){T item;if (freeCount > 0) item = _pool.Pop();else{item = Create();totalCount++;}return item;}public override void Release(T item){if (item == null) return;_pool.Push(Reset(item));}protected override T Reset(T item){T v_item;if (overrideReset != null) v_item = overrideReset(item);else v_item = item;return v_item == null ? item : v_item;}protected override T Create(){if (isFixed && totalCount == capacity)throw new InvalidOperationException("Pool:The number of objects in the object pool has reached the upper limit.");T item;if (overrideCreate != null) item = overrideCreate();else item = Activator.CreateInstance<T>();if (item == null) throw new InvalidOperationException("Pool:The item created is null.");return item;}
}

UnityObjectPool.cs

using System;
using UnityEngine;/// <summary>
/// Unity对象池
/// </summary>
/// <typeparam name="T">Unity对象类型</typeparam>
public class UnityObjectPool<T> : ClassPool<T>, IDisposable
where T : UnityEngine.Object
{protected readonly GameObject _container;protected readonly T _original;protected readonly string _defaultName;protected readonly bool _activeWhenGet;bool _isDisposed;public UnityObjectPool(){_container = new GameObject($"{_typeName}Pool");MonoBehaviour.DontDestroyOnLoad(_container);_activeWhenGet = true;}public UnityObjectPool(int capacity) : base(capacity){_container = new GameObject($"{_typeName}Pool");MonoBehaviour.DontDestroyOnLoad(_container);_activeWhenGet = true;}public UnityObjectPool(int capacity, bool isFixed) : base(capacity, isFixed){_container = new GameObject($"{_typeName}Pool");MonoBehaviour.DontDestroyOnLoad(_container);_activeWhenGet = true;}public UnityObjectPool(UnityObjectPoolSettings<T> settings) :base(settings == null ? PoolConstant.DEFAULT_CAPACITY : settings.capacity, settings != null && settings.isFixed){if (settings == null){_container = new GameObject($"{_typeName}Pool");MonoBehaviour.DontDestroyOnLoad(_container);return;}_container = settings.container;_original = settings.original;_defaultName = settings.defaultName;_activeWhenGet = settings.activeWhenGet;if (settings.isPersistant) MonoBehaviour.DontDestroyOnLoad(_container);}/// <summary>/// 释放对象池/// <para>提示:释放后对象池将无法继续使用</para>/// </summary>public void Dispose(){if (_isDisposed) return;Dispose(true);GC.SuppressFinalize(this);}public sealed override void Clear(){if (_isDisposed) return;DoClear();}public sealed override void Release(T item){if (_isDisposed) return;DoRelease(item);}public sealed override T Get(){if (_isDisposed) return null;return DoGet();}protected virtual void DoClear(){T item;while (_pool.Count > 0){item = _pool.Pop();MonoBehaviour.Destroy(item);}totalCount = 0;}protected virtual void DoRelease(T item) { base.Release(item); }protected virtual T DoGet() { return base.Get(); }void Dispose(bool disposing){if (_isDisposed) return;_isDisposed = true;if (disposing){Clear();MonoBehaviour.Destroy(_container);}}~UnityObjectPool(){Dispose(false);}
}

GameObjectPool.cs

using System;
using UnityEngine;/// <summary>
/// GameObject 对象池
/// </summary>
public sealed class GameObjectPool : UnityObjectPool<GameObject>
{public GameObjectPool() { }public GameObjectPool(int capacity) : base(capacity) { }public GameObjectPool(int capacity, bool isFixed) : base(capacity, isFixed) { }public GameObjectPool(UnityObjectPoolSettings<GameObject> settings) : base(settings) { }protected override GameObject DoGet(){if (!_activeWhenGet) return base.DoGet();else{GameObject item = base.DoGet();item.SetActive(true);return item;}}protected override GameObject Reset(GameObject item){GameObject v_item;if (overrideReset != null) v_item = overrideReset(item);else{v_item = item;v_item.SetActive(false);}if (v_item == null) throw new InvalidOperationException("Pool:The item being reset is null.");return v_item;}protected override GameObject Create(){if (isFixed && totalCount == capacity)throw new InvalidOperationException("Pool:The number of objects in the object pool has reached the upper limit.");GameObject item;if (overrideCreate != null) item = overrideCreate();else{if (_original == null) item = new GameObject();else item = MonoBehaviour.Instantiate(_original);if (item != null){if (!string.IsNullOrEmpty(_defaultName)) item.name = _defaultName;item.transform.SetParent(_container.transform);item.SetActive(false);}}if (item == null) throw new InvalidOperationException("Pool:The item being created is null.");return item;}
}

MonoPool.cs

using System;
using UnityEngine;/// <summary>
/// Monobehaviour 类型对象池
/// </summary>
/// <typeparam name="T">具体的 Monobehaviour 类型</typeparam>
public sealed class MonoPool<T> : UnityObjectPool<T>
where T : MonoBehaviour
{public MonoPool() { }public MonoPool(int capacity) : base(capacity) { }public MonoPool(int capacity, bool isFixed) : base(capacity, isFixed) { }public MonoPool(UnityObjectPoolSettings<T> settings) : base(settings) { }protected override T DoGet(){if (!_activeWhenGet) return base.DoGet();else{T item = base.DoGet();item.enabled = true;return item;}}protected override T Reset(T item){T v_item;if (overrideReset != null) v_item = overrideReset(item);else{v_item = item;v_item.enabled = false;}if (v_item == null) throw new InvalidOperationException("Pool:The item being reset is null.");return v_item;}protected override T Create(){if (isFixed && totalCount == capacity)throw new InvalidOperationException("Pool:The number of objects in the object pool has reached the upper limit.");T item;if (overrideCreate != null) item = overrideCreate();else{if (_original == null) item = _container.AddComponent<T>();else item = MonoBehaviour.Instantiate(_original);if (item != null){if (!string.IsNullOrEmpty(_defaultName)) item.name = _defaultName;item.enabled = false;}}if (item == null) throw new InvalidOperationException("Pool:The item being created is null.");return item;}
}

测试

using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;public class ObjectPoolTest
{// 子弹public class Bullet : MonoBehaviour{public Action<Bullet> onDestroy;public DamageModel damageModel;public void OnCustomTriggerEnter(string tag){if (tag == "Head"){Debug.Log("Attack Head:" + damageModel.AttackHead());onDestroy?.Invoke(this);}else if (tag == "Body"){Debug.Log("Attack Body:" + damageModel.AttackBody());onDestroy?.Invoke(this);}}}// 伤害计算模型public class DamageModel{public int damage;public int AttackHead(){return damage * 2;}public int AttackBody(){return damage;}}static readonly GameObjectPool bulletPool = new GameObjectPool();static readonly ClassPool<DamageModel> damagePool = new ClassPool<DamageModel>();static readonly string[] tags = { "Head", "Body" };static ObjectPoolTest(){bulletPool.overrideReset = ResetBullet;damagePool.overrideReset = ResetDamageModel;}static GameObject ResetBullet(GameObject go){if (go.TryGetComponent(out Bullet bullet)){damagePool.Release(bullet.damageModel);bullet.damageModel = null;bullet.onDestroy = null;}go.SetActive(false);return go;}static DamageModel ResetDamageModel(DamageModel dm){dm.damage = 0;return dm;}Bullet GetBullet(){GameObject go = bulletPool.Get();if (!go.TryGetComponent(out Bullet bullet)) bullet = go.AddComponent<Bullet>();DamageModel damageModel = damagePool.Get();damageModel.damage = UnityEngine.Random.Range(10, 100);bullet.damageModel = damageModel;bullet.onDestroy = OnBulletDestroy;return bullet;}void OnBulletDestroy(Bullet bullet){Debug.Log("Bullet is being destroied.");bulletPool.Release(bullet.gameObject);}[UnityTest]public IEnumerator ObjectPool_Test(){int index = 0;WaitForSeconds waitForSeconds = new WaitForSeconds(0.5f);Stack<Bullet> temp = new Stack<Bullet>();while (index < 9){Debug.Log($"正在进行第{index + 1}次射击...");int sendBulletCount = UnityEngine.Random.Range(1, 5);for (int i = 0; i < sendBulletCount; i++){Debug.Log($"正在生成第{i + 1}颗子弹...");temp.Push(GetBullet());}Debug.Log($"生产子弹总量:{bulletPool.totalCount},子弹库存:{bulletPool.freeCount}");int j = 0;while (temp.Count > 0){Debug.Log($"正在发射第{j + 1}颗子弹...");temp.Pop().OnCustomTriggerEnter(tags[UnityEngine.Random.Range(0, 1)]);j++;}yield return waitForSeconds;index++;}yield return null;Assert.IsTrue(true);}
}

 上述代码基于Unity Test Framework进行测试,模拟了9次射击,每次随机发射1-5颗子弹,随机设置每个子弹的基本伤害为10-100,用对象池技术管理子弹游戏对象实例和伤害计算模型实例。

分析

BasePool作为所有对象池的抽象基类,规范对象池的必要属性和方法。PoolConstant记录对象池所用的常量值。UnityObjectPoolSettings作为Unity对象池特有的对象池设置参数,在创建Unity对象池时传递。ClassPool作为C#类对象池。UnityObjectPool作为Unity对象池,继承自ClassPool。GameObjectPool作为Unity游戏对象池。MonoPool作为Monobehaviour对象池。

版本改进

......

系列文章

......

如果这篇文章对你有帮助,请给作者点个赞吧!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com