[开发笔记] LayaAir-踩坑
人的记忆是有极限的,所以写博客记录一下。。。
最近开发的模拟经营类微信小游戏项目,同屏显示的精灵数太多,使用cocos creator开发性能有点差,所以不得不用Laya。
特地测试了一下:
cocos creator同屏(其实也不算全部同屏,算是大部分,因为引擎2.0版本以上已经去除了culling)数量在400+左右,其中400个精灵不停的切换父节点(因为3d游戏做成2d的需要改层级遮挡关系)在微信上运行IphoneX的FPS已经掉到30帧左右了,黑鲨1是60帧,IphoneX的FPS比黑鲨还低可能是ios处理js本来就比较慢的原因。
逻辑代码全部不变,全部转成了Laya之后,同屏700个精灵在微信上运行IphoneX的FPS是60帧,黑鲨也是60帧,再多点就没测试了,因为已经满足需求了。
所以就觉定用Laya了,使用的版本是2.1.1.1,在这之前已经使用过Laya开发了一款3D的小游戏,由于2D的UI界面比较少,所以踩的坑不多。这次的游戏是2D的,结果踩了一连串的坑。。。。。
首先吐槽一下可视化的UI编辑器,选中精灵按键盘的方向键是微调位置,但是我选中了层级窗口的节点,想按方向键上下切换节点,左右展开节点,但是每按一次方向键节点的位置就微调了1,这应该算是BUG吧,不知道为什么这么久还不修。。。
接下来是坑了:
1.很多情况下节点不填宽高默认auto是会出BUG的,比如坐标转换会出错,使用Dialog(这个组件比较特别,就算设置了宽高也会出现BUG,不知道是什么操作)如果创建了之后直接弹出(new Dialog().popup()),由于不能及时获取到宽高,弹窗位置不会居中,第二次弹出正常。要解决的话需要在构造函数设置一下宽高,有些弹窗还必须要再onAwake再设置一下宽高才能解决。
2.由于是从creator转过来的,所以锚点用习惯了anchor,然后坐标转换一直不对,悲剧了,折腾了一段时间之后断点进去看了函数实现发现Laya是用pivot的。。。。最后自己复制代码出来改装了一下:
/**局部坐标转换成全局坐标 应用锚点* @param {pos} 需要转换的局部坐标* @param {node} 局部坐标所在的容器* @param {toGlobalNode} 需要转换到的上级容器 (默认舞台)*/export function localToGlobalAR(pos:Point,node:Laya.Sprite,toGlobalNode?:Laya.Sprite){//坐标转换let point = new Point(pos.x,pos.y);toGlobalNode=toGlobalNode || Laya.stage;while (node && !node.destroyed){if (node==toGlobalNode)break ;//锚点偏移计算(优先anchor 其次pivot)if(node["anchorX"])node.pivotX = node["anchorX"] * node.width;if(node["anchorY"])node.pivotY = node["anchorY"] * node.height;point=node.toParentPoint(point);node=node.parent as Laya.Sprite;}return point;}/**全局坐标转换成局部坐标 应用锚点* @param {pos} 需要转换的全局坐标* @param {node} 需要转换到局部坐标所在的容器* @param {toGlobalNode} 全局坐标所在的上级容器 (默认舞台)*/export function globalToLocalAR(pos:Point,node:Laya.Sprite,toGlobalNode?:Laya.Sprite){let point=new Point(pos.x,pos.y);var list=[];toGlobalNode=toGlobalNode || Laya.stage;while (node && !node.destroyed){if (node==toGlobalNode)break ;list.push(node);node = node.parent as Laya.Sprite;};var i=list.length-1;while (i >=0){node=list[i];//锚点偏移计算(优先anchor 其次pivot)if(node["anchorX"])node.pivotX = node["anchorX"] * node.width;if(node["anchorY"])node.pivotY = node["anchorY"] * node.height;point=node.fromParentPoint(point);i--;}return point;}
3.接上面,容器的scale为0时 转换出来的坐标会是NaN
4.导入bmfont后必须要重启项目才能在UI编辑器中预览,而且在使用这个UI界面之前必须要先加载bmfont。
5.bmfont是不能直接设置fontSize的,需要在加载完成后加上bmFont.autoScaleSize = true。示例如下
let mBitmapFont = new Laya.BitmapFont();
这里不需要扩展名,外部保证fnt与png文件同名
mBitmapFont.loadFont(url, Laya.Handler.create(this, function (font: Laya.BitmapFont) {if (font) {var name = url.match(/\/(.*?).fnt/)[1];font.autoScaleSize = true;Laya.Text.registerBitmapFont(name, font);}cp.runWith(font);
}, [mBitmapFont]));
6.bmfont在UI编辑器中设置fontSize是无效的,我才发现原来Laya在UI编辑器使用bmfont的正确姿势是直接设置scale。。。
7.bmfont在微信小游戏上运行会报错,必须要把domparserinone.js库勾上。
8.把节点放到Panel下实现滚动效果,节点的parent并不是Panel,而是被嵌套了一层Box,获取Panel需要.parent.parent。
9.使用了scrollRect时候子节点位置会根据scrollRect的x,y来,坐标转换又来坑了。。
10.3D的Animator重新播放要填参数play(name,layer,0),normalizedTime填0;
11.一个Tween实例调用了clear之后,再调用一次clear会清掉别的Tween(这是巨坑,莫名其妙的)。
12.使用了布局需要注意HBox会根据x坐标排序,VBox会根据y坐标排序。(cocos是根据节点顺序zIndex排序)。
13.最后是粒子,粒子实现原理是创建了一个网格 所有粒子都是渲染到这个网格上的,粒子运动的运算是在shader上,默认发送出来的粒子是不会根据节点移动(拖尾效果),而且不能清空已经被激活的粒子(源码可能是我没看仔细,找不到)只能等待生命周期结束(使用对象池要注意的问题,避免从对象池取出来后还残留着上次的生命周期没结束的粒子,销毁需要延迟等待什么周期自行结束后才放到对象池延迟时间是particle.emitter["setting"].duration * 1000),想要清空就直接destroy掉。
想要移除拖尾效果(应该说是移除全局拖尾效果,只留局部拖尾,也就是所有粒子都相对于父节点的坐标系)就重写一下Particle2D的customRender和_particleTemplate对象的addParticleArray加上节点移动时跟原位置的偏移。代码如下:
//粒子静态跟随对象(不拖尾)
class CustomParticleStaticFollow extends Laya.Script {private staticFollowElement: Laya.Sprite;private srcX: number;private srcY: number;private oldX: number;private oldY: number;onUpdate() {let ele = this.getPointElement();if (ele.x !== this.oldX ||ele.y !== this.oldY) {let par = this.owner as CustomParticle2D;par.setOffset(ele.x - this.srcX, ele.y - this.srcY);this.oldX = ele.x;this.oldY = ele.y;}}setStaticFollowElement(ele: Laya.Sprite) {this.staticFollowElement = ele;ele = this.getPointElement();this.oldX = this.srcX = ele.x;this.oldY = this.srcY = ele.y;}getPointElement(): any {let rect = this.staticFollowElement.scrollRect;if (rect) return rect;else return this.staticFollowElement;}
}export class CustomParticle2D extends Laya.Particle2D {private offset: Laya.Point;/**静态跟随的对象 */private staticFollowElement: Laya.Sprite;constructor(setting: Laya.ParticleSetting) {super(setting);this.offset = new Laya.Point(0, 0);}/**自定义渲染 */customRender(context, x, y) {// this.transformthis["_matrix4"][0] = context._curMat.a;this["_matrix4"][1] = context._curMat.b;this["_matrix4"][4] = context._curMat.c;this["_matrix4"][5] = context._curMat.d;this["_matrix4"][12] = context._curMat.tx - this.offset.x;this["_matrix4"][13] = context._curMat.ty - this.offset.y;var sv = (this["_particleTemplate"]).sv;sv.u_mmat = this["_matrix4"];}/**绑定静态跟随的对象(绑定坐标会改变的节点,跟着偏移,不拖尾)*/bindStaticFollowElement(ele: Laya.Sprite) {//绑定静态跟随的对象let follow = (this.getComponent(CustomParticleStaticFollow) || this.addComponent(CustomParticleStaticFollow)) as CustomParticleStaticFollow;follow.setStaticFollowElement(ele);this.setOffset(0, 0);return this;}clearStaticFollowElement() {let com = this.getComponent(CustomParticleStaticFollow) as CustomParticleStaticFollow;com && com.destroy();this.setOffset(0, 0);}/**设置偏移 */setOffset(x: number, y: number) {this.offset.x = x;this.offset.y = y;}setParticleSetting(setting: Laya.ParticleSetting) {super.setParticleSetting(setting);//重定向粒子 生成坐标(加上偏移)let pt = this["_particleTemplate"];pt.taddParticleArray = pt.addParticleArray;pt.addParticleArray = function (position, velocity) {if (this.posot) {position[0] += this.posot.x;position[1] += this.posot.y;}this.taddParticleArray(position, velocity);}pt.posot = this.offset;}
}
使用方法是:
let setting = new Laya.ParticleSetting();setting.textureName = "texture.png";//必须要设置一张图片 不然会报错let par = new CustomParticle2D(setting);
par.load(url);
par.bindStaticFollowElement(map.owner.parent);
[开发笔记] LayaAir-踩坑相关推荐
- HBase眼高手低从Shell到IDEA编程、心路笔记、踩坑过程
HBase眼高手低从Shell到IDEA编程.心路笔记.踩坑过程 HBase眼高手低 通过shell操作Hbase Foundation 在terminal中输入hbase,就可以查看hbase命令的 ...
- 我的物联网开发入门和踩坑历程
我的M5Stack物联网开发入门和踩坑历程:基于M5STACK和ONENET 开发准备 M5STACK简介 环境配置 UIflow环境 ESP-IDF环境 方法一 方法二(更推荐) 感知模块 网络连接 ...
- Slam学习笔记——ROS踩坑记录
Slam学习笔记--ROS踩坑记录 1. 安装 2. ROS文件系统 2.1 工作区 2.2 包package 2.2.1 包的操作 2.2.2 描述文件package.xml 2.3 节点node ...
- Android SDK 开发——发布使用踩坑之路
前言 在 Android 开发过程中,有些功能是通用的,或者是多个业务方都需要使用的. 为了统一功能逻辑及避免重复开发,因此将该功能开发成一个 SDK 是相当有必要的. 背景 刚好最近自己遇到了类似需 ...
- uniapp开发聊天APP踩坑记录
最近工作重心转移到了uniapp上,有一说一,这个框架跨端确实牛逼,一套代码能一次编译到多端使用.但随之而来的兼容性问题也是层出不穷,同样的在面临APP底层的改动也显得力不从心.同时,uniapp的性 ...
- 高德地图开发-常用api踩坑使用
一.高德地图的加载初始化 在这就踩过很多坑,新建项目正常显示没问题,放到我们的项目就是不显示,加载不出来, 这个时候不要慌,只要确保下面三部完成就莫问题了 1.引入高德地图开发者api <scr ...
- Could not resolve all files for configuration “: app: debug Compileclasspath“ mac开发 cordova build踩坑
作为小白第一次开发android,想到会踩坑,没想到这么多.话不多说直接上主题,在做基于ionic + cordova安卓开发时遇到了一个打包的问题,如下图. Could not resolve al ...
- react开发公众号踩坑日志
最近在用react开发一个公众号产品.以前没有过开发公众号的经验,在这里记录一下过程中踩过的坑. 这个项目是前后端开发的.本篇文章只站在前端的视角,希望给大家一个参考 一.授权回调 微信授权过程 进入 ...
- 开源大数据开发平台DataSphereStudioLinkis踩坑记录
Linkis:https://github.com/WeBankFinTech/Linkis DataSphereStudio:https://github.com/WeBankFinTech/Dat ...
- uni-app开发,防止踩坑
一.组件设置全屏覆盖 设置宽度和高度100%是没用的 需要在里面加设置一层view,并且设置对应宽高分别为vw和vh <uni-popup><view class="wra ...
最新文章
- Spring Data JPA 五分钟快速入门和实践
- WinForm 读写配置文件
- CSS 布局与“仓库管理”的关系
- 亚信联创java面试题_亚信联创面试题及答案
- python 整数输出 d f_如何将数字(10,11,12,13,14,15)分配给Python 3中的字母(A,B,C,D,E,F)?...
- bme280 环境传感器开发板_半导体所在柔性湿度传感器与非接触控制方面取得进展...
- 为Android安装BusyBox
- 【CV实战】Ubuntu18.04源码编译安装opencv-3.4.X+测试demo
- 【Spark】Spark 2.4 Stream 读取kafka 写入kafka
- autobench 快速入门
- fckeditor代码总结
- wh计算公式_电池的wh和mah怎么换算?
- 惠普打印机双击之后没有扫描_惠普打印机 找不到 扫描图标 怎么办,急需扫描一些证件 ,求救...
- Python 使用乐动体育的 backoff 更优雅的实现轮询
- 武魂java_jdk及tomcat的安装
- Angular NgModule
- ubuntu下.chm文档查看工具
- 《数据库系统原理》教学上机实验报告
- 基于Master-DistributedMaster-Slave架构的replication
- 《LCD总结篇(中级)》