目录
对象池优化内存
1、对象池优化是游戏开发中非常重要的优化方式,也是影响游戏性能的重要因素之一。
2、游戏中有许多对象会不停的创建与移除,比如角色攻击子弹、特效的创建与移除,NPC(非玩家角色)的被消灭与刷新等,在创建过程中非常消耗性能,特别是数量多的情况下。
3、对象池技术能很好解决以上问题,在对象移除消失的时候回收到对象池,需要新对象的时候直接从对象池中取出使用。
4、对象池的优点是减少了实例化对象时的开销,且能让对象反复使用,减少了新内存分配与垃圾回收器运行的机会。
5、注意:对象移除时并不是立即从内存中抹去,只有认为内存不足时,才会使用垃圾回收机制清空,清空时很耗内存,很可能就会造成卡顿现象。用了对象池后将减少程序的垃圾对象,有效的提高程序的运行速度和稳定性。
对象池 Pool
Package | laya.utils |
类 | public class Pool |
Inheritance | Pool Object |
1、Pool 是对象池类,用于对象的存贮、重复使用。合理使用对象池,可以有效减少对象创建的开销,避免频繁的垃圾回收,从而优化游戏流畅度。
Method(方法) | |
---|---|
clearBySign(sign:String):void ,[static] 清除对象池的对象。 |
Pool |
getItem(sign:String):* ,[static] 根据传入的对象类型标识字符,获取对象池中已存储的此类型的一个对象,如果对象池中无此类型的对象,则返回 null 。 |
Pool |
getItemByClass(sign:String, cls:Class):* [static] 根据传入的对象类型标识字符,获取对象池中此类型标识的一个对象实例。 当对象池中无此类型标识的对象时,则根据传入的类型,创建一个新的对象返回。 |
Pool |
getItemByCreateFun(sign:String, createFun:Function):* [static] 根据传入的对象类型标识字符,获取对象池中此类型标识的一个对象实例。 当对象池中无此类型标识的对象时,则使用传入的创建此类型对象的函数,新建一个对象返回。 |
Pool |
getPoolBySign(sign:String):Array ,[static] 根据对象类型标识字符,获取对象池。 |
Pool |
recover(sign:String, item:Object):void ,[static] 将对象放到对应类型标识的对象池中。 |
Pool |
官网 API:https://layaair.ldc.layabox.com/api/?category=Core&class=laya.utils.Pool
2、其中较常用是 getItemByClass() 与 recover() 方法。
/**
* <p>根据传入的对象类型标识字符,获取对象池中此类型标识的一个对象实例。</p>
* <p>当对象池中无此类型标识的对象时,则根据传入的类型,创建一个新的对象返回。</p>
* @param sign 对象类型标识字符。
* @param cls 用于创建该类型对象的类。
* @return 此类型标识的一个对象。
*/
static getItemByClass(sign: string, cls: any): any;
/**
* 将对象放到对应类型标识的对象池中。
* @param sign 对象类型标识字符。
* @param item 对象。
*/
static recover(sign: string, item: any): void;
编码示例
如上所示演示每隔 100 帧使用对象池方法创建 100 个雪花,当雪花移动超出边界或缩放小于 0 时进行了移除舞台,并调用Pool.recover() 方法,使指定的对象回收至对象池内。
Laya.init(1136, 640, Laya.WebGL);//初始化引擎,不支持 WebGL自动切换为Canvas
Laya.Stat.show(0, 0);/**显示性能面板 */
Laya.stage.scaleMode = Laya.Stage.SCALE_SHOWALL;//按照最小比率缩放
Laya.stage.bgColor = "#232628";//背景颜色
Laya.timer.frameLoop(1, this, onFrame);//帧循环,每隔1帧调用一次 onFrame函数
var createTime = 0;
/**帧动画回调 */
function onFrame() {
//如果创建对象时间为100帧间隔后,即间隔100帧(约1.6秒)生成100个雪花从天而降
if (createTime >= 100) {
for (var i = 0; i < 100; i++) {//每100帧间隔创建100个雪花
/**
* 不使用对象池写法:var img = new Image();
*/
//通过对象池创建图片,如对象池中无相应的对象,则根据Image类型执行new Image()创建
/**
* getItemByClass(sign: string, cls: any) 根据传入的对象类型标识字符,获取对象池中此类型标识的一个对象实例.
* 当对象池中无此类型标识的对象时,则根据传入的类型,创建一个新的对象返回.
* sign 对象类型标识字符.cls 用于创建该类型对象的类.@return 此类型标识的一个对象
*/
var img = Laya.Pool.getItemByClass("snowflake", Laya.Image);
img.anchorX = img.anchorY = 0.5;//通过锚点设置轴心点,值为0-1
img.skin = "res/snow0.png"//设置图片资源(皮肤),图片尺寸 100 * 100
//在舞台上方随机位置创建
img.x = Math.random() * Laya.stage.width;
img.y = Math.random() * -150;
/**
* 因为雪花在下落过程中会逐渐减小 scaleX、scaleY,从而让雪花看起来越来越小
* 当超出边界后会将雪花(图片)对象回收到对象池,所里从对象池中的取出的图片是被缩放了的,这里需重置其缩放属性
* 同理如果对象中还有其他属性被改变了,下落之前也应该进行重置
*/
img.scaleX = img.scaleY = 1;
Laya.stage.addChild(img);//加载到舞台显示
createTime = 0;//100帧后创建完对象后时间将时间归0
}
} else {
createTime++;//更新创建时间
}
animation();
}
/**刷新整个舞台中的所有雪花的位置以及状态信息 */
function animation() {
/**
* readonly numChildren: number 子对象数量,这是超类 laya.display.Node 中的属性
* getChildAt(index: number): Node 根据子节点的索引位置,获取子节点对象。继承自超类 laya.display.Node
*/
for (var j = 0; j < Laya.stage.numChildren; j++) {
var img = Laya.stage.getChildAt(j);
img.y++;//位置更新,垂直降落
img.scaleX -= 0.001;//对雪花大小进行缩放
img.scaleY -= 0.001;//对雪花大小进行缩放
img.rotation++;//对雪花(图片)进行旋转
//超出边界或缩放小于0时,将对象进行回收并从舞台中清除
if (img.y > Laya.stage.height || img.scaleX <= 0) {
/**removeChild(node: Node): Node 删除子节点
* 从舞台中移除雪花(图片),继承自超类 laya.display.Node */
Laya.stage.removeChild(img);
/**recover(sign: string, item: any) 将对象放到对应类型标识的对象池中。
* sign 对象类型标识字符。item 对象。
*/
Laya.Pool.recover("snowflake", img);
// img.destroy(); //不使用对象池的编写方式时,直接用destroy清空
}
}
}
示例使用的图片资源: