Unity之C#学习笔记(17):对象池模式 Object Pooling
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Unity之C#学习笔记(17):对象池模式 Object Pooling,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3141字,纯文字阅读大概需要5分钟。
内容图文
前篇链接:Unity之C#学习笔记(16):单例模式及单例模板类 Singleton and MonoSingleton
在游戏中,有一些生命周期很短,需要频繁创建和销毁的物体,例如射击游戏中的子弹。按一般做法,我们也需要频繁地实例化(Instantiate)和销毁(Destroy)这些物体,这其实是有一定开销的。对象池模式的思想就是创建容纳了一些物体的“池”,需要时从中取一个,用完了再放回去,循环利用,减少生成和销毁物体的次数,优化性能。
来看一个例子:我们现在有子弹的prefab,按下空格键时,生成一个子弹,子弹过一秒自动消失。传统的做法是:
GameManager:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public GameObject bulletPrefab;
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(bulletPrefab);
}
}
}
Bullet:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
void Start()
{
Destroy(this.gameObject, 1.0f); // 创建后延迟1秒销毁
}
}
实验一下会发现,即使按最快速度按空格,场景中大概也只能生成7个左右的子弹。也就是说,我们只需要一个容纳7个子弹实体的池就足够了。在实际场景中,池的容量自然是要根据游戏逻辑确定。创建PoolManager脚本,用List实现对象池。在Start函数中初始化7个GameObject并放在List中:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PoolManager : MonoSingleton<PoolManager>
{
public GameObject bulletPrefab;
private List<GameObject> _bulletPool;
void Start()
{
_bulletPool = GenerateBullets(7);
}
List<GameObject> GenerateBullets(int amount)
{
List<GameObject> pool = new List<GameObject>();
for (int i = 0; i < amount; i++)
{
GameObject bullet = Instantiate(bulletPrefab);
bullet.SetActive(false);
pool.Add(bullet);
}
return pool;
}
PoolManager使用单例模式,关于单例模式和单例模板类,可以参考上一篇文章
PoolManager对外提供获取对象的接口。获取对象时,从List中找到一个空闲状态的GameObject并返回。如果找不到空闲的,说明池子中所有对象都被占用了,需要扩充容量,创建新的对象放入池子。在实现中,我们不需要真的模拟将对象从池子中“取走”,“放回”的过程,而可以用一个状态量判断某个对象是否空闲。例如这里最简单的,我们用Active属性决定。
public GameObject RequestBullet()
{
foreach (var bullet in _bulletPool)
{
if (bullet.activeInHierarchy == false) // 找到一个未使用的对象
{
bullet.SetActive(true); // Active设为true,表示被占用
return bullet;
}
}
// 池子内的对象用光了!创建一个新的
// 如果不够用的情况经常发生,考虑一次扩充更多的容量,例如一次性将池子扩充为1.5倍
GameObject newBullet = Instantiate(bulletPrefab);
_bulletPool.Add(newBullet);
return newBullet;
}
在外部获取一个对象:
if (Input.GetKeyDown(KeyCode.Space))
{
GameObject bullet = PoolManager.Instance.RequestBullet();
// 对bullet对象做一些其它操作,例如移动,旋转...
}
回收对象时,由于本例中我们是使用物体的Active属性判断是否空闲,故只需SetActive(false)即可。
Bullet:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
private void OnEnable() // 对象设为Active时被调用
{
Invoke("Die", 1); // 延迟1秒调用Die
}
void Die()
{
this.gameObject.SetActive(false);
}
}
实际应用中,管理的对象会更复杂,分配和回收可能涉及其他相关资源的处理。占用和回收的条件也不能只用简单的SetActive实现,需要设计更合适的数据结构。
内容总结
以上是互联网集市为您收集整理的Unity之C#学习笔记(17):对象池模式 Object Pooling全部内容,希望文章能够帮你解决Unity之C#学习笔记(17):对象池模式 Object Pooling所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。