[开发笔记] 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.transform
        this["_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);

 

 

 

你可能感兴趣的:(开发笔记,踩坑笔记,Laya,cocos,creator,踩坑)