当前位置: 首页 > news >正文

【bigo前端】egret中的对象池浅谈

file

本文首发于: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 对外暴露expansiongetFish方法,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...
}

分配器源代码如下,对外提供distributionaddFishgetFishclear以及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之间,游戏效果总体流畅度得到相应的提升,用户的游戏体验得到改善。目前游戏整体效果得到一定的提升,但仍存在性能优化的空间,后续会继续提升游戏的性能,给用户更好的体验。
效果1
效果2
效果3
效果4

欢迎大家留言讨论,祝工作顺利、生活愉快!

我是bigo前端,下期见。

相关文章:

【bigo前端】egret中的对象池浅谈

本文首发于&#xff1a;https://github.com/bigo-frontend/blog/ 欢迎关注、转载。 egret是一款小游戏开发引擎&#xff0c;支持跨平台开发&#xff0c;之前使用这款引擎开发了一款捕鱼游戏&#xff0c;在这里简单聊下再egret中关于对象池的使用&#xff0c;虽然该引擎已经停止…...

用公式告诉你 现货黄金投资者要不要换策略?

看过笔者相关文章的朋友都知道&#xff0c;其实笔者是相当不鼓励投资者更改策略的。但这并不意味着&#xff0c;策略不能改或者换。之所以反对更改策略&#xff0c;是因为很多人对自己的策略还没上手&#xff0c;没了解清楚就急着换策略&#xff0c;这是没必要的。通过下面这个…...

系列六、多线程集合不安全

一、多线程List集合不安全 1.1、List集合不安全案例代码 /*** Author : 一叶浮萍归大海* Date: 2023/11/20 12:38* Description: 多线层环境下List集合不安全案例代码*/ public class NotSafeListMainApp {public static void main(String[] args) {List<String> list …...

MidJourney笔记(1)-入门

注册 MidJourney注册和使用方式,有点特别。在介绍注册之前,需要给大家先介绍Discord。 Discord是一家游戏聊天应用与社区,在国内用的人相对比较少,在国外用得比较多。 那MidJourney和Discord有什么关系呢? MidJourney是搭建在Discord上的一个人工智能程序,通过在Discord添…...

CRM系统定制开发价格

我们都知道&#xff0c;CRM系统对企业有着很大的帮助。但是市面上大多数CRM系统都是标准化的&#xff0c;无法满足那些产品线复杂&#xff0c;或者有着特殊需求的企业。这个时候&#xff0c;就需要对CRM系统进行二次开发。那么&#xff0c;CRM系统二次开发的价格是多少&#xf…...

Kubernetes实战(五)-pod之间网络请求实战

1 同namespace内pod网络请求 1.1 创建namespace ygq $ kubectl create namespace ygq namespace/ygq created 1.2 创建svc和deployment 在naemspace ygq下创建两个应用&#xff1a;nginx和nginx-test。 1.2.1 部署应用nginx $ cat nginx-svc.yaml apiVersion: v1 kind: …...

7年经验之谈 —— 如何高效的开展app的性能测试?

APP性能测试是什么 从网上查了一下&#xff0c;貌似也没什么特别的定义&#xff0c;我这边根据自己的经验给出一个自己的定义&#xff0c;如有巧合纯属雷同。 客户端性能测试就是&#xff0c;从业务和用户的角度出发&#xff0c;设计合理且有效的性能测试场景&#xff0c;制定…...

小程序action-sheet结合自定义tabbar显示

要实现此效果&#xff0c;遇到的问题&#xff1a;背景在电脑端调试的情况正常的情况下&#xff0c;手机端点击事件工单&#xff0c;返回回来的时候action-sheet卡住在屏幕上&#xff0c;点击遮罩层都不消失。更奇怪的是 这种情况并不是每次发生&#xff0c;而是有时候发生&…...

机器学习笔记 - 隐马尔可夫模型的简述

隐马尔可夫模型是一个并不复杂的数学模型,到目前为止,它一直被认为是解决大多数自然语言处理问题最为快速、有效的方法。它成功地解决了复杂的语音识别、机器翻译等问题。看完这些复杂的问题是如何通过简单的模型得到描述和解决,我们会由衷地感叹数学模型之妙。 人类信息交流…...

iOS学习 --- Xcode 15 下载iOS_17.0.1_Simulator失败解决方法

1.去开发者官网下载安装包 https://developer.apple.com/download/all/?qiOS%2017 使用浏览器下载。 2.打开终端通过命令添加到xcode 命令如下&#xff1a; sudo xcode-select -s /Applications/Xcode.app(输入开始密码)xcodebuild -runFirstLaunch (等待一小会)xcrun simctl…...

多视图聚类论文阅读(二)

Deep multi-view semi-supervised clustering with sample pairwise constraints 基于样本对约束的深度多视图半监督聚类 1.1 提出的问题 提出问题&#xff1a; 多视图聚类技术多数方法都忽视了弱监督信息的重要性&#xff0c; 提出的解决方法 将自监督学习引入到了多视图…...

Docker在Centos7下的安装

1、卸载旧版本 执行如下指令对旧版本进行卸载&#xff1a; sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 执行完毕后&#xff0c;如果输入docker version发现do…...

LLM大模型4位量化实战【GPTQ】

权重量化方面的最新进展使我们能够在消费类硬件上运行大量大型语言模型&#xff0c;例如 RTX 3090 GPU 上的 LLaMA-30B 模型。 这要归功于性能下降最小的新型 4 位量化技术&#xff0c;例如 GPTQ、GGML 和 NF4。 在上一篇文章中&#xff0c;我们介绍了简单的 8 位量化技术和出…...

安装keras、tensorflow

看起来你仍然面临SSL证书验证失败的问题。这可能是由于你的网络环境或代理设置引起的。你可以尝试以下几个步骤&#xff1a; 检查网络连接&#xff1a; 确保你的计算机能够正常访问互联网。 关闭代理&#xff1a; 如果你使用了代理&#xff0c;尝试暂时关闭它&#xff0c;然后…...

ffmpeg知识点整理

使用FFmepg进行视频转码、视频格式转换、图片提取等&#xff01;_ffmepg -c:v-CSDN博客 中文文档&#xff1a; ffmpeg 中文手册 (beandrewang.github.io) 笔记&#xff1a; 通用规则是&#xff0c;所有选项作用于其后边的第一个文件。因此&#xff0c;顺序是非常重要的&…...

Git 笔记之gitignore

解释为&#xff1a;git ignore 即&#xff0c;此类型的文件将会被忽略掉&#xff0c;从而不会进行管理 具体的模板可以从 GitHub 网站上来进行设置 GitHub - github/gitignore: A collection of useful .gitignore templates Common_gitignore: gitignoregithub开源项目&…...

【配置】Redis常用配置详解

文章目录 IP地址绑定设置密码 IP地址绑定 默认情况下&#xff0c;如果未指定 “bind” 配置指令&#xff0c;Redis 将监听服务器上所有可用的网络接口的连接。 可以使用 “bind” 配置指令来仅监听一个或多个选定的接口&#xff0c;后跟一个或多个 IP 地址 示例&#xff1a;bin…...

Linux(Ubuntu)安装JDK环境

系统环境 Ubuntu20.04 下载JDK压缩包 前往Oracle官网进行后续下载或单击下载JDK压缩包 下拉找到JDK8&#xff0c;在Linux板块下选择适配系统架构的压缩包文件(后缀为tar.gz)&#xff0c;系统架构可通过uname -m命令查看 安装JDK 安装环境通常放在/usr/local下&#xff0c;进入…...

OpenCV C++ 张正友相机标定【相机标定原理、相机标定流程、图像畸变矫正】

文章目录 3.1 标定原理3.2 相机标定流程步骤1:采集棋盘格图像,批处理(调整尺寸、重命名)步骤2:提取棋盘格内角点坐标步骤3:进一步提取亚像素角点信息在棋盘标定图上绘制找到的内角点(非必须,仅为了显示)步骤4:相机标定--计算出相机内参数矩阵和畸变系数步骤5:畸变图像…...

SDL2 播放音频(MP4)

1.简介 这里引入FFmpeg库&#xff0c;获取音频流数据&#xff0c;然后通过FFmpeg将视频流解码成pcm原始数据&#xff0c;再将pcm数据送入到SDL库中实现音频播放。 2.FFmpeg的操作流程 注册API&#xff1a;av_register_all()构建输入AVFormatContext上下文&#xff1a;avform…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

uniapp 实现腾讯云IM群文件上传下载功能

UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中&#xff0c;群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS&#xff0c;在uniapp中实现&#xff1a; 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解

进来是需要留言的&#xff0c;先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码&#xff0c;输入的<>当成字符串处理回显到页面中&#xff0c;看来只是把用户输…...

PH热榜 | 2025-06-08

1. Thiings 标语&#xff1a;一套超过1900个免费AI生成的3D图标集合 介绍&#xff1a;Thiings是一个不断扩展的免费AI生成3D图标库&#xff0c;目前已有超过1900个图标。你可以按照主题浏览&#xff0c;生成自己的图标&#xff0c;或者下载整个图标集。所有图标都可以在个人或…...

电脑桌面太单调,用Python写一个桌面小宠物应用。

下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡&#xff0c;可以响应鼠标点击&#xff0c;并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...

EEG-fNIRS联合成像在跨频率耦合研究中的创新应用

摘要 神经影像技术对医学科学产生了深远的影响&#xff0c;推动了许多神经系统疾病研究的进展并改善了其诊断方法。在此背景下&#xff0c;基于神经血管耦合现象的多模态神经影像方法&#xff0c;通过融合各自优势来提供有关大脑皮层神经活动的互补信息。在这里&#xff0c;本研…...