对象池是一种通过空间来换取时间的思想
占内存,时间消耗少
适用性:频繁创建/销毁游戏对象
字典<类型,对象>
数据结构:Dictionary<string,List< GameObject >>
核心成员
1.通过对象池创建对象
2.回收对象
GameObjectPool
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Common
{
/*
*使用方式
* 1.所有频繁创建/销毁的游戏对象,通过对象池来使用,或创建或回收
* GameObjectPool.Instance.CreateObjet(类别,预制体,位置,旋转);
* GameObjectPool.Instance.CollectObjet(游戏对象);
* 2.需要通过对象池创建的游戏对象,如需每次创建时执行,则让脚本实现IRestable接口
*/
/// <summary>
/// 如果游戏对象某些行为需要重置
/// </summary>
internal interface IRestable
{
void OnReset();
}
/// <summary>
/// 对象池
/// 只用一次,继承单例类
/// </summary>
public class GameObjectPool : MonoSingleton<GameObjectPool>
{
//数据结构
//对象池:字典<类别,列表<对象>>
private Dictionary<string , List<GameObject>> cache;
//初始化
public override void Init()
{
base.Init();
cache = new Dictionary<string, List<GameObject>>();
}
/// <summary>
/// 【重要一】通过对象池,创建对象
/// </summary>
/// <param name="key">类别</param>
/// <param name="prefab">需要创建实例的预制体</param>
/// <param name="pos">位置</param>
/// <param name="rotate">旋转</param>
/// <returns>返回需要的对象</returns>
/// 结构清晰
public GameObject CreateObject(string key,GameObject prefab,Vector3 pos,Quaternion rotate)
{
//1.找到可用的对象
GameObject go = FindUsableObject(key);
//2.如果未找到可以使用,创建新对象,并加入对象池
if (go == null)
{
go = AddObject(key, prefab); //创建游戏对象--->设置目标点--->设置位置、旋转
}
//3.设置对象的位置,旋转(提取方法)
UseObject(pos, rotate, go);
return go;
}
//1.查找可用的对象,返回对象
private GameObject FindUsableObject(string key)
{
//1.查找指定类别,找到未使用(禁用、未激活)的对象
//如果包含此类别
if (cache.ContainsKey(key))
{
//找到未使用的对象
return cache[key].Find(g => !g.activeInHierarchy);
}
return null;
}
//2.创建新的对象,并加入对象池,返回一个对象
private GameObject AddObject(string key, GameObject prefab)
{
//2.创建新的对象,并加入对象池
//创建新的对象
GameObject go = Instantiate(prefab);
//加入对象池,如果池中没有key类别
if (!cache.ContainsKey(key))
{
//添加新的类别key
cache.Add(key, new List<GameObject>());
//把对象go加入这个key类别
cache[key].Add(go);
}
return go;
}
//钩子...
//3.设置对象的位置,旋转
private void UseObject(Vector3 pos, Quaternion rotate, GameObject go)
{
go.transform.position = pos;
go.transform.rotation = rotate;
go.SetActive(true);
//设置目标点
//抽象
//go.GetComponent<IRestable>().OnReset();
//遍历需要创建的对象所有组件,执行需要重置的逻辑,比如设计目标点等
foreach (var item in go.GetComponents<IRestable>())
{
item.OnReset();
}
}
/// <summary>
/// 【重要二】回收对象
/// </summary>
/// <param name="go">需要被回收的对象</param>
/// <param name="delay">延迟时间,默认为0</param>
public void CollectObject(GameObject go ,float delay=0)
{
StartCoroutine(CollectObjectDelay(go,delay));
}
public IEnumerator CollectObjectDelay(GameObject go, float delay = 0)
{
yield return new WaitForSeconds(1);
go.SetActive(false);
}
/// <summary>
/// 清空某个key类别,和其游戏对象
/// </summary>
/// <param name="key">类别</param>
public void Clear(string key)
{
顺序删除
//for (int i = 0; i < cache[key].Count; i++)
//{
// Destroy(cache[key][i]);
//}
//常规倒叙删除,游戏对象
for (int i = cache[key].Count-1; i >=0; i--)
{
Destroy(cache[key][i]);
}
//删除类别
cache.Remove(key);
}
/// <summary>
/// 清除全部类别
/// </summary>
/// <param name="key"></param>
public void ClearAll(string key)
{
//foreach只读元素,不能操作
//异常:无效的操作
//foreach (var item in cache.Keys)
//{
// Clear(key);//删除字典记录
//}
//将所有字典的key存入list中
List<string> keyList = new List<string>(cache.Keys);
//读A删除B,遍历A集合,删除字典记录
foreach (var item in keyList)
{
Clear(key);
}
}
}
}
Bullet
using Common;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
namespace ns
{
/// <summary>
///
/// </summary>
public class Bullet : MonoBehaviour ,IResetable
{
private Vector3 targetPos;
//创建对象时执行一次
//private void Awake()
//{
// //计算正前方50m的世界坐标
// //TransformPoint : 自身坐标系 ---> 世界坐标系
// targetPos = transform.TransformPoint(0, 0, 50);
//}
//每次通过对象池创建时执行一次
public void OnReset()
{
targetPos = transform.TransformPoint(0, 0, 50);
}
private void Update()
{
transform.position = Vector3.MoveTowards(transform.position, targetPos, Time.deltaTime * 50);
if (Vector3.Distance(transform.position, targetPos) < 0.1)
{
//Destroy(gameObject);
GameObjectPool.Instance.CollectObject(gameObject);
//System.Object object int List<string>
//UnityEngine.Object Object 模型 贴图 组件
}
}
}
}
Gun
using Common;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ns
{
/// <summary>
///
/// </summary>
public class Gun : MonoBehaviour
{
public GameObject bulletPrefab;
/*
问题:子弹发射方向有误。
解决:……
*/
public void Fire()
{
//创建物体 --> 设置位置/旋转 --> 立即执行Awake(计算目标点)
//Instantiate(bulletPrefab, transform.position, transform.rotation);
//创建物体 --> 设置位置/旋转 --> 重置(计算目标点)
GameObjectPool.Instance.CreateObject("bullet", bulletPrefab, transform.position, transform.rotation);
}
//************测试**************
private void OnGUI()
{
if (GUILayout.Button("发射"))
{
Fire();
}
if (GUILayout.Button("清空类别"))
{
GameObjectPool.Instance.Clear("bullet");
}
if (GUILayout.Button("清空全部"))
{
GameObjectPool.Instance.ClearAll();
}
}
}
}