Web前端可以转行做游戏吗?
作者:ManfredHu
链接:http://www.manfredhu.com/2018/03/15/31-laya-game-tips/index.html
声明:版权所有,转载请保留本段信息,谢谢大家
Web前端最近都在跨界!!现在又伸手到游戏领域了。但是真的那么好跨界吗?请让我一一道来。
Canvas和WebGL的出现其实让Web游戏有了实现的可能,但是让我们用ctx一个个画,效率还是低了点,所以需要游戏引擎。它帮助我们去动态渲染游戏每一帧的元素。
业界比较著名的几个H5游戏引擎,有Egret(白鹭),Layabox,Three.js,coco2d-js等等,详情可以看知乎的回答。
因为我们团队不是一开始做游戏的,我们是传统意义上的前端团队,从web发家的,起初做的是电商类的业务——拍拍。所以这里我们综合几家游戏引擎,选择了Layabox。
有如下有点吧:
- LayaAir是一个优秀的适用于多端的游戏引擎,配备有丰富的组件,有自己的IDE可以快速构建布局等,不需要写类似CSS的代码
- 支持html的页面渲染,就是说你可以让游戏引擎跟web页面,混用(这在一些类似文本的页面非常有用)
- 支持2D、3D甚至VR方面的开发。性能也足够优秀
- 对Web前端普遍的上手难度也较其他引擎框架简单很多
- 不需要写重构(CSS)代码
其实我们团队之前也是做得H5竞猜小游戏,不过是基于DOM的,用CSS3做动画。但是发现CSS3操作复杂动画,有很多缺点:
- 复杂动画支持度非常差
- 页面元素太多,渲染性能差
- 很多复杂的需求做起来很耗时
- 玩家手机容易发烫(页面元素多,动画复杂)
因此,我们经过预研和讨论,果断走出传统Web的开发模式,拥抱传统的游戏开发!!当然这里肯定不是一帆风顺的,从Web前端转向游戏开发,还是有非常多的坑点的。
首先需要摆脱HTML和CSS,你不是在做页面,你是在做一个游戏!!游戏的逻辑占据了一个游戏80%的工作量,所以你很多时候是在写JavaScript代码,这不是问题,其次,你需要拥有面向对象编程的思想。这可能是很多老前端欠缺的,因为JavaScirpt说到底是一门面向函数、面向过程的语言。大家知道模块化,但是却还是习惯写function
而不是ES6的class
。
这里因为平台也在转型向ES6靠近,所以大胆采用了ES6+Babel+Webpack
的模式,甚至于在做Weex、小程序、Web三端融合。即一份代码,可以在三个平台跑。扯的有点远哈,下面开始正文,我们不说用法,具体是说一些坑点,和优缺点对比。
游戏引擎不适用的地方
游戏引擎这东西在动画一块是真心好用,可以高度还原设计师的动画,可是其没有网页的排版布局,更多的布局应该是通过x、y、更改pivot、anchor属性来实现。
CSS可以很快速的通过代码进行相关布局(flex、float、position等属性),网页那种自上而下的内容排版可以自动适应内容,对文字处理十分便捷。
针对各自的优缺点,从实现的便捷性来说,游戏主场景(动画极多)的情况下,为了提高用户的体验,应该用游戏引擎来写。
而对一些活动浮层、投注记录、游戏规则等有大量图片文本的页面,应该用传统的Web网页来编写,这样才是物尽其用的做法。
在这个背景下,游戏开发的前端需要掌握多好几种技能——简单的游戏开发的技能、重构部分的构建技能(团队大前端的趋势下,去除重构岗位,重构工作由前端接管),可以说工作量翻了一倍。但是在业务侧来考虑,因为减少了相关的中间环节,需求迭代可以更快速的落地。
Laya的IDE使用要注意的地方
LayaIDE提供一个组件库,如list列表,tab按钮切换等等简单的Web组件,可以直接拖拽使用而不用自己用代码再实现一次。
但是IDE自带的很多组件有坑点,如list组件的selectHandler触发并不灵敏,数据源重新绑定后会出现点击无法响应的问题,这个时候要绑定mouseHanlder来代替点击事件等。
IDE的使用对于不熟悉的人来说上手并不简单,熟练后可以提高效率。具体可以看官网的介绍。
sceneColor并不起作用
这个属性是IDE的一个配置属性,在引用的时候并不会起作用。可以理解为是一个IDE的背景色,可以让你在用IDE编辑的时候看的更清楚。
如果你需要更换背景色,应该通过绘制一个底部的矩形来实现。
1
|
this.graphics.drawRect(0, 0, this.stage.width, this.stage.height, '#404d6f'); //设置背景颜色
|
var和name
var
一般组件view下不管嵌套的层级多深,只要有一个var属性的命名,都可以用this.xxx
来获取到这个var属性得带组件的引用,并对其进行逻辑操作。
name
而name在特定的组件内name有自己的命名规则,如list下的box,命名为render,可以自动识别该box为list内部渲染节点,设置list的repeat等值,直接简便的实现某些功能。
再譬如dialog界面,我们设置btn的name为close、yes、no等值,可以直接实现关闭dialog窗口的功能等等。name在这个组件下面也是唯一的,可以用来区分不同的组件。
top、right对x,y的影响
如果组件设置了top、right等值,在对其进行x,y变化是无效的。
解决方法:IDE通过这些属性设置好布局要取消掉,会转化为对应的x、y值,此时可以操作
图集图片过大导致图片加载失败
之前按照引擎官方人员的建议设置最大合集图片为2048乘以2048,后面经过我们的测试发现1024宽高比较适配大部分机型,即图片最大不能超过1024,否则微信手Q会有图片load时间过长导致失败的问题。
这里可能是部分合并的大图片下载失败,也可能是全部下载失败。然后引擎会单独去下载每个碎片文件,而服务器是没有这些文件的,导致下载全部返回404。应该尽量避免这种情况发生。
显示区域与点击区域并不完全相等
用一句话来说就是:你看到的并不一定是真实的。如我要完成收起按钮,然后隐藏整个浮层。
但是你明明可以看到,绑定的点击事件却没有触发。
这是因为这个层级的高度或者宽度太小,被遮挡这部分是不会触发的。但是是可见的
分离代码和工程
起初是因为不想在LayaIDE下写代码,所以分成了两部分,后面发现这种形式还是非常OK的,因为Laya工作人员不是传统前端开发,他们的IDE是类似Atom的Electron做的,所以其实运行起来编码体验并不是太好。其次是因为IDE会生成图片(png)和图集(atlas)文件,这些图片类的静态资源,更新频率还是非常高的。如果你只需要修改代码,或者只要修改图片图集,发布一次就好了,不需要同时发布两种。
这样的分离,代码你可以按照你喜欢的方式来写,比如webpack配置工程,比如文件摆放,该怎么放怎么放。再把Laya生成的东西拷贝进来就好了。
设计稿和工程大小
这里我们设计稿和IDE的宽度高度是完全对应的,所以不存在换算的问题。也不需要类似CSS的做REM兼容等等操作。你设定宽度是750,高度会自动拉伸,但是显示的页面层级,需要在初始化的时候拉伸一下,不然还是IDE里面设定的宽高,当然如果你害怕上面提到的点不到,也可以设定一个非常大的值。
Object.assign兼容
Object.assign是ECMAScript标准的合并对象属性的方法,类似有jQuery的extend等等。
如果你抛弃了jQuery和Zepto等懒得写extend方法,又拥抱了ES6,那你可以像我这样找polyfill来兼容,这里babel官方有个模块
也可以自己选择做兼容,在入口开始的时候载入兼容文件就好。
抗锯齿问题
这个问题是在WebGL下(Canvas不会),会出现graphics.drawCircle
绘制的圆环有锯齿问题。如下图:
左边为没有设置抗锯齿,右边设置了抗锯齿。
1
2
|
Laya.Config.isAntialias=true; //开启抗锯齿,会消耗一些性能
Laya.init(Browser.clientWidth, Browser.clientHeight, WebGL);
|
mask遮罩不支持抗锯齿
如图,下边是没有优化前的,锯齿严重。上边那个图是优化后的,明显边框清晰了很多。
这里之前的思路是矩形头像和mask遮罩为一个整体在前面,然后内边框和外边框层级在后面,但是这样的话,mask遮罩部分现在laya还不会抗锯齿,所以这里对公共头像组件进行参数扩展,加了zOrder参数。让边框盖在头像上,就可以达到抗锯齿的作用。
最后实现的思路如下图层级所示。
Laya几种优化的写法
用Laya自带的属性获取像素比
1
2
3
|
//var browserHeight = document.body.scrollHeight * window.devicePixelRatio;
var browserHeight = Laya.Browser.height;//会考虑设备像素比,而且会针对特定机型调整补全
`
|
这个不用自己算了,Laya.Broswer
现在可以获取得到了。简化了运算过程
用.super()方法继承父类
Laya.class定义的时候会在原型定义.super方法,直接用就好。两种用法等价,但是看起来.super更简单把?
可能有一些例子是通过xxx._super.call(this)
继承父类的,其实直接xxx.super(this)
就好了。_super
还是看成私有属性好了。