 
 获得徽章 0
  #每天一个知识点#  
2023/07/10
优化Cocos Creator 包体积
优化这一步在游戏中可以说至关重要了,而优化的地方也方方面面,这里就看看再 cocos ceater 中对包体的优化
首先按需导入啦,在cocos ceater 项目 - 模块设置中,我们可以按需导入需要的模块,比如,如果单纯的2D游戏,就不需要物理系统
过来就是图片资源,图片资源首先是可以在不影响效果呈现的情况下做压缩,其次是尽量使用9宫格图片,打包图集。
字体资源体积优化,尽可能使用系统字体,移除不用的字体,性能上的优化也提一嘴吧,在场景中使用系统字体或 TTF 字体的 Label 会打断渲染合批,特别是 Label 和 Sprite 层叠交错的情况,每一个 Label 都会打断合批增加一个 DrawCall,对于游戏中的文本,特别是数字、字母和符号,都建议 使用 BMFont 来代替 TTF 或系统字体,并且 将 BMFont 与 UI 碎图打包到同一图集中(或 开启动态合图),可以免除大部分文本导致的 DrawCall。  
2023/07/10
优化Cocos Creator 包体积
优化这一步在游戏中可以说至关重要了,而优化的地方也方方面面,这里就看看再 cocos ceater 中对包体的优化
首先按需导入啦,在cocos ceater 项目 - 模块设置中,我们可以按需导入需要的模块,比如,如果单纯的2D游戏,就不需要物理系统
过来就是图片资源,图片资源首先是可以在不影响效果呈现的情况下做压缩,其次是尽量使用9宫格图片,打包图集。
字体资源体积优化,尽可能使用系统字体,移除不用的字体,性能上的优化也提一嘴吧,在场景中使用系统字体或 TTF 字体的 Label 会打断渲染合批,特别是 Label 和 Sprite 层叠交错的情况,每一个 Label 都会打断合批增加一个 DrawCall,对于游戏中的文本,特别是数字、字母和符号,都建议 使用 BMFont 来代替 TTF 或系统字体,并且 将 BMFont 与 UI 碎图打包到同一图集中(或 开启动态合图),可以免除大部分文本导致的 DrawCall。
      展开
    
  评论
 
          2
        
  #每天一个知识点#  
2023/07/09
游戏开发中的坐标
刚入行的时候坐标真的是个超级烦人的东西,实话说现在我都还不是特别的里的清楚,今天就大概梳理一下这块的东西吧
首先坐标都有哪些,首先分为两类,一类是世界坐标(绝对坐标),一类是本地坐标(相对坐标)。什么是世界坐标呢?那就是这个一整个游戏中的坐标系,采用的是笛卡尔右手坐标系。而本地坐标可以理解为每个节点自身的坐标系。
这也就导致为什么有些时候我们输出两个节点的坐标的时候,坐标值明明是一样的,但是实际中我们看到的确实是不一样,这是因为他们的父节点的坐标系是不同的。我们往往当想拿到某一个坐标的位置,然后把另一个节点的坐标设置到该位置的时候,就的得考虑到这一点
,也就是下面的转化公式:
本地坐标转换为世界坐标
世界坐标 = 父节点.convertToWorldSpaceAR(子节点坐标);
世界坐标转换为本地坐标
本地坐标 = 转换点.convertToNodeSpaceAR(世界坐标)  
2023/07/09
游戏开发中的坐标
刚入行的时候坐标真的是个超级烦人的东西,实话说现在我都还不是特别的里的清楚,今天就大概梳理一下这块的东西吧
首先坐标都有哪些,首先分为两类,一类是世界坐标(绝对坐标),一类是本地坐标(相对坐标)。什么是世界坐标呢?那就是这个一整个游戏中的坐标系,采用的是笛卡尔右手坐标系。而本地坐标可以理解为每个节点自身的坐标系。
这也就导致为什么有些时候我们输出两个节点的坐标的时候,坐标值明明是一样的,但是实际中我们看到的确实是不一样,这是因为他们的父节点的坐标系是不同的。我们往往当想拿到某一个坐标的位置,然后把另一个节点的坐标设置到该位置的时候,就的得考虑到这一点
,也就是下面的转化公式:
本地坐标转换为世界坐标
世界坐标 = 父节点.convertToWorldSpaceAR(子节点坐标);
世界坐标转换为本地坐标
本地坐标 = 转换点.convertToNodeSpaceAR(世界坐标)
      展开
    
  评论
 
          4
        
  #每天一个知识点#  
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 提供预加载,我们可以先下载必须的部分,而在后面缓慢下载其他资源。
资源加载后当然也需要释放,引擎也有对该部分的处理,包含计数释放,静态资源和动态资源的处理等,以及我们主动释放,另外加载进入内存的资源不会被主动释放,也会导致内存越来越大等问题  
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
        
 
          14
        
  #每天一个知识点#  
2023/07/07
单例模式中
饿汉式单例和懒汉式单例
虽然之前有学习过,这两者区别,但是还是得实际工作中遇到问题了才能比较深刻的体会出两者的区别。
饿汉式和懒汉式应该是我们比较常用的单例了,昨天在工作中做的操作是进入游戏就对一个活动的控制层做初始化下载资源的数据,然后交给资源管理层做下载处理。该活动之前是另一个人同事写的,采用懒汉式的写法,没有调用单例就不会创建。但是再我今天的改动中,变一进入游戏就会对数据做初始化,这时候其实已经创建了 this,但是因为没有调用获取单例,所以这个this是没有赋值给单例的,这就导致在别的地方调用单例的时候就又创建了一个单例,创建了一个新的 this。这时候其实也就不能说这个控制层是唯一的了;那么其实这里我们一进入游戏就需要做初始化的,因该改为饿汉式单例,一进入初始化的时候就赋值单例,样的话才能确保这个单例是惟一的。
两者简单来说,懒汉式是在调用的时候才会创建,而饿汉式是只要有就创建,前者可以说是能减少内存的浪费,以为只有在第一次调用的时候才会被创建。而后者是加载的时候就初始化创建了,问题就是相反的浪费内存了,有些时候即使可能一直没有使用也创建出来,产生垃圾对象  
2023/07/07
单例模式中
饿汉式单例和懒汉式单例
虽然之前有学习过,这两者区别,但是还是得实际工作中遇到问题了才能比较深刻的体会出两者的区别。
饿汉式和懒汉式应该是我们比较常用的单例了,昨天在工作中做的操作是进入游戏就对一个活动的控制层做初始化下载资源的数据,然后交给资源管理层做下载处理。该活动之前是另一个人同事写的,采用懒汉式的写法,没有调用单例就不会创建。但是再我今天的改动中,变一进入游戏就会对数据做初始化,这时候其实已经创建了 this,但是因为没有调用获取单例,所以这个this是没有赋值给单例的,这就导致在别的地方调用单例的时候就又创建了一个单例,创建了一个新的 this。这时候其实也就不能说这个控制层是唯一的了;那么其实这里我们一进入游戏就需要做初始化的,因该改为饿汉式单例,一进入初始化的时候就赋值单例,样的话才能确保这个单例是惟一的。
两者简单来说,懒汉式是在调用的时候才会创建,而饿汉式是只要有就创建,前者可以说是能减少内存的浪费,以为只有在第一次调用的时候才会被创建。而后者是加载的时候就初始化创建了,问题就是相反的浪费内存了,有些时候即使可能一直没有使用也创建出来,产生垃圾对象
      展开
    
  评论
 
          1
        
 #每天一个知识点# 
2023/07/05
事件总线
事件总线也叫EventBus,其实表现的方式都很多,但是基本来说都是一个思路和实现,优点和弊端也是一样的。
优点是什么呢?那就是能够很便捷的跨文件(组件)传递数据,缺点也是因为这种能够全局飞数据的方式带来的不好维护。
具体是怎么实现的呢?简单来说事件总线其实是发布 - 订阅者模式的一种实现。定义了一对多或者多对多,当发布者发布事件的时候,所有订阅者都能够得到响应,进行各自对应的操作。
比如在游戏中,我们监听数据接口,当有数据来的时候,我们可以对绑定该监听的所有视图进行数据更新。
在使用事件总线的时候,还需要注意的是取消注册,当我们离开,或者不再使用的时候,需要把之前注册的事件移除,避免错误的响应  
2023/07/05
事件总线
事件总线也叫EventBus,其实表现的方式都很多,但是基本来说都是一个思路和实现,优点和弊端也是一样的。
优点是什么呢?那就是能够很便捷的跨文件(组件)传递数据,缺点也是因为这种能够全局飞数据的方式带来的不好维护。
具体是怎么实现的呢?简单来说事件总线其实是发布 - 订阅者模式的一种实现。定义了一对多或者多对多,当发布者发布事件的时候,所有订阅者都能够得到响应,进行各自对应的操作。
比如在游戏中,我们监听数据接口,当有数据来的时候,我们可以对绑定该监听的所有视图进行数据更新。
在使用事件总线的时候,还需要注意的是取消注册,当我们离开,或者不再使用的时候,需要把之前注册的事件移除,避免错误的响应
      展开
    
  评论
 
          1
        
  #每天一个知识点#  
有限状态机
首先说概念吧,有限状态机也就是 Finite-state machine, 英文简称FSM,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
也就是当我们能够确定一个东西的所有状态的时候,我们列举出所有状态,通过不同的条件,进行不同的动作,达成最后的状态。这其中三点关键就是条件,动作,状态。
其实实际上面对这些转态转换的也就是我们常使用的 if- else ,但是使用 if- else 在一些更复杂的场景下,可读性,扩展性都不够,并且容易出错。而使用 fsm 能够对我们状态和事件统一管理。我们也可以通过画图来把转态转移画出来,这样就能更加清晰的编码状态机了。特别是在游戏中,状态的变化也是常态。  
有限状态机
首先说概念吧,有限状态机也就是 Finite-state machine, 英文简称FSM,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
也就是当我们能够确定一个东西的所有状态的时候,我们列举出所有状态,通过不同的条件,进行不同的动作,达成最后的状态。这其中三点关键就是条件,动作,状态。
其实实际上面对这些转态转换的也就是我们常使用的 if- else ,但是使用 if- else 在一些更复杂的场景下,可读性,扩展性都不够,并且容易出错。而使用 fsm 能够对我们状态和事件统一管理。我们也可以通过画图来把转态转移画出来,这样就能更加清晰的编码状态机了。特别是在游戏中,状态的变化也是常态。
      展开
    
  评论
 
          2
        
  #每天一个知识点#  
2023/06/27
分享个思路吧,今天做的业务中,发现需要处理很多种类的奖励领取,这里不同的奖励领取,流程和事件都是不确定的,并且他们没有各自的回调。这就导致没发知道这个领取是否完成结束了,来通知我走后面的步骤。当时起初的想法是有使用一个队列来维护,并且轮帧的去询问。但其实感觉这么写挺麻烦的。想有没有更加简单的,后面想到的是,在引擎垃圾回收和资源引用的地方常常是使用计数器来判断是否释放。这种计数器的思想就挺适合当前的情况的,当开始领取的地方打上加一,结束的地方减一,那么无论多少个什么种类的领取,我们只需要判断当前计数器是否为 0 ,是的话就执行下面的步骤,不是就继续等待。  
2023/06/27
分享个思路吧,今天做的业务中,发现需要处理很多种类的奖励领取,这里不同的奖励领取,流程和事件都是不确定的,并且他们没有各自的回调。这就导致没发知道这个领取是否完成结束了,来通知我走后面的步骤。当时起初的想法是有使用一个队列来维护,并且轮帧的去询问。但其实感觉这么写挺麻烦的。想有没有更加简单的,后面想到的是,在引擎垃圾回收和资源引用的地方常常是使用计数器来判断是否释放。这种计数器的思想就挺适合当前的情况的,当开始领取的地方打上加一,结束的地方减一,那么无论多少个什么种类的领取,我们只需要判断当前计数器是否为 0 ,是的话就执行下面的步骤,不是就继续等待。
      展开
    
  评论
 
          1
        
  #每天一个知识点#  
2023/06/25
游戏中场景的概念(scene)
在前一个项目中是只有一个场景的,但是在后面的第二个项目,是把游戏分为两大类主场景的。首先多分场景能更清楚管理项目,我们确保同一时刻只有运行一个场景,而切换场景的时候就把上一个场景的东西都回收。如果没有使用场景,之前的开发有一个问题,那就是我们有一个金币栏的组件,没有区分场景的时候,即使进入关卡,实际上大厅的东西都是存在的,只不过看不到(被遮罩了),这时候就可能触发一些错误监听。
当然也有支持单场景的开发,单场景的话,其实就能不用考虑太多数据传递的问题。不过目前我们项目中,是把核心控件都提取出来设置为常驻,就算切换场景也不会被销毁。
对于是单场景还是多场景,其实还是得看实际的业务开发,没有绝对的正确,多场景的话便于管理,清晰,但是得考虑场景切换逻辑比较复杂,单场景所有资源都能管理处理,缺点是没法很好的管理  
2023/06/25
游戏中场景的概念(scene)
在前一个项目中是只有一个场景的,但是在后面的第二个项目,是把游戏分为两大类主场景的。首先多分场景能更清楚管理项目,我们确保同一时刻只有运行一个场景,而切换场景的时候就把上一个场景的东西都回收。如果没有使用场景,之前的开发有一个问题,那就是我们有一个金币栏的组件,没有区分场景的时候,即使进入关卡,实际上大厅的东西都是存在的,只不过看不到(被遮罩了),这时候就可能触发一些错误监听。
当然也有支持单场景的开发,单场景的话,其实就能不用考虑太多数据传递的问题。不过目前我们项目中,是把核心控件都提取出来设置为常驻,就算切换场景也不会被销毁。
对于是单场景还是多场景,其实还是得看实际的业务开发,没有绝对的正确,多场景的话便于管理,清晰,但是得考虑场景切换逻辑比较复杂,单场景所有资源都能管理处理,缺点是没法很好的管理
      展开
    
  评论
 
          2
        
  #每天一个知识点#  
2022/06/23
说说在 2D游戏中实现一个一些效果吧。前端时间公司新项目需要尽可能的模拟现实中游戏的场景,也就是说我们需要实现一个3D 曲面的效果,可是我们现在的是一个 2D游戏,要基于原本的项目框架,如何实现呢?这边试验的方案首先是直接写 shader 处理渲染,简单来说就是曲面就是一个双曲线的效果嘛,所以我们计算出一个长方形投影映射为双曲线的转换公式,然后来做处理。这是方案一,其实开始也实现了这个曲面的效果,但是这个计算过程太麻烦了、后面同事又给出另有一种方式,那就是建模,这里是建了一个曲面的模型,然后我们拿到摄像机的渲染的纹理,把这个纹理设置到这个模型上,也能达到效果,这也算一种方案吧。不过其实这些都算野路子的实现,真正想实现3D的效果,其实还是应该用 3D去做,但是这样成本太高了,不过其实吧研究使用这些野路子的过程和后续的一些问题,也花了不少时间~  
2022/06/23
说说在 2D游戏中实现一个一些效果吧。前端时间公司新项目需要尽可能的模拟现实中游戏的场景,也就是说我们需要实现一个3D 曲面的效果,可是我们现在的是一个 2D游戏,要基于原本的项目框架,如何实现呢?这边试验的方案首先是直接写 shader 处理渲染,简单来说就是曲面就是一个双曲线的效果嘛,所以我们计算出一个长方形投影映射为双曲线的转换公式,然后来做处理。这是方案一,其实开始也实现了这个曲面的效果,但是这个计算过程太麻烦了、后面同事又给出另有一种方式,那就是建模,这里是建了一个曲面的模型,然后我们拿到摄像机的渲染的纹理,把这个纹理设置到这个模型上,也能达到效果,这也算一种方案吧。不过其实这些都算野路子的实现,真正想实现3D的效果,其实还是应该用 3D去做,但是这样成本太高了,不过其实吧研究使用这些野路子的过程和后续的一些问题,也花了不少时间~
      展开
    
  评论
 
          1
        
  #每天一个知识点#  
2023/06/21
cocos ceater对象池
在 cocos ceater 中实现对象池主要是两个基本方法,那就是获取节点,以及存储节点
获取节点的时候,我们传入需要实例的预制体,和该该节点钩挂的父节点。那么我们实现中,我们可以通过节点的名来作为 key,然后先查看是有以及有该节点池,有的话直接拿,要是没有的话我们得克隆出来,而要是没有该节点的对象池的,就需要创建该节点的对象池。
而存储的方法中,我们就是需要把该节点传入,然后判断是否有该节点池,有的话存入,没得话就得创建该节点的对象池来存入
然后我们在每一个克隆节点的地方就能换为对象池中的 getNode方法,然后销毁的地方使用 pushNode 方法,下面是最简单基本的一个实现,具体开发中,我们还需要更多的条件和对应的函数等  
2023/06/21
cocos ceater对象池
在 cocos ceater 中实现对象池主要是两个基本方法,那就是获取节点,以及存储节点
获取节点的时候,我们传入需要实例的预制体,和该该节点钩挂的父节点。那么我们实现中,我们可以通过节点的名来作为 key,然后先查看是有以及有该节点池,有的话直接拿,要是没有的话我们得克隆出来,而要是没有该节点的对象池的,就需要创建该节点的对象池。
而存储的方法中,我们就是需要把该节点传入,然后判断是否有该节点池,有的话存入,没得话就得创建该节点的对象池来存入
然后我们在每一个克隆节点的地方就能换为对象池中的 getNode方法,然后销毁的地方使用 pushNode 方法,下面是最简单基本的一个实现,具体开发中,我们还需要更多的条件和对应的函数等
      展开
    
  评论
 
          1