成都快型网络公司排名,昆明网站推广优化公司,wordpress是英文版的,cms企业网站源码本文首发于#xff1a;https://github.com/bigo-frontend/blog/ 欢迎关注、转载。
egret是一款小游戏开发引擎#xff0c;支持跨平台开发#xff0c;之前使用这款引擎开发了一款捕鱼游戏#xff0c;在这里简单聊下再egret中关于对象池的使用#xff0c;虽然该引擎已经停止…
本文首发于https://github.com/bigo-frontend/blog/ 欢迎关注、转载。
egret是一款小游戏开发引擎支持跨平台开发之前使用这款引擎开发了一款捕鱼游戏在这里简单聊下再egret中关于对象池的使用虽然该引擎已经停止维护了但是对象池的概念适合通用的游戏场景不限框架。
起因
关于对象池的使用主要是有两个场景一个是捕鱼游戏里面鱼的生成还有一个是射击过程中子弹的生成。当用户处于游戏时这两个场景会频繁的生成对象并展示对应的动画会造成大量的内存碎片以及频繁的分配内存空间。而通过对象池能够比较好的解决这个问题。
对象池模式
首先定义一个池对象用来存储可复用的对象。池对象包含两组列表一组为可复用hash对象一组为正在使用的hash对象。在游戏加载游戏资源的时候对池对象进行初始化创建了一个鱼对象集合并且同时初始化可复用hash对象作为备用池。
当游戏资源加载完成的同时向对象池尝试获取一个可复用的鱼对象对象池查询可复用hash对象是否存在可以复用的鱼对象存在可复用对象的时候将对象进行初始化并将对象的索引从可复用hash对象中移除加入正在使用的hash对象。当鱼对象在游戏舞台中被移除的时候将其进行回收到可复用hash对象等待下一轮渲染。通过这种方式避免了大量的重复对象的创建跟销毁减少不必要的内存分配。
实现方式
首先设计一个工厂方法实现一个FishGenerator类负责各种类型Fish的生成Distributor类负责各类鱼的回收与存储。 鱼的实现如下前期开发过程中不同种类的鱼没有单独分开类实现都是通过传入骨骼动画与类型内部实现的所以这里通过 type 来识别不同的鱼进行获取与复用。 hashc 是 egret 本身的 hashCode 通过 hashc 允许外部访问并且由于其具有唯一性所以将其作为存储管理的下标。
interface IFish {hashc:number; //hashCodetype:string; //类型标识isIdle:boolean; //标记是否空闲lastUsed: number // 上次使用时间dispose():void; //释放对象内部引用del():void; //彻底释放对象reset():void; //重置setProtocol( val:IDistributor ):void; //设置协议
}Distributor 的实现如下 distribution 负责将生成或者复用的鱼分配到对应的hash对象并删除其再原先hash对象上的引用 clearRegularly 则是定时清除过久未复用的鱼对象减少复用hash对象所占的内存
interface IDistributor {distribution(val:IFish):void; //分配addFish(val:IFish):void; //添加元素getFish(type:string):IFish; //获取元素clear():void; //清除所有未使用的对象clearRegularly(): void; // 定期清除过久未使用的对象
}BashFish 源代码如下 reset 方法重置鱼的空闲状态重新在空闲池跟使用池之间进行分配记录鱼的使用时间作为定期清除的标识。 dispose 方法则是释放鱼将鱼的状态重置为空闲状态并将鱼重新分配。
class FishBase extends egret.Sprite implements IFish {private _isIdle: boolean false;private _dis:IDistributor null;public type:string ;public lastUsed: number 0;...//more code...constructor(factory: dragonBones.EgretFactory, config: fishTypeConfig) {super();this.type config.type;...// more code...}public reset():void {// 重置当前鱼的对象空闲状态为false并且更新使用时间将其进行对象的交互this._isIdle false;this.lastUsed Date.now();this._dis.distribution(this);}public get hashc():number {return this.hashCode;}public get isIdle():boolean {return this._isIdle;}public dispose():void {this._isIdle true;// 重新进行分配this._dis.distribution(this);}public del():void {this.dispose();this._dis null;}public setProtocol( val:IDistributor ):void {// 建立Distributor链接this._dis val;}// 离开舞台后移除鱼remove() {this.dispose();}...// more code...
}
...
FishGenerator 源代码如下FishGenerator 对外暴露expansion和getFish方法expansion方法是当空闲池不足时一次性创建大量的空闲的鱼备用getFish方法是通过Distributor获取空闲池中的鱼当空闲池中的鱼不足的时候创建新的鱼分配到空闲池中并将鱼进行返回。
class FishGenerator {private _dis:IDistributor null;...//more code...public constructor( val:IDistributor ) {this.init(val);}private init(val:IDistributor):void {this._dis val;}public expansion(factoryList: any, num) {const len factoryList.length;for (let i 0; i len; i 1) {const item factoryList[i];const fish this.createFish(item.factory, item.config);this._dis.addFish(fish);fish.reset();}}public getFish(factory: any, config:any):IFish {let fish:IFish this._dis.getFish(config.type);// 无法进行复用则创建一个新的鱼对象if(fish null) {fish this.createFish(factory, config);this._dis.addFish(fish);fish.reset();}return fish;}private createFish(factory: any, config:any):IFish {return new FishBase(factory, config);}...//more code...
}分配器源代码如下对外提供distributionaddFish getFishclear以及clearRegularly方法 distribution根据鱼的状态进行重新分配 addFish建立鱼跟Distributor 的链接并将鱼分配到空闲池 getFish获取可复用的鱼 clear清除空闲鱼群 clearRegularly 获取鱼次数达到500的倍数的时候清除过久未使用的空闲鱼群 class Distributor implements IDistributor {private _UsedPool:Object null; //使用中的鱼private _IdlePool:Object null; //空闲的鱼private count:number 0;...//more code...public constructor() {this._IdlePool {};this._UsedPool {};}// 将鱼进行重新分配空闲状态分配到空闲hash对象使用中分配到使用hash对象// 移除原先的引用public distribution( val:IFish ):void {if(val.isIdle) {this._IdlePool[val.hashc] val;delete this._UsedPool[val.hashc];} else {this._UsedPool[val.hashc] val;delete this._IdlePool[val.hashc];}}public addFish(val:IFish):void {val.setProtocol(this);if(val.isIdle) {this._IdlePool[val.hashc] val;} else {this._UsedPool[val.hashc] val;}}public getFish(type:string):IFish {this.count 1;let obj:IFish null;const keys Object.keys(this._IdlePool);for (let i 0,len keys.length; i len; i 1) {const key keys[i];obj this._IdlePool[key] as IFish;// 如果类型一致则为可复用对象返回引用并重置状态if (obj.type type) {obj.reset();if (this.count % 500 0) this.clearRegularly();return obj;}}if (this.count % 500 0) this.clearRegularly();return null;}public clear():void {let obj:IFish null;for (let key in this._IdlePool) {obj this._IdlePool[key] as IFish;// 释放与Distributor的链接obj.del();}this._IdlePool null;this._IdlePool {};}private clearRegularly() {const cur Date.now();const keys Object.keys(this._IdlePool);for (let i 0,len keys.length; i len; i 1) {const key keys[i];const obj this._IdlePool[key] as IFish;// 复用hash中存在10分钟内未复用过的对象进行销毁动作if (cur - obj.lastUsed 600 * 1000) { obj.del();delete this._IdlePool[key];}}}...//more code...
}最终效果
游戏运行期间鱼的总数量维持在80-114之间内存稳定在27-31mb之间游戏效果总体流畅度得到相应的提升用户的游戏体验得到改善。目前游戏整体效果得到一定的提升但仍存在性能优化的空间后续会继续提升游戏的性能给用户更好的体验。
欢迎大家留言讨论祝工作顺利、生活愉快
我是bigo前端下期见。