Cocos Creator 游戏性能优化指南

news/2024/10/6 15:05:40/

性能优化

  • 引言
  • 一、减少Draw Call
    • 什么是Draw Call?
    • 为什么要减少Draw Call?
    • 减少Draw Call的方法
        • 1、剔除
          • I、视锥剔除:摄像机的位置和视角形成一个视锥体,只有位于视锥体内的对象才会被渲染。可以通过检查对象的包围盒(Bounding Box)是否与视锥体相交来判断对象是否需要渲染。
          • II、遮挡剔除:如果一个对象被其他对象完全遮挡,则该对象不需要被渲染。
          • III、背面剔除:对于封闭的几何体来说,朝向摄像机背面的面不需要被渲染。
          • IV、距离剔除:距离相机太远的物体不需要渲染。
        • 2、LOD
        • 3、图集
          • I、静态图集
          • II、动态图集
          • III、示例
  • 二、使用对象池
    • 1、什么是对象池?
    • 2、对象池的优缺点
    • 3、对象池的实现
  • 三、优化资源加载
    • 1、延迟加载
    • 2、预加载资源
  • 四、减少动画开销
          • 1、**减少动画帧数**:减少动画帧数可以减少CPU和GPU的负担。对于快速动作,玩家不会注意到少量帧的减少。
          • 2、**骨骼动画优化**:骨骼动画可以通过控制少量骨骼来驱动大量顶点,减少计算量。减少骨骼数量和复杂度可以进一步降低计算开销。
          • 3、**使用对象池技术复用动画对象**:通过对象池技术复用动画对象,避免频繁创建和销毁动画对象,减少内存分配和回收的开销。
  • 五、代码优化

引言

游戏开发中,流畅的游戏体验是玩家最关心的问题之一。一个卡顿的游戏会严重影响玩家的体验,甚至让玩家失去继续玩的兴趣。因此,优化游戏性能是每个游戏开发者必须掌握的技能。本文将详细介绍在使用Cocos Creator进行游戏开发时的一些性能优化技巧。

一、减少Draw Call

什么是Draw Call?

Draw Call是指CPU向GPU发出的命令,用来告诉GPU绘制某个图形图像。

为什么要减少Draw Call?

每一次Draw Call都会涉及到CPU和GPU之间的通信,这种通信是有成本的。大量的Draw Call会导致以下问题:

  • CPU开销:每个Draw Call都需要CPU发出命令,如果命令太多,会占用大量的CPU资源。
  • GPU开销:GPU需要处理每一个Draw Call的命令,导致GPU资源的浪费。
    在这里插入图片描述

GPU的绘制能力非常强大,能一次处理大量数据。但每一次Draw Call前,CPU都要做一系列的准备工作,才能让GPU正确渲染出图像。举个例子,假设你的网速是10M/s,传输一个1000M的压缩包,和传输1000个1M的文件,谁的速度快。【传输 1 个 1000M 的文件要比传输 1000个 1M 的文件要快得多得多】。因为在每一个文件传输前,CPU 都需要做许多额外的工作来保证文件能够正确地被传输,而这些额外工作造成了大量额外的性能和时间开销,导致传输速度下降。

减少Draw Call的方法

1、剔除

将不满足条件的对象整体移除,以下是实现算法:

I、视锥剔除:摄像机的位置和视角形成一个视锥体,只有位于视锥体内的对象才会被渲染。可以通过检查对象的包围盒(Bounding Box)是否与视锥体相交来判断对象是否需要渲染。
typescript">// 伪代码示例
public isInFrustum(camera, object) {
let frustum = camera.getFrustum();
let boundingBox = object.getBoundingBox();
return frustum.intersects(boundingBox);
}
II、遮挡剔除:如果一个对象被其他对象完全遮挡,则该对象不需要被渲染。
III、背面剔除:对于封闭的几何体来说,朝向摄像机背面的面不需要被渲染。
IV、距离剔除:距离相机太远的物体不需要渲染。
2、LOD

LOD算法是一种优化技术,用于减少远处或不重要物体的渲染复杂度,以提高整体渲染性能。它通过动态调整模型的细节级别,根据对象与摄像机的距离或重要性来选择不同的细节级别进行渲染。

在这里插入图片描述

  • 为同一个物体,配置不同材质(少Pass、少贴图、少计算)
  • 为同一个物体,配置不同的Mesh。例如高细节(High Poly)、中细节(Medium Poly)和低细节(Low Poly)。在渲染时,根据对象与摄像机的距离选择合适的细节级别进行渲染。
3、图集
I、静态图集

将多个小图片合并成一个大图片的方法,这样在渲染多个小图片时,只需要一次Draw Call就可以完成绘制。

Cocos Creator提供了自动图集(Auto Atlas)功能,可以方便地将多个小图自动合并成一个大图。在Cocos Creator中,可以通过资源管理器创建自动图集:

  1. 打开资源管理器,右键选择要合并的小图片文件夹。
  2. 选择“创建 -> 自动图集”。
  3. 在自动图集属性中,可以调整合并规则和参数。

使用图集

typescript">// 示例代码
resources.load('path/to/atlas', cc.SpriteAtlas, (err, atlas) => {if (err) {console.error(err);return;}let frame = atlas.getSpriteFrame('sprite_name');this.node.getComponent(cc.Sprite).spriteFrame = frame;
});
II、动态图集

Cocos Creator 提供了动态图集功能,实现机制如下:

  1. 从动态图集中获得一张 2048 x 2048 的空白纹理
  2. 当渲染一张小图时(任何一边不超过 512),如果这张小图没有被合并过,则将这张小图合并到这张空白纹理上(如果图集空间不够,则会新开空白纹理)
  3. 修改当前 2D 元素的 uv和图集信息

这样一来,小图就可以根据顺序实现自动图集分布,相邻的两个元素使用的图集会尽可能的一致。

动态图集功能在 Web 端默认开启,如果想要禁用,则需要调用:

typescript">// 禁用动态图集
DynamicAtlasManager.instance.enabled = false;

这个机制会有几个缺点。

  1. 需要开启图片内存缓存,会增一倍的内存开销
  2. 由于需要内存数据支持,目前PVR/ETC等GPU压缩格式的纹理,不支持动态图集
  3. 如果需要渲染的2D元素过多,会很容易导致图集交叉使用的情况
  4. 图集只会在场景切换时清空,对单场景不友好
III、示例

cocos creator的渲染流程中,会先渲染父节点,然后逐个渲染子节点。简单讲:深度优先。

在这里插入图片描述

因为 item 节点下的 Sprite 与 Label 节点渲染类型不同,并相互间隔排列,引擎无法向 GPU 批量提交渲染数据。

因此渲染一个 item 需要 DrawCall 4次:Sprite → Label → Sprite → Label。

优化:将Cache Mode模式改成BITMAP。Cache Mode有三种模式。

在这里插入图片描述

  • NONE:每一个 Label 都会生成为一张单独的位图,且不会参与动态合图,所以每一个 Label 都会打断渲染合批
  • BITMAP:当 Label 组件开启 BITMAP 模式后,文本同样会生成为一张位图,只要符合动态合图要求就可以参与动态合图,和周围的精灵合并 DrawCall(注意 BITMAP 模式只适用于不频繁更改的文本)。
  • CHAR:当 Label 组件开启 CHAR 模式后,引擎会将该 Label 中出现的所有字符缓存到一张全局共享的位图中,相当于是生成了一个 BMFont(适用于文本频繁更改的情况,对性能和内存最友好)。

二、使用对象池

1、什么是对象池?

对象池技术(Object Pooling)是一种优化方法,用于管理和重复利用对象,减少频繁创建和销毁对象的开销,特别适用于需要频繁生成和回收对象的场景,如子弹、敌人、特效等。通过对象池技术,可以显著提升游戏性能,减少内存碎片和垃圾回收的压力。

2、对象池的优缺点

优点

  • 提高性能:对象池通过重复利用已经创建的对象,避免了频繁的对象创建和销毁操作,从而提高了系统的性能。相比于每次都创建新的对象,从对象池中获取已经存在的对象可以节省系统开销,并显著减少了系统响应时间。
  • 节约内存和减少垃圾回收:对象池可以减少垃圾回收的频率,因为对象的重复利用降低了新对象的创建量。这样可以减少系统对内存的占用,提高内存的利用效率。
  • 资源管理和控制:对象池可以对对象进行统一的管理和控制,包括对象的创建、初始化、回收和销毁。通过对象池,可以有效地管理系统对资源的占用和释放,避免资源泄露和浪费。

缺点

  • 增加初始内存占用:对象池在初始化时会创建大量对象,占用一定的内存。

3、对象池的实现

具体实现请移步:对象池的制作

三、优化资源加载

1、延迟加载

延迟加载是指在需要使用资源时才进行加载,而不是在游戏启动时一次性加载所有资源。这样可以减少初始加载时间,提高游戏的启动速度。可以使用场景切换或事件触发时进行加载。

2、预加载资源

游戏加载阶段预先加载一些必要资源,以减少游戏运行时的卡顿。

图像:常用的装备图片、角色展示图片等常用显示图片可以在加载场景的时候就先预加载,存放在Map里面,使用时直接获取。

typescript">// 示例代码
resources.preload(['path/to/resource1', 'path/to/resource2'], (err, assets) => {// 资源预加载完成
});

四、减少动画开销

1、减少动画帧数:减少动画帧数可以减少CPU和GPU的负担。对于快速动作,玩家不会注意到少量帧的减少。
typescript">// 示例代码
let animation = node.getComponent(cc.Animation);
let clip = animation.getClip('animationName');
clip.sample = 10; // 将帧率降低到10帧每秒
animation.play('animationName');
2、骨骼动画优化:骨骼动画可以通过控制少量骨骼来驱动大量顶点,减少计算量。减少骨骼数量和复杂度可以进一步降低计算开销。
3、使用对象池技术复用动画对象:通过对象池技术复用动画对象,避免频繁创建和销毁动画对象,减少内存分配和回收的开销。

五、代码优化

1、尽量减少临时对象的创建,避免频繁触发垃圾回收。

typescript">for (let i = 0; i < 1000; i++) {let obj = getObject(); // 避免在循环中频繁创建新对象}

2、减少不必要的更新逻辑。确保update函数中只包含必要的逻辑,避免频繁调用耗时的操作。少在UPDATE里面刷新内容。多用事件触发等方式刷新。

typescript">//减少不必要的更新逻辑。确保update函数中只包含必要的逻辑,避免频繁调用耗时的操作。
update(dt) {if (this.needUpdate) {this.performUpdate(); // 仅在需要时执行更新逻辑}
}
typescript">//多用事件触发等方式刷新内容,避免频繁调用 update。
this.node.on('customEvent', this.onCustomEvent, this);

http://www.ppmy.cn/news/1473960.html

相关文章

uni-app使用ucharts地图,自定义Tooltip鼠标悬浮显示内容并且根据@getIndex点击事件获取点击的地区下标和地区名

项目场景&#xff1a; uni-app使用ucharts地图,自定义Tooltip鼠标悬浮显示内容并且根据getIndex点击事件获取点击的地区下标和地区名 例如&#xff1a; 问题描述 官方给的文档有限&#xff0c;需要自己下载地图json数据然后自己渲染和编写鼠标悬浮显示内容以及获取点击地址…

高效使用 Guzzle:POST 请求与请求体参数的最佳实践

介绍 在现代爬虫技术中&#xff0c;高效发送 HTTP 请求并处理响应数据是关键步骤之一。Guzzle 是一个强大的 PHP HTTP 客户端&#xff0c;广泛应用于发送同步和异步请求。本文将介绍如何使用 Guzzle 发送 POST 请求&#xff0c;特别是如何传递请求体参数&#xff0c;并结合代理…

【面向就业的Linux基础】从入门到熟练,探索Linux的秘密(十二)-管道、环境变量、常用命令

大致介绍了一下管道、环境变量、一些常用的基本命令&#xff0c;可以当作学习笔记收藏学习一下&#xff01;&#xff01;&#xff01; 文章目录 前言 一、管道 二、环境变量 1.概念 2.查看 3.修改 4.常用环境变量 三、系统状况 总结 前言 大致介绍了一下管道、环境变量、一些常…

Spring Boot中的领域驱动设计

Spring Boot中的领域驱动设计 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;领域驱动设计&#xff08;Domain-Driven Design&#xff0c;简称DDD&#xff09;是…

自定义编写 MySQL 语句 SELECT * 及返回对象用 MySQL 表映射类接收值为空的定位及处理

在实际的开发过程中&#xff0c;维护老代码并增加新功能是常见的任务。这篇文章将探讨在维护过程中遇到的一个问题&#xff1a;在对应的表中添加新字段后&#xff0c;表映射实体类中新增的字段因命名不符合驼峰命名规则&#xff0c;导致查询结果值为空的问题。 一、问题背景 …

每天一个数据分析题(四百零五)- 因子分析

因子分析是一种经典的统计分析方法&#xff0c;关于因子分析下列说法错误的是&#xff08; &#xff09;。 A. 因子分析是一种数据简化的技术 B. 最大似然法是因子载荷矩阵的估计方法之一 C. 因子旋转时采用最大方差旋转是一种正交旋转 D. 因子分析的假设中没有规定特殊因子…

计算机视觉是什么,涉及的关键技术和应用领域

计算机视觉是一门技术&#xff0c;它是人工智能&#xff08;AI&#xff09;的一个重要分支&#xff0c;它使计算机能够从图像或视频中识别、处理和理解视觉信息。它的研究和应用涉及多个领域&#xff0c;包括工业自动化、安全监控、医疗诊断、交通管理等。计算机视觉的应用非常…

electron教程(一)创建项目

一、方式① 根据官网描述将electron/electron-quick-start项目克隆下来并启动 electron/electron-quick-start地址&#xff1a; GitHub - electron/electron-quick-start: Clone to try a simple Electron app git clone https://github.com/electron/electron-quick-start…