获得徽章 0
#每天一个知识点#

2023/07/11

cocos ceater 中 shader 格式简介,主要是分为三大部分,配置流程,以及分别是顶点着色器,片元着色器 的处理
展开
鱼___鱼于2023-07-11 21:26发布的图片
鱼___鱼于2023-07-11 21:26发布的图片
鱼___鱼于2023-07-11 21:26发布的图片
评论
#每天一个知识点#

2023/07/10

优化Cocos Creator 包体积

优化这一步在游戏中可以说至关重要了,而优化的地方也方方面面,这里就看看再 cocos ceater 中对包体的优化

首先按需导入啦,在cocos ceater 项目 - 模块设置中,我们可以按需导入需要的模块,比如,如果单纯的2D游戏,就不需要物理系统

过来就是图片资源,图片资源首先是可以在不影响效果呈现的情况下做压缩,其次是尽量使用9宫格图片,打包图集。

字体资源体积优化,尽可能使用系统字体,移除不用的字体,性能上的优化也提一嘴吧,在场景中使用系统字体或 TTF 字体的 Label 会打断渲染合批,特别是 Label 和 Sprite 层叠交错的情况,每一个 Label 都会打断合批增加一个 DrawCall,对于游戏中的文本,特别是数字、字母和符号,都建议 使用 BMFont 来代替 TTF 或系统字体,并且 将 BMFont 与 UI 碎图打包到同一图集中(或 开启动态合图),可以免除大部分文本导致的 DrawCall。
展开
评论
#每天一个知识点#
2023/07/09

游戏开发中的坐标

刚入行的时候坐标真的是个超级烦人的东西,实话说现在我都还不是特别的里的清楚,今天就大概梳理一下这块的东西吧

首先坐标都有哪些,首先分为两类,一类是世界坐标(绝对坐标),一类是本地坐标(相对坐标)。什么是世界坐标呢?那就是这个一整个游戏中的坐标系,采用的是笛卡尔右手坐标系。而本地坐标可以理解为每个节点自身的坐标系。

这也就导致为什么有些时候我们输出两个节点的坐标的时候,坐标值明明是一样的,但是实际中我们看到的确实是不一样,这是因为他们的父节点的坐标系是不同的。我们往往当想拿到某一个坐标的位置,然后把另一个节点的坐标设置到该位置的时候,就的得考虑到这一点
,也就是下面的转化公式:

本地坐标转换为世界坐标
世界坐标 = 父节点.convertToWorldSpaceAR(子节点坐标);

世界坐标转换为本地坐标
本地坐标 = 转换点.convertToNodeSpaceAR(世界坐标)
展开
评论
#每天一个知识点#
2023/07/08
cocos assetManager 资源加载管理

在游戏中,资源的加载管理也是个大问题,没有好好清楚很容易导致各种比如热更新出问题,游戏卡顿的问题等。今天简单说个关于包的问题,首先我们一般会把独立的部门设置为一个包,比如活动/关卡,这样我们可以根据运营的计划,来安排那些被开启加载等。那么设置为bundle。这里面发生什么呢,来说说里面会有的问题:

首先我们的游戏构建之后,一般就是所有资源都被分到内置包( internal / main / resources / start-scene )以及我们设置的单独 bundle 中。

在构造阶段,配置为 bundle 的文件夹就会把文件夹中的资源,以及该文件夹中依赖的其他资源合并到该 bundle 中,文件中的资源会主要被分为三类,代码 / 资源 / 资源配置,放到四个文件夹中(import/ native / config.json / index.js),另一点需要说的是bundle的优先级问题,多个包引用一个资源,如果budle 的优先级都相等,就会把这份资源复制多分,每一个bundle里面都有一份,而要是有一个优先级更高,就会只在优先级高的bundle 保存一份,而其他包引用就会指向该bundle(所以如果低优先的包要使用该资源就需要先加载这个优先级更高的 bundle)

当我们加载 包(bundle)(loadBundle() )的时候,其实并没有把这个包的资源都加载到内存里面,而是只是把 config 以及脚本加入,需要加载资源的时候我们需要 (bundle.load())来载入我们需要的资源。这里也就是我们经常一进游戏卡顿的问题,因为一进入游戏,大量的资源进行 load,导致高额IO压力。(我们现在的处理是对所有该该操作做队列处理,避免一次性同时加载).高IO在网页调试中中能看到比较明显,但相反在手机上问题更大的是 包的下载花费的时间,所以cocos 提供预加载,我们可以先下载必须的部分,而在后面缓慢下载其他资源。

资源加载后当然也需要释放,引擎也有对该部分的处理,包含计数释放,静态资源和动态资源的处理等,以及我们主动释放,另外加载进入内存的资源不会被主动释放,也会导致内存越来越大等问题
展开
3
#每天一个知识点#

2023/07/07
单例模式中
饿汉式单例和懒汉式单例

虽然之前有学习过,这两者区别,但是还是得实际工作中遇到问题了才能比较深刻的体会出两者的区别。

饿汉式和懒汉式应该是我们比较常用的单例了,昨天在工作中做的操作是进入游戏就对一个活动的控制层做初始化下载资源的数据,然后交给资源管理层做下载处理。该活动之前是另一个人同事写的,采用懒汉式的写法,没有调用单例就不会创建。但是再我今天的改动中,变一进入游戏就会对数据做初始化,这时候其实已经创建了 this,但是因为没有调用获取单例,所以这个this是没有赋值给单例的,这就导致在别的地方调用单例的时候就又创建了一个单例,创建了一个新的 this。这时候其实也就不能说这个控制层是唯一的了;那么其实这里我们一进入游戏就需要做初始化的,因该改为饿汉式单例,一进入初始化的时候就赋值单例,样的话才能确保这个单例是惟一的。

两者简单来说,懒汉式是在调用的时候才会创建,而饿汉式是只要有就创建,前者可以说是能减少内存的浪费,以为只有在第一次调用的时候才会被创建。而后者是加载的时候就初始化创建了,问题就是相反的浪费内存了,有些时候即使可能一直没有使用也创建出来,产生垃圾对象
展开
评论
#每天一个知识点#

2023/07/06

说说资源加载这个大头,之前我们的游戏,一打开就会非常卡,会卡上好几帧,这样的用户体验是非常不好的,当时排查问题,这是问什么呢?是因为我们一打开游戏就有数百个节点开始实例,读取资源,IO是一个非常耗时的操作,尤其是没有对这一块的加载做处理,这些加载都在同一时刻加载,导致IO堵塞,就会卡。

后面这一快的改动是,所有资源都是改为队列的方式加载,这就避免了一帧内过多的读取导致堵塞,同时我们在进入游戏的loading阶段就先做打开游戏就需要的资源的预加载,相当于是把一部分资源加载放到加载界面,进一步减卡顿的问题。
展开
评论
#每天一个知识点#
2023/07/05
事件总线

事件总线也叫EventBus,其实表现的方式都很多,但是基本来说都是一个思路和实现,优点和弊端也是一样的。

优点是什么呢?那就是能够很便捷的跨文件(组件)传递数据,缺点也是因为这种能够全局飞数据的方式带来的不好维护。

具体是怎么实现的呢?简单来说事件总线其实是发布 - 订阅者模式的一种实现。定义了一对多或者多对多,当发布者发布事件的时候,所有订阅者都能够得到响应,进行各自对应的操作。

比如在游戏中,我们监听数据接口,当有数据来的时候,我们可以对绑定该监听的所有视图进行数据更新。

在使用事件总线的时候,还需要注意的是取消注册,当我们离开,或者不再使用的时候,需要把之前注册的事件移除,避免错误的响应
展开
评论
#每天一个知识点#

有限状态机
首先说概念吧,有限状态机也就是 Finite-state machine, 英文简称FSM,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。

也就是当我们能够确定一个东西的所有状态的时候,我们列举出所有状态,通过不同的条件,进行不同的动作,达成最后的状态。这其中三点关键就是条件,动作,状态。

其实实际上面对这些转态转换的也就是我们常使用的 if- else ,但是使用 if- else 在一些更复杂的场景下,可读性,扩展性都不够,并且容易出错。而使用 fsm 能够对我们状态和事件统一管理。我们也可以通过画图来把转态转移画出来,这样就能更加清晰的编码状态机了。特别是在游戏中,状态的变化也是常态。
展开
评论
#每天一个知识点#

2023/07/03

我们写代码功能的时候回,要尽量事件是事件,实现是实现,建议区分开来,比如一个点击节点显示弹板的功能,这里应该分为点击触发的事件函数,和显示弹板的实现函数。因为不分开处理,不便于后续开发(哪天策划想要不同的时候点击显示不同的内容呢~,以及一般我们显示弹板,还会有比如三秒后自动消失/点击空白处消失/某种情况下不能出现/消失之类的情况,区分事件和实现会便于我们后续开发)
展开
评论
#每天一个知识点#

2023/07/02

简单说说依赖注入吧,依赖注入其实是实现控制反转的一种设计方法,消除类之间依赖关系的设计模式。比如A类要依赖B类,A类不再直接创建B类,而是传入给A。举个例子来说就是,工厂伐木,每个员工的斧头,是员工自带的,还是工厂给的。使用依赖注入的话,我们可以是实现松耦合,如果工厂现在突然急需要完成任务,改用电锯,那么改通知每一个员工带电锯,这实现起来可能就很多问题了,但是如果工厂提供的,那么相当于对于员工来说,只是接收到的该工具不同。这也就是依赖注入,实现松耦合的目的了
展开
评论
#每天一个知识点#

2023/07/01

说说控制类吧,之前做web开发,其实基本不需要写控制类,因为web开发,大多就是服务器拿数据,然后进行即时刷新。但是在游戏开发中,往往是分过程的,我们得存起数据,以及对数据的一些处理之类的。那么比如一个活动中的控制类就得有构造函数和析构函数,构造函数中我们需要对数据做初始化的处理,确保即使后端给我们的数据有问题,也是能够不报错运行的。同时我们的控制类中一般得使用单例模式,来确保控制类是唯一的。当然控制类里面的东西还不止这点,根据你活动的复杂度之类的,考虑资源的加载,等各种条件。
展开
评论
#每天一个知识点#

2023/06/30

我们在使用缓动的时候要小心,当我们在一个节点绑定缓动,如果关闭了该节点(action 置为 false)然后再打开,这时候上面挂载的缓动就会被清除掉了,如果我们需要能够再次执行,我们可以在 onEnable 里面重新打开
展开
评论
#挑战每日一条沸点#

2023/06/29

野指针问题,这算是个比较隐蔽的问题,还不好发现。当时的场景就是想在缓动中设置缩放,先放大,然后再缩小,结果最后看到的比原本的小,这就很奇怪。后面很久才发现,当时设置缓动中变化的值是个指针地址,这就导致每次变化并不是想象中放大的倍数,而是变化后的值继续乘以变化目标值。
展开
鱼___鱼于2023-06-29 22:06发布的图片
评论
#每天一个知识点#

2023/06/28

游戏中开发要切实注意的三个地方,一个是网络,二来是读取资源,三来是多节点处理。

这三个地方主要的问题是基本是异步的行为,不可控,很多时候我们没法确保信息是否回来了,资源是否加载好了,而不考虑这些因素很容易造成卡顿的现象,或者错误。比方说我们如果没有用异步其读取资源,加载资源是一个高IO的操作,这就会到导致一帧内无法执行完毕,导致看起来卡顿的感觉。
展开
评论
#每天一个知识点#

2023/06/27

分享个思路吧,今天做的业务中,发现需要处理很多种类的奖励领取,这里不同的奖励领取,流程和事件都是不确定的,并且他们没有各自的回调。这就导致没发知道这个领取是否完成结束了,来通知我走后面的步骤。当时起初的想法是有使用一个队列来维护,并且轮帧的去询问。但其实感觉这么写挺麻烦的。想有没有更加简单的,后面想到的是,在引擎垃圾回收和资源引用的地方常常是使用计数器来判断是否释放。这种计数器的思想就挺适合当前的情况的,当开始领取的地方打上加一,结束的地方减一,那么无论多少个什么种类的领取,我们只需要判断当前计数器是否为 0 ,是的话就执行下面的步骤,不是就继续等待。
展开
评论
#每天一个知识点#

2023/06/25

游戏中场景的概念(scene)

在前一个项目中是只有一个场景的,但是在后面的第二个项目,是把游戏分为两大类主场景的。首先多分场景能更清楚管理项目,我们确保同一时刻只有运行一个场景,而切换场景的时候就把上一个场景的东西都回收。如果没有使用场景,之前的开发有一个问题,那就是我们有一个金币栏的组件,没有区分场景的时候,即使进入关卡,实际上大厅的东西都是存在的,只不过看不到(被遮罩了),这时候就可能触发一些错误监听。

当然也有支持单场景的开发,单场景的话,其实就能不用考虑太多数据传递的问题。不过目前我们项目中,是把核心控件都提取出来设置为常驻,就算切换场景也不会被销毁。

对于是单场景还是多场景,其实还是得看实际的业务开发,没有绝对的正确,多场景的话便于管理,清晰,但是得考虑场景切换逻辑比较复杂,单场景所有资源都能管理处理,缺点是没法很好的管理
展开
评论
#每天一个知识点#

2023/06/24
材质(Materials),材质球(Effect),属性面板(Inspector),纹理(Texture)之间的关系

我们先看上图,图中我们创建一个单色精灵(渲染组件),你会在第三点那里(属性面板)看到有一个 Materials 的数组,这就是我们的材质数组,一个物体它的材质可以有多种,所以这是一个数组。细心的你会发现,几乎所有的渲染组件都是存在这个属性的,因为一个小球,他是塑料感还是玻璃感,其实就是材质决定的。而材质中指向的 Effect 我们也叫材质球,做用是指定纹理渲染到屏幕的方式
展开
鱼___鱼于2023-06-24 23:05发布的图片
评论
#每天一个知识点#

2022/06/23

说说在 2D游戏中实现一个一些效果吧。前端时间公司新项目需要尽可能的模拟现实中游戏的场景,也就是说我们需要实现一个3D 曲面的效果,可是我们现在的是一个 2D游戏,要基于原本的项目框架,如何实现呢?这边试验的方案首先是直接写 shader 处理渲染,简单来说就是曲面就是一个双曲线的效果嘛,所以我们计算出一个长方形投影映射为双曲线的转换公式,然后来做处理。这是方案一,其实开始也实现了这个曲面的效果,但是这个计算过程太麻烦了、后面同事又给出另有一种方式,那就是建模,这里是建了一个曲面的模型,然后我们拿到摄像机的渲染的纹理,把这个纹理设置到这个模型上,也能达到效果,这也算一种方案吧。不过其实这些都算野路子的实现,真正想实现3D的效果,其实还是应该用 3D去做,但是这样成本太高了,不过其实吧研究使用这些野路子的过程和后续的一些问题,也花了不少时间~
展开
评论
#每天一个知识点#

2023/06/22
热更新遇到的一个问题

我们一般热更新之后会重启,这样能确保文件的完整和准确,避免出错,但是前几天听同事说了个问题,这里记录一下,就是热更完,下面的 debug 显示是需要默认资源的,这时候重启游戏会报错,是因为没有那个 debug显示的默认资源,这里需要先关闭,不然的话会报错导致没法进入游戏
展开
评论
#每天一个知识点#
2023/06/21
cocos ceater对象池

在 cocos ceater 中实现对象池主要是两个基本方法,那就是获取节点,以及存储节点

获取节点的时候,我们传入需要实例的预制体,和该该节点钩挂的父节点。那么我们实现中,我们可以通过节点的名来作为 key,然后先查看是有以及有该节点池,有的话直接拿,要是没有的话我们得克隆出来,而要是没有该节点的对象池的,就需要创建该节点的对象池。
而存储的方法中,我们就是需要把该节点传入,然后判断是否有该节点池,有的话存入,没得话就得创建该节点的对象池来存入
然后我们在每一个克隆节点的地方就能换为对象池中的 getNode方法,然后销毁的地方使用 pushNode 方法,下面是最简单基本的一个实现,具体开发中,我们还需要更多的条件和对应的函数等
展开
鱼___鱼于2023-06-21 09:12发布的图片
评论
下一页
个人成就
文章被点赞 5
文章被阅读 1,250
掘力值 88
收藏集
1
关注标签
12
加入于