游戏开发设计模式之对象池模式(unity3d 示例实现)
前篇:游戏开发设计模式之命令模式(unity3d 示例实现)
博主才学尚浅,难免会有错误,尤其是设计模式这种极富禅意且需要大量经验的东西,如果哪里书写错误或有遗漏,还请各位前辈指正。
原理:从一个固定的池中重用对象,来提升性能和内存的使用,而不是一个一个的分配内存在释放它们。
当你需要创造大量重复的对象,而且经常使用这些对象,你就要考虑使用对象池了,因为反复创建销毁就是一个内存反复分配与释放的过程,很容易产生内存碎片。
在主机和移动端与PC相比内存稀缺,我们都希望游戏能够更加稳定,而不能有效的管理内存,此时大量的内存碎片是致命的。
内
存碎片的意思是内存被分成一个一个的小块而不是整个大块,所有内存小块的大小可能很大但并不能使用,比如你想分配16byte的内存,此时如果有
20byte的空间就可以分配成功,但是如果这20byte是内存碎片,为两个10byte就会分配失败。所以,如果存在大量内存碎片,理论上有足够的可
用内存,也会分配失败。
很多游戏公司的游戏都会进行浸泡测试,让一个游戏跑好几天,查看是否崩溃来检测内存泄露等等,因为内存碎片产生毁灭性的结果是一个缓慢的过程。
内存池的原理就是预先分配一大块内存,生成满需要经常用的对象,然后直到不使用再全部释,可以把内存池看做是一堆可重用对象的集合。可以一定程度上避免产生大量内存碎片。
创
建内存池时我们生成指定数量的所有对象,然后把这些对象做标记区分来是否正在使用,所以当我们想要一个对象时只需要从池中获取一个“未使用”标记的对象就
可以,再把它标记为“使用中”,用完了再标记回“未使用”即可。就像一个租借处,需要的时候借出去,用完了再还回来。用这种方法来重用对象。注意:使用时
切记要初始化对象,对象池不需要了要立即释放。
对象池经常用在粒子系统生成粒子,和子弹,还有生成敌人等等,或者是需要播放的声音。
当你需要:
1. 频繁的创建和销毁一种对象
2. 需要空间大小差不多的对象
3. 可能产生内存碎片
4. 可重用,而且创建和销毁都很消耗的对象
请毫不犹豫的使用对象池。
对
象池也有一些缺点,可能开始生成很多对象但是大多用不上,浪费了大量内存,所以需要根据情况控制好开始生成对象的数量,或者创建第二个池,接下来会讲动态
扩充对象池,会解决这个问题。另一种可能是生成的不够用,悲剧,一种解决办法是强行“不使用“一个或几个对象来拆东墙补西墙,最好拆掉的不会被玩家发现,
还有一种就是同上接下来会讲动态扩充对象池会解决这个问题。一个很小的对象池也可能并无卵用,还是会产生内存碎片。而且在初始化时一瞬间分配大量内存,可
能产生问题。
我们需要把生成的对象储存在池中,来取出增加回收,有下面几种可以选择
1.数组,此处不是ArrayList就是普通的Object[]这样的数组,在内存中是连续存储的,索引速度非常快,使用起来比较。但是这种数组不能动态扩充,也就是生成对象的数量是不变的,不小心超出了这个范围还会产造成数据溢出,而且只能存储一种类型的对象。
2.ArrayList,动态数组,可以动态扩充,也可以存储不同类型对象,但是在操作不同类型数据时需要装箱拆箱(要做一个强制转换),带来性能耗损,并且不是类型安全。
3.List<T>,泛型,可动态扩充,但是不能存储不同类型数据,需要制定存储数据类型T。安全类型,不存在装箱拆箱。
除此三种基本的之外还可以用堆,栈,哈希,Dictionary,如果需要根据key来查找具体的对象可以用哈希或Dictionary。博主下面代码用List<T>来示范。
简单的生成敌人的代码
首先看看敌人类:
using UnityEngine;
using System.Collections; public class Enemy : MonoBehaviour {
public AnimationClip hurtAnimation;
public AudioClip hertSound;
public AudioClip dieSound;
AudioSource audiosouce; int Max_HP = 3;
int Now_HP = 3;
bool isUsed = false;
float moveSpeed = 0;
float act = 0; // Use this for initialization
public void init(bool _isUsed, float _moveSpeed, float _act, Vector3 _scale, Vector3 _pos, Quaternion _rot,int _Max_HP)
{
isUsed = _isUsed;
moveSpeed = _moveSpeed;
act = _act;
this.transform.localScale = _scale;
this.transform.position = _pos;
this.transform.rotation = _rot;
Max_HP = _Max_HP;
Now_HP = _Max_HP;
}
public bool getUsed()
{
return isUsed;
}
void hert()
{
…受伤处理…
}
void Die()
{
audiosouce.PlayOneShot(dieSound);
isUsed = false;
this.GetComponent<Rigidbody>().useGravity = false;
this.transform.position = Vector3.zero;
// Destroy(this.gameObject);不需要destroy对象了
}
void Start () {
audiosouce = this.GetComponent<AudioSource>();
}
void OnTriggerEnter(Collider other)
{
…hert()..
}
// Update is called once per frame
void Update () {
…逻辑…..
}
}
init函数负责初始化敌人,每次从池中生成都需要初始化,最开始初始化isUsed标记为false代表未使用然后再在池中调用init()赋参,getUsed方法是池获取对象状态的途径。
一个简单的生成敌人的对象池:
using UnityEngine;
using System.Collections;
using System.Collections.Generic; public class EnemyPool : MonoBehaviour
{
public GameObject Hero;
public GameObject perfab;
List<GameObject> enemy = new List<GameObject>();
int Max_Amount = 10;
// Use this for initialization
void Start()
{
InvokeRepeating("setEnemy", 1, 10);
for (int i = 0; i < Max_Amount; i++)
{
enemy.Add(Instantiate(perfab, Vector3.left*i*2, Quaternion.identity) as GameObject);
}
}
void setEnemy()
{
for (int i = 0; i < Max_Amount; i++)
{
if (!enemy[i].GetComponent<Enemy>().getUsed())
{
enemy[i].GetComponent<Enemy>().init(true,2,enemy[i].transform.localScale,_pos,Quaternion.identity, 3);
enemy[i].GetComponent<Rigidbody>().useGravity = true;
return;
}
}
print("enemy all busy! create new!");
addEnemy();
}
void addEnemy()
{
enemy.Add(Instantiate(perfab, Vector3.zero, Quaternion.identity) as GameObject);
++Max_Amount;
}
}
此处博主设定每10秒钟生成一个敌人,可以自动扩充对象池。
setEnemy()为生成一个敌人,在
setEnemy()方法中我们遍历所有敌人对象来寻找未使用的敌人,再标记为标为使用,再初始化敌人属性,就成功“生成“了一个敌人。对于遍历所产生的
消耗有一种办法,把分为使用和未使用两个表,create时就从未使用的表中获取,再放入使用中的表中。
addEnemy()方法为扩充一个敌人,使用List<T>的add方法。
实现结果:
博主近期渲染:最近用unity5弄的一些渲染
---- by wolf96
游戏开发设计模式之对象池模式(unity3d 示例实现)的更多相关文章
- GoLang设计模式06 - 对象池模式
这次介绍最后一个创建型模式--对象池模式.顾名思义,对象池模式就是预先初始化创建好多个对象,并将之保存在一个池子里.当需要的时候,客户端就可以从池子里申请一个对象使用,使用完以后再将之放回到池子里.池 ...
- 游戏开发设计模式之状态模式 & 有限状态机 & c#委托事件(unity3d 示例实现)
命令模式:游戏开发设计模式之命令模式(unity3d 示例实现) 对象池模式:游戏开发设计模式之对象池模式(unity3d 示例实现) 原型模式:游戏开发设计模式之原型模式 & unity3d ...
- 游戏开发设计模式之原型模式 & unity3d JSON的使用(unity3d 示例实现)
命令模式:游戏开发设计模式之命令模式(unity3d 示例实现) 对象池模式:游戏开发设计模式之对象池模式(unity3d 示例实现) 实现原型模式 原型模式带来的好处就是,想要构建生成任意独特对象的 ...
- java设计模式之实现对象池模式示例分享
http://www.jb51.net/article/46941.htm 对象池模式经常用在频繁创建.销毁对象,且对象创建.销毁开销很大的场景,比如数据库连接池.线程池.任务队列池等.本代码简单,没 ...
- 对象池模式(Object Pool Pattern)
本文节选自<设计模式就该这样学> 1 对象池模式的定义 对象池模式(Object Pool Pattern),是创建型设计模式的一种,将对象预先创建并初始化后放入对象池中,对象提供者就能利 ...
- 游戏开发设计模式之命令模式(unity3d 示例实现)
博主才学尚浅,难免会有错误,尤其是设计模式这种极富禅意且需要大量经验的东西,如果哪里书写错误或有遗漏,还请各位前辈指正. 打 算写设计模式的目的就是,首先自己可以理清思路,还有就是国内的设计模式资料很 ...
- 游戏设计模式——Unity对象池
对象池这个名字听起来很玄乎,其实就是将一系列需要反复创建和销毁的对象存储在一个看不到的地方,下次用同样的东西时往这里取,类似于一个存放备用物质的仓库. 它的好处就是避免了反复实例化个体的运算,能减少大 ...
- C++设计模式 之 “对象性能” 模式:Singleton、Flyweight
“对象性能”模式 面向对象很好地解决了“抽象”的问题,但是必不可免地要付出一定的代价.对于通常情况来讲,面向对象的成本大都可以忽略不计.但是某些情况,面向对象所带来的成本必须谨慎处理. 典型模式 # ...
- C++设计模式 之 “对象创建”模式:Factory Method、Abstract Factory、Prototype、Builder
part 0 “对象创建”模式 通过“对象创建” 模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定.它是接口抽象之后的第一步工作. 典型模式 Fact ...
随机推荐
- android 微信分享没反应问题总结
一.废话 我必须说我再这个上面吃了很多的亏,所以希望有人不跟我一样吃亏.因为我本身不够仔细的原因,所以我希望能够做一些总结.---废话讲完. 这个文章已经过时了.是几年前写的.http://www. ...
- SQL Server 2008文件与文件组的关系
此文章主要向大家讲述的是SQL Server 2008文件与文件组,其中包括文件和文件组的含义与关系,文件.文件组在实践应用中经常出现的问题,查询文件组和文件语句与MSDN官方解释等相关内容的介绍. ...
- iOS---There was an internal API error 错误
There was an internal API error. 错误原因:把Product Name作为程序名称,程序名称错乱 解决方法:检查Product Name, 不要包含中文以及特殊字符.在 ...
- 类库探源——System.Type
一.MSDN 描述 Type 类:表示类型声明:类类型.接口类型.数组类型.值类型.枚举类型.类型参数.泛型类型定义.以及开放或封闭构造的泛型类型. 命名空间: System 程序集:mscorlib ...
- wireshark添加用户执行
默认情况下,访问网络端口需要root权限,而wireshark的只是/usr/share/dumpcap的一个UI,/usr/share/dumpcap需要root权限,所以没法non-root用户无 ...
- C 语言 printf格式控制详解
闲来无事,整理了一下C语言printf() 的格式控制语句. PS:详细来源于网络. printf的格式控制的完整格式: % - 0 m.n l或h 格式字符 下面对组成格式说明的各项加以说 ...
- Android学习3—电话拨号器
本测试主要实现了一个Android的拨打电话的功能 一:界面预览 由图中可以看出,这个Activity需要3个控件:TextView.EditText.Button 其实实现一个功能要经过几个步骤: ...
- Install-Package 那点事儿
为了练习使用SignaR,新建了一个.net 4.0的MVC4项目, 第一步,不用说就是先将SignaR安装到项目中,考虑到SignaR 目前已经更新到2.0 并且无法在 4.0框架下面使用,此时通过 ...
- c#配置文件appStrings配置节的读取、添加和修改
程序开发中经常会用到应用程序配置文件,好处就是维护人员可以直接修改配置文件进行维护,而不用修改程序.好,切入主题. 给项目添加应用程序配置文件App.config,先在里面写几句: <?xml ...
- js判断用户进入设备代码
var system ={ win : false, mac : false, xll : false }; //检测平台 var p = navigator.platform; system.win ...