关于游戏性能优化的技巧

关于游戏性能优化的技巧

  • 游戏性能优化
  • 对象池
  • Jobs、Burst、多线程
  • 间隔处理
  • 定时更新
  • 全局广播
  • 缓存组件
  • 缓存常用数据
  • 2D残影优化
  • 2D骨骼转GPU动画
  • 定时器
  • 优化DrawCall合批处理
  • 优化碰撞层
  • 优化粒子特效

游戏性能优化

好久没有在CSDN上面写文章了,今天突然看到鬼谷工作室技术负责人分享的关于游戏性能优化的技巧想梳理一下游戏优化这块的理解,这篇文章不会从细节入手,针对的是大部分游戏性能瓶颈期和对优化没有完整概念的开发。优化的方法和手段很多如果我说的不详细的地方欢迎大家评论探讨,感谢。

对象池

对象池可以重复利用某一些对象,避免重复的创建实例化。比如特效使用对象池,当特效销毁时可以隐藏起来,并添加到对象池中没下次需要创建一样的特效时只需要从对象池中返回特效,并从对象池中移除。下次再使用这个对象池的时候就不需要重新实例化了。对象类别还包括游戏中常见的一些怪物模型、特效、音频、血条、飘字等等,还有一些辅助单刀的临时节点。我们使用技能的时候会创建很多弹道,这些弹道的移动轨迹是通过辅助节点来移动的。这些辅助节点创建的频率频繁,如果使用对象池,这些节点就不再需要重复创建。但是要注意,如果特效中使用了异步的功能,在加入到对象池之后记得要关闭,否则下次可能会有BUG。

在这里插入图片描述
在这里插入图片描述

Jobs、Burst、多线程

游戏中一些复杂的逻辑可能都是在主线程下面编写的如果游戏的复杂逻辑比较多,就会造成主线程的压力大,这个时候就可以使用多线程。但是,多线程使用不当可能会导致上下文切换比较频繁或线程锁的问题。使用Jobs就可以安全方便的编写多线程代码,最终可以提升上百倍的效率。我们弹道的移动轨迹和复杂公式,包括各种大地图上AI的评分都可以使用Jobs来编写,但是编写的东西要和主代码脱离,否则你可能会有很多模块化之间的交互。如果你的寻路之类使用Jobs写不太方便的话,可以直接采用多线程来进行优化。
在这里插入图片描述

间隔处理

比如1秒钟内创建了几十个怪物,即使有对象池,怪物的初始化也是需要时间的,这时就可以把怪物分摊到多帧间隔中创建,避免同一帧的卡顿。还有声音和特效,创建一个弹道可能会发出声音,一个技能使用的时候可能会创建几十个弹道,这个时候声音是不需要重复创建的,可以只创建一个声音。对于特效,比如打到怪物上面会有被击效果,弹道比较密集,此时你的特效可以考虑间隔处理,让它达到一定时间才会创建。
在这里插入图片描述

定时更新

血量UI、效果图标、技能CD等这些UI是不需要频繁更新的。每一次击打怪物的时候造成广播,可能造成1秒钟之内更新几百上千次UI。此时可以做间隔更新,比如设置一个最短时间或者定时更新,减少更新次数。对于技能上的逻辑,比如我们有一个技能,场上没存在一把剑影,移动速度加10。场上的弹道销毁和创建的频率比较高,不能鉴听创建和销毁的广播,此时就可以定时检测场上的弹道数量,降低检测频率。

在这里插入图片描述

全局广播

图中,最右边是大招,最中间是器灵、法宝、逆天改命和后天气运,加起来可能会有200个左右的被动技能。这些被动技能很多是监听,即打到人时做什么事情或者使用什么技能做出的事情,当然还有一些是一次性加属性的,比如近战之后某些技能攻击增加、弹道数量增加。我们监听性效果是比较多的,近战可能可以达到上百个监听性的效果。
在这里插入图片描述举个例子,最右边图中是刚刚那个技能,黄色框的是监听攻击到单位时就造成伤害的提升或释放技能,下面的是监听使用技能时场上所有的效果,达到一定层数就会额外提升发射弹道。比如黄色的这种,如果我们使用监听的方式,打到敌人时候判断攻击者是否是自己,攻击的技能是否是此技能。那么我们的所有伤害都会被监听到,是很浪费效率的,可以把广播拆细一点,比如指定角色使用了指定技能攻击到敌人,此时效果监听只需要把效果、身上挂载的单位和配置表上填写的技能ID组成一个唯一的串来监听这个技能打到的伤害,就可以把无效的广播去掉。下面的这个使用技能的广播也一样,如果用使用技能的单位和使用的技能来判断,会有很多无效判断。那么可以采用和上面一样的逻辑,使用指定角色和指定ID组成的一个唯一串来广播,只有有效的技能才会收到广播。如果我们技能频率比较高,比如1秒钟造成3000次伤害,监听很多无效广播来做判断会比较浪费效率。
在这里插入图片描述

缓存组件

频繁的获取组件也是不好的。比如子弹发射时,每次发射会获取到它的碰撞体来监听碰撞的敌人,然后造成伤害。当弹道过多的时,每次发射都进行获取是浪费性能的,这个时候可以把组件缓存起来。例如,对象池中组成的特效类似于右边的那个类,里面包含特效的对象,包括很多缓存的组件,动画、碰撞体等等。这个时候如果要获取组件,可以通过这个缓存的组件来获取,那么所有组件只有在第一次初始化的时候才会获取一次,不需要每次都获取。
在这里插入图片描述

缓存常用数据

我们在弹道表中可能会配置一些弹道速度和持续时间,如果在弹道类里面每次创建弹道的时候都来读取这个数据是浪费效率的,因此可以把这些数据储存到技能上面,通过技能传递数据到弹道类中,弹道类就不需要来堆配置表了。一般还有两种缓存,一种是不需要实时更新的数据,比如说角色战力、角色的各种向性评分,还有它的喜好评分,可以在一段时间内更新一次,也可以把这个数据缓存起来,通过系统或其他方式来更新。另外一种就是固定的数据,比如密集微粒。我们的密集微粒是通过它密集组装的词条来生成的。密集词条越高,它的威力就越高,这个值是固定的,只需要在首次创建的时候把它缓存,下次就不需要重新计算了。在这里插入图片描述

2D残影优化

Unity的2D残影方式一般都是实例化模型的当前动画这一帧,并把动画速度设置为0来实现。但是就算把动画速度设置为0,骨骼还是会继续模拟的,所以当场景过多时,对性能会有一定影响。优化场景的方法也很简单,每次创建残影时不再需要实例化整个模型,而是便利模型所有的精灵,读取精灵的顶点、UV等数据,创建出一个网格,通过设置网格的材质来实现残影效果。模型在创建残影时就不需要实例化来创建了,并且在创建残影时的网格也可以加到对象池当中复用,下一次同一个模型来创建残影时就可以通过对象池来获取数据,只需要把当前模型上精灵的顶点、UV等数据复制到那个网格中。但是这个操作比较耗时,可以开一个线程来做,这样在主线程几乎体会不到性能的消耗。在获取那些精灵的组件时,也可以把组件缓存起来,下次从缓存的地方来获取。
在这里插入图片描述

2D骨骼转GPU动画

先看右边这张图,密密麻麻的点就是一个2D角色,这个角色不是一个简单的面片,每个角色有100多个顶点,这里面有10000个角色。2D残影优化说到的骨骼性能问题,在这种同屏上有很多2D单位有动画模拟的时候性能是消耗比较高的。优化方法和2D残影差不多,就是把CPU的骨骼运动转到GPU上面。GPU的动画优点是可以解决CPU模拟动画时会有的性能消耗问题,但缺点是无法使用动画控制器功能,如动画过渡,动态骨骼也无法绑定。如果模型的顶点数量太多,单个动画的时长太长,就会导致这张贴图过大。
在这里插入图片描述
下面简单讲一下转换的思路。
转换动画的第一步是编写工具来读取骨骼动画上面的顶点数据,导出为GPU需要的资源。最左边的这张图包含了所有的动画文件和动画配置。动画配置指的是一些所需数据,比如动画时长,每个动画的名称、缩影等等。图集就是原来的贴图,图集材质就是自定义的一个Shader,可以自己控制这个骨骼动画的播放,网格就是读取模型上的所有精灵,通过这个精灵来生成一个网格。
中间这张图就是转换动画图的思路。动画的帧数一帧帧循环,然后读取网格上面的顶点数量,把每一个顶点的数据储存到图片上面,然后就可以通过Shader来驱动动画的模仿。右边的那张是生成的动画图,下面的是每个顶点在图片中的布局。比如第一帧,横向的X组成了所有顶点的位置。第二帧放上去,就可以组成那些动画的顶点数据了。右边那张图可以看到,顶点的数量决定了每张图的X宽度,动画的长度决定了图片的高度,这意味着模型顶点太多就会影响图片大小,包括动画时长。
在这里插入图片描述
Shader是如何驱动图片来驱动顶点的呢?先看Shader的顶点函数,顶点函数中有顶点的ID和它的动画时间,动画时间是自己定义的一个参数。有这两个数据后,可以对贴图进行采样,采样后就能得到每个顶点的位置了。X就是1除以图片宽度,可以理解为每个像素的宽度,然后乘上顶点ID,得到每一个顶点在动画中的位置。例如,采样之后可以设置动画的时间,动画时间是一个0-1的值,0是动画的第一帧,1是动画的最后一帧,对应的采样中的Y,X就是顶点ID乘上贴图,X图片宽度可以理解为采样第几个顶点。通过采样后的顶点数据可以改变顶点的位置,每一帧进行这个操作就能用Shader驱动动画来播放了。
第三步,编写自己的动画控制器脚本。脚本中可以提供自己需要的功能,比如播放动画、播放指定动画、设置动画的播放速度、从指定时间开始播放,上一张动画配置里面记录的数据可以放到这个动画控制器里使用,这样就可以操作整个动画的播放了。
在这里插入图片描述

定时器

如果游戏中使用了大量的定时器,比如延迟一帧或延迟N秒作为一个函数,多少秒之后会销毁这个弹道等等,那么每秒钟可能会创建上千个定时器。每个定时器都单独处理是比较消耗性能的,可以把它们统一管理起来,类似于ECS的思想。做法就是做自己的一个定时器,把需要的函数传递过去,包括延迟时间,在定时器里面统一循环,到达时间了,函数就来执行,统一管理后会比单独处理的性能高很多。游戏中如果有一些移动之类的操作都可以使用ECS的思想来统一管理。
在这里插入图片描述

优化DrawCall合批处理

DrawCall如果比较高,它的帧率是比较低的,就会对性能有影响。战斗UI如果比较复杂就必须优化战斗的DrawCall,因为战斗UI是常驻的,很影响战斗中的体验,不能让UI占用太多的性能消耗。如果不在战斗中,只打开几个普通UI,性能占用就不会太大,但是如果像背包这种大量数据的地方就需要注意。UI一般可以采用动态UI和静态UI来分离,可以合批处理。例如,字体和贴图一般来说不要在一个地方混着,可以把它分离出来做合批处理;战斗中的特效,如被击特效、身上挂的buff,以及其他渲染对象尽量保持在同一渲染层,就可以做合批处理。
在这里插入图片描述

优化碰撞层

如果战斗的物理对象比较多,也是比较消耗CPU性能的,此时就要优化碰撞层,去掉不必要的碰撞检测。比如,玩家的子弹不会和玩家碰撞,子弹不会和场景脚底的障碍物碰撞,此时就要根据自己的项目来设置物理层,越简单越好。场景的物理层可以分为地板的、脚底的障碍物、大型障碍物、可破坏的障碍物等。不同层的碰撞是不会相互影响的,调整好碰撞层后可以减少物理的消耗。

在这里插入图片描述

优化粒子特效

粒子模拟使用的是CPU进行计算,当粒子的发射数量比较多时,CPU压力就会比较大。我们应该在前期就把粒子的检测工具制作好。比如特效的贴图一般是根据自己项目来制定的,上不同的平台,贴图的大小就有不一样的规范。另外,每种粒子的粒子数量也要有规范,如果同屏只有一个仙法或比较大的特效,此时它的规范就要宽一点。如果是小特效但在同屏有很多个,此时应该有不一样的规范。
可以在工具里面自定义一些规则来检测每个粒子的数量。但是数量在同屏中会出现几个弹道,一般有两种情况:第一种是比较简单的弹道,可以通过配置表获取就能知道同屏会出现几个弹道;第二种是像鬼谷一样,很多地方都会修改弹道数量,这个时候可以制作一个检测器。在内部开发时,这个检测器会运行,检测同屏中每个弹道的粒子数量以及个数。将检测器获取到的数量上传到本地服务器记录异常特效,在优化完特效后就可以将异常特效移除。开发中制作新技能的时候,弹道肯定会进行测试,通过检测器就能获取到弹道的数量,以应对比较复杂的弹道情况。检测器获取粒子数量一样可以使用缓存,把特效脚本缓存起来,下次获取的时候就不太需要编译了,性能影响也是比较小的。
在这里插入图片描述
不只是特效,所有资源都应该有一个规范。比如音效的格式、场景的贴图大小、怪物角色的顶点数量等等,应该都有一个工具来检测它们。还有,要尽量在前期考虑好游戏中哪些逻辑是比较影响性能的,根据实际情况考虑使用多线程还是Jobs。如果游戏的复杂度比较高,也可以考虑使用ECS来制作。
Unity的ECS性能是比较高的。两个程序之间,它们可能本地有几十个或者几十万个实体对象,在做联机的时候是需要同步这两个实体对象的。我们制作了一个小demo测试了一下,几十万的实体对象来同步,ECS可以把所有的组件自动生成同步代码,同步系统会自动把这些数据同步到两台服务器,几十万的实体一帧内只需要几毫秒来运行,它的效率是非常夸张的。前期可以把这些项目的规范制定好,包括程序是否需要采用DOTS还是GPU的动画,这样后期优化的工作就会比较少。

原文连接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/223297.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一篇文章带你搞定CTFMice基本操作

CTF比赛是在最短时间内拿到最多的flag,mice必须要有人做,或者一支战队必须留出一块时间专门写一些mice,web,pwn最后的一两道基本都会有难度,这时候就看mice的解题速度了! 说实话,这是很大一块&…

【C++】bind绑定包装器全解(代码演示,例题演示)

前言 大家好吖,欢迎来到 YY 滴C系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 主要内容含: 欢迎订阅 YY滴C专栏!更多干货持续更新!以下是传送门! YY的《C》专栏YY的《C11》专栏YY的《Linux》…

【视觉实践】使用Mediapipe进行目标检测:杯子检测和椅子检测实践

目录 1 Mediapipe 2 Solutions 3 安装mediapipe 4 实践 1 Mediapipe Mediapipe是google的一个开源项目,可以提供开源的、跨平台的常用机器学习(machine learning,ML)方案。MediaPipe是一个用于构建机器学习管道</

Spring IoCDI

文章目录 前言什么是Spring1. 什么是 IoC 容器1.1 什么是容器1.2 什么是 IoC 2. 什么是DI IoC & DI 的使用IoC详解Bean的存储Controller注解如何获取Bean1. 根据Bean的名称获取Bean2. 根据Bean类型获取Bean3. 根据Bean名和Bean类型获取Bean Service注解Repository注解Compo…

【深度学习】序列生成模型(六):评价方法计算实例:计算ROUGE-N得分【理论到程序】

文章目录 一、BLEU-N得分&#xff08;Bilingual Evaluation Understudy&#xff09;二、ROUGE-N得分&#xff08;Recall-Oriented Understudy for Gisting Evaluation&#xff09;1. 定义2. 计算N1N2 3. 程序 给定一个生成序列“The cat sat on the mat”和两个参考序列“The c…

阿里云林立翔:基于阿里云 GPU 的 AIGC 小规模训练优化方案

云布道师 本篇文章围绕生成式 AI 技术栈、生成式 AI 微调训练和性能分析、ECS GPU 实例为生成式 AI 提供算力保障、应用场景案例等相关话题展开。 生成式 AI 技术栈介绍 1、生成式 AI 爆发的历程 在 2022 年的下半年&#xff0c;业界迎来了生成式 AI 的全面爆发&#xff0c…

【Win10安装Qt6.3】安装教程_保姆级

前言 Windows系统安装Qt4及Qt5.12之前版本和安装Qt.12之后及Qt6方法是不同的 &#xff1b;因为之前的版本提供的有安装包&#xff0c;直接一路点击Next就Ok了。但Qt5.12版本之后&#xff0c;Qt公司就不再提供安装包了&#xff0c;不论是社区版&#xff0c;专业版等&#xff0c…

SpringMVC基础知识(持续更新中~)

笔记&#xff1a; https://gitee.com/zhengguangqq/ssm-md/blob/master/ssm%20md%E6%A0%BC%E5%BC%8F%E7%AC%94%E8%AE%B0/%E4%B8%89%E3%80%81SpringMVC.md 细节补充&#xff1a;

Mac版MySQL开启服务及终端进入MySQL的基本操作

Mac版MySQL开启服务及终端进入MySQL的基本操作 一、开启mysql服务 下载完成后&#xff0c;系统偏好设置->MySQL 如图显示&#xff0c;左边是绿色的&#xff0c;右边的按键显示是Stop MySQL Server&#xff0c;说明服务已经开启 二、终端进入mysql 1.输入下面语句并回车…

05. Springboot admin集成Actuator(一)

目录 1、前言 2、Actuator监控端点 2.1、健康检查 2.2、信息端点 2.3、环境信息 2.4、度量指标 2.5、日志文件查看 2.6、追踪信息 2.7、Beans信息 2.8、Mappings信息 3、快速使用 2.1、添加依赖 2.2、添加配置文件 2.3、启动程序 4、自定义端点Endpoint 5、自定…

【数据结构和算法】---栈和队列的互相实现

目录 一、用栈实现队列1.1初始化队列1.2模拟入队列1.3模拟出队列1.4取模拟的队列头元素1.5判断队列是否为空 二、用队列实现栈2.1初始化栈2.2模拟出栈2.3模拟入栈2.4取模拟的栈顶元素2.5判读栈是否为空 一、用栈实现队列 具体题目可以参考LeetCode232. 用栈实现队列 首先要想到…

开源 AI 新秀崛起:Bittensor 更像是真正的“OpenAI”

强大的人工智能正在飞速发展&#xff0c;而完全由 OpenAI、Midjourney、Google&#xff08;Bard&#xff09;这样的少数公司控制 AI 不免让人感到担忧。在这样的背景下&#xff0c;试图用创新性解决方案处理人工智能中心化问题、权力集中于少数公司的 Bittensor&#xff0c;可谓…

HackTheBox - Medium - Linux - Jupiter

Jupiter Jupiter 是一台中等难度的 Linux 机器&#xff0c;它有一个使用 PostgreSQL 数据库的 Grafana 实例&#xff0c;该数据库在权限上过度扩展&#xff0c;容易受到 SQL 注入的影响&#xff0c;因此容易受到远程代码执行的影响。一旦站稳脚跟&#xff0c;就会注意到一个名…

【机器学习】决策树

参考课程视频&#xff1a;https://www.icourse163.org/course/NEU-1462101162?tid1471214452 1 概述 样子&#xff1a; 2 分裂 2.1 分裂原则 信息增益 信息增益比 基尼指数 3 终止 & 剪枝 3.1 终止条件 无需分裂 当前节点内样本同属一类 无法分裂 当前节点内…

为实体服务器配置Ubuntu

简介 我们在使用虚拟机时&#xff0c;直接在网上找到镜像然后下载到本地&#xff0c;在VMware创建实例时将该iso文件作为镜像源然后进行基础配置就可以轻松安装配置好Linux虚拟机。 在为实体服务器安装Linux系统&#xff0c;同样的&#xff0c;我们也需要镜像源&#xff08;即…

nodejs+vue+ElementUi医院预约挂号系统3e3g0

本医院预约挂号系统有管理员&#xff0c;医生和用户。该系统将采用B/S结构模式&#xff0c;使用Vue和ElementUI框架搭建前端页面&#xff0c;后端使用Nodejs来搭建服务器&#xff0c;并使用MySQL&#xff0c;通过axios完成前后端的交互 管理员功能有个人中心&#xff0c;用户管…

Gartner2023数据库魔力象限发布 阿里云依旧领导者 腾讯退出 EDB/Yugabyte进入

这是一个跨越数年的系列&#xff0c;历史文章参考&#xff1a; * 数据库魔力象限2022&#xff1a;阿里领先、腾讯再次进入 * 2021 藏在魔力象限中的数据库江湖 * Gartner云计算魔力象限2018 概述 Gartner云数据库魔力象限&#xff08;后简称“象限”或“MQ”&#xff09;一…

Ubuntu 常用命令之 clear 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 clear命令在Ubuntu系统下用于清除终端屏幕的内容。这个命令没有任何参数&#xff0c;它的主要作用就是清理终端屏幕上的所有信息&#xff0c;使得屏幕看起来像是新打开的一样。 使用clear命令非常简单&#xff0c;只需要在终端中…

Linux——缓冲区

我在上篇博客留下了一个问题&#xff0c;那个问题就是关于缓冲区的问题&#xff0c;我们发现 文件有缓冲区&#xff0c;语言有用户级缓冲区&#xff0c;那么缓冲区到底是什么&#xff1f;&#xff0c;或者该怎 么认识缓冲区&#xff1f;这篇文章或许会让你有所认识&#xff0c;…

nvm安装教程, 实现nodejs多版本切换

文章目录 前言下载安装步骤切换下载镜像管理node查看版本安装指定版本使用指定版本卸载指定版本 nvm基本命令参考 前言 刚在做项目需要用到nodejs 16以上, 而我的本地安装是nodejs15, 想办法升级一下nodejs的版本. 查阅资料后发现可以下载 nvm&#xff08;Node.js 版本管理工…