cocos2d-x从c++到js20:脚本语言风格的JS代码
Posted 老G
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cocos2d-x从c++到js20:脚本语言风格的JS代码相关的知识,希望对你有一定的参考价值。
最近听说Cocos2d JS官方在组织写新的代码例子。并且林顺同学在开会时说,Cocos2d JS接口将回归JS风格,成员变量访问方式用“.”,以及初始化时用对象字面量{}。非常不错啊。
如果之前是Cocos2d-x的C++程序员,在使用Cocos2d JS时很容易沿用C++的思路来写脚本。这种方式不容易发挥出脚本语言的快速开发优势。
在Cocos2d-x 的例子代码中有一些写法,尤其是在Test中,有许多代码是按照C++例子原样翻译过来的。里面应用了很多继承与组合等代码组织方式。并且,很多静态强类型语言的写法(类型强迫症),在脚本语言中对于开发速度是有很大影响的。
一、继承VS动态添加成员
继承,是一种最重量级的代码复用方式(他有自己的优势但是也有非常多的副作用)。但是问题在于,很多编辑器和运行库是既不支持协变又不支持各种动态绑定。这种情况下会让你的继承代码毫无作用。你只能选择组合,而组合差不多是一种最罗嗦的代码复用方式。他会很大程度抵消你的脚本语言开发速度优势。从这种情况看来CocosBuilder的设计无疑比CocoStudio要先进许多。
那么怎么做呢?因为脚本语言的优势可以在运行时动态给一个实例添加成员。 (Dynamic addition of methods and attributes to instances.)使用这种特性就可以跳过繁琐的继承+组合复用方式来构建代码。并且Cocos2d-x作为游戏引擎,因为存在UI等显示系统,也就是说存在一个全局节点树,可以用来递归遍历所有显示对象,使用类型判定然后直接调用相应的扩展函数直接在对象实例上进行扩展。
上面说的是指基于Cocos2d JS的二次开发代码的使用方法。在编写功能代码时也可以应用这种特性。
这么做的坏处是会破坏JS内部的类型系统(构造器与对象行为不匹配)。如果库的编写者和使用者没有充分沟通,可能会遇到无法理解的代码。让对象行为变得不可控,因为JS本身就是动态弱类型的。所以一定要严格限制功能代码中被扩展的对象的作用范围和使用范围,必要时使用文档规范,避免其他人接手莫名其妙的代码。
而对于自带运行库的编辑器来说,还有第二种选择——直接扩展插件。这是完全按照强类型的路子走了。
二、装载时执行OR装载时注册启动时初始化
代码在加载时可以执行,这是脚本语言的又一个特色。因此我们可以在代码文件被装载时自动做很多初始化工作。
但是这么搞也是存在一定问题的,如果初始化代码散落在不同的文件中,对debug是不利的。需要在多个调用点去来回查找。
不过凡事都有例外,如果你把很多代码当成资源加载,就不存在这种问题。比如,加载一些AI脚本、动画脚本、UI脚本的时候,就不存在这种问题。因为这些代码的接口规范都很统一,而且一定会有一个外部装载机制和管理机制。先通过读取文件将启动函数绑定好,再统一启动。
三、具名索引And有限状态机FSM
访问一个对象的成员,可以用[]内嵌名字(具名索引access attribute by name),也可以用.后面加名字。我建议动态获得的成员名进行访问时使用前一种方式,普通的成员访问时候使用后一种,以示区别。
尤其是通过[]内嵌名字方式,可以直接调用函数这种方式,可以非常好的同游戏中的各种状态机制和脚本指令结合。比状态模式(基于对象和接口)与状态变量(基于switch-case)要简便许多。
四、文件访问域And模块化
javascript的函数级作用域其实是很讨厌的。有几条原因:
1.一不小心很容易就污染了全局变量和全局函数
2.因为1的原因如果你选择对象构造方式来避免污染全局作用域又会遇到另外一个问题就是this。这个this不但罗嗦,每句都得写。还常常乱变,例如:bind callback的时候,在回调函数启动的时候,你常常无法确定当前this到底是哪个对象。(当然,在JS中也有一种叫bind this的技术,但有句话是:与其每次都解决问题,不如根本没问题)
Coffee是用闭包方式构造一个“文件访问域”的,还有很多库也有这种功能。这可以让你:
1.省掉写this
2.不会污染全局
当然如果你能支持module require还可以做更多的功能模块化开发(这对于前后端统一JS开发也很有好处)。官方介于闭包的性能和兼容性问题(都要考虑浏览器),应该不会添加CommonJS支持。
五、匿名回调函数
在bind callback时,直接通过匿名函数方式打入回调函数,是一种不错的方式,能够少写很多代码。
但是很多时候,如果遇到复杂流程控制,多种状态切换时,这种原地展开的callback,就会让代码可读性和错误查找变得困难起来,并且由于这种写法的上下文非常隐晦,还会引入this问题。
对于简单的UI显示控制,纯显示效果调用,匿名函数这种方式还是可以的。但是如果遇到复杂流程,并且牵扯到上下文,逻辑控制,函数复用,还是老老实实写实现,然后再bind callback时bind 函数比较好一点。
最后
都说JS的代码编写很多时候是基于函数的。卡哥的名言——“很多时候需要的仅仅是一个函数”。
写功能代码的时候。相对于OO,很多时候,你需要的是一个有用的对象,而不是类。对于类使用,在倾向于封装代码和类型约定(这个便于review和debug),但是如果说为了复用,明显有点太扯了(离需求太近,专门定制化的类,复用一定成问题)。当然关心代码质量和复用是好事,但是搞成项目改得精疲力尽就得不偿失了。
以上是关于cocos2d-x从c++到js20:脚本语言风格的JS代码的主要内容,如果未能解决你的问题,请参考以下文章
cocos2d-x从c++到js22:使用非侵入方式扩展UI系统接口的举例
cocos2d-x从c++到js16:使用cocos2d-console工具转换脚本为字节码
cocos2d-x从c++到jsJS与C++的交互2——JS与C++的“函数重载”问题
cocos2d-x从c++到js21:使用CocosCode调试JSB