quick-cocos2d-x(后文简称 quick)与 cocos2d-x 的关系,用一句话概括:quick 是 cocos2d-x 针对 Lua 的豪华套装威力加强版。
那 quick 与 cocos2d-x 相比到底有什么区别,又有什么加强呢?这篇文章就是答案:
cocos2d-x 是一个用 C++ 开发的游戏引擎,其架构设计和 API 基本上是照搬的 cocos2d-iphone(一个用 Objective-C 的 iOS 游戏开发引擎)。
由于 C++ 对开发人员要求较高,所以网龙科技利用 tolua++ 这个工具,将 cocos2d-x 的 C++ 接口转为了 Lua 接口(这种将 C++ 接口导出为 Lua 接口的库通常称为 luabinding)。让开发者可以使用 Lua 这种简单易懂的脚本语言来编写游戏,从而大大提高开发效率。
大概在 2012 年上半年,我们公司开始使用 cocos2d-x + Lua 来开发游戏。但是发现当时 cocos2d-x 对 Lua 的支持还存在相当多不完善的地方。所以我重写了整个 luabinding 的支持代码,解决了内存泄露、只能使用全局函数做回调等问题。
在 cocos2d-x 2.0 发布后,luabinding 又进行了不少改进和完善。截止到 cocos2d-x 2.1.4,整个 luabinding 已经可以说是相当稳定了。所以《我是 MT》、《大掌门》这些赚钱像印钱的游戏,就纷纷采用 cocos2d-x + Lua 的解决方案了。
可惜 cocos2d-x 团队从 2012 年以来一直在强力推广 cocos2d-x 的 JavaScript 解决方案,所以在 Lua 支持上基本上就没有什么大动作了。而从我们使用 Lua 解决方案的开发商看来,需要 luabinding 具备更强大的功能,因此这就是我们开发 quick 的最初原因。
quick 的目标:
虽然 cocos2d-x luabinding 已经很完善了,但是要开发一个游戏,我们还需要做许多基础工作。
看看下面的代码:
#!lua
-- 载入 Sprite Sheet
local frameCache = CCSpriteFrameCache:sharedSpriteFrameCache()
frameCache:addSpriteFramesWithFile("Sprites.plist", "Sprites.png")
-- 构造一个帧动画序列 Run0001.png -> Run0010.png
local frames = CCArray:create()
for index = 1, 10 do
local frameName = string.format("Run%04d.png", index)
local frame = frameCache:spriteFrameByName(frameName)
frames:addObject(frame)
end
-- 创建 CCSprite 对象
local firstFrame = tolua.cast(frames:objectAtIndex(0), "CCSpriteFrame")
local sprite = CCSprite:createWithSpriteFrame(firstFrame)
-- 在 CCSprite 之上播放动画(用 0.5 秒播放完 10 帧)
local animation = CCAnimation:createWithSpriteFrames(frames, 0.5 / 10)
sprite:runAction(CCRepeatForever:create(CCAnimate:create(animation)))
这段代码的功能在游戏中会反复出现,所以通常会封装成几个简单的函数。而 quick 里封装后的接口要完成同样功能会使用如下代码:
#!lua
display.addSpriteFramesWithFile("Sprites.plist", "Sprites.png")
local frames = display.newFrames("Run%04d.png", 1, 10)
local sprite = display.newSpriteWithFrame(frames[1])
local animation = display.newAnimation(frames, 0.5 / 10)
sprite:playAnimationForever(animation)
通过这个对比,可以看出二次封装是多么必要。而 quick 提供了一个 Lua Framework,封装了大量最常用的接口。
cocos2d-x 是一个功能完善的游戏引擎,但对于一个能挣钱的游戏来说,cocos2d-x 还缺少很多必须的功能。所以 quick 在 cocos2d-x 基础上添加了更多游戏必须的功能,例如完善的 HTTP 和 Socket 网络功能、数据加密解密、设备功能访问等等。
游戏的玩法做得差不多了,就需要开始集成付费充值、统计、社会化分享、好友链等各种第三方 SDK。
在 iOS 和 Android 平台上做这些工作,传统做法是分别编写 Objective-C 和 Java 的接口代码,然后再用 C++ 中转,借助 tolua++ 导出给 Lua 使用。这种做法不但繁琐,而且像 Java 和 C++ 的交互存在相当多的困难,所以开发效率极低。
quick 针对这个问题,特别开发了 LuaObjectiveCBridge 和 LuaJavaBridge 两个模块。利用这两个模块,我们在接入 SDK 时,就不再需要 C++ 中转层,也不需要 tolua++,由此省下的工作量相当惊人。
而且 quick 的附属项目会提供大量现成的 SDK 封装,进一步提高开发效率,让开发商把主要的资源花在游戏玩法上。
在开发过程中,需要不断测试。而 cocos2d-x 自带的 Windows 和 Mac 模拟器功能太简单。quick 特别开发了功能完备的模拟器,让整个游戏在开发阶段的大部分时间里都不需要借助真机就可以进行(小伙伴们都知道,Android 真机调试那么是多么的蛋疼)。
看看 quick 华丽的模拟器吧 :)
除了上述内容,quick 里还包含了物理引擎 Chipmunk 2D 的 Lua 封装(相信我,你不可能找到比这个更容易使用的物理引擎接口)、骨骼动画播放(支持 DragonBones、CocoStudio)、高性能的 LuaJIT 虚拟机等等。
总结而言,quick 和 cocos2d-x 的主要区别有如下几点:
除了这些重大区别外,quick 还在细节上做了一些调整和完善。并且后续还会将来自 cocos2d-x 最新开发分支(devel 3.0)的一些重要 bugfix 和有价值的新功能移植到 quick 中。
当然,当 cocos2d-x 3.0 完全稳定下来的时候,quick 也会做相应的升级。
quick 由几个主要部分组成:
除此之外,还包含一些 Lua 的扩展:
目前 cocos2d-x 支持两种脚本语言的 binding,从我个人了解,各自的情况列表如下:
Features | Lua | JavaScript |
---|---|---|
完全访问 cocos2d-x API | YES | YES |
iOS 平台 | YES | YES |
Android 平台 | YES | YES |
Windows 平台 | YES | YES |
Mac 平台 | YES | YES |
HTML5 平台 | NO | YES |
JIT 支持 | YES | YES |
编译为字节码 | YES | YES |
字节码是否可以反编译 | NO | NO |
运行性能 | HIGH | LOW |
接入 SDK 工作量 | 简单 | 复杂,通过 C++ 中转 |
导出自定义 C++ 类 | 简单 | 一般 |
而我最看重其中几点:
是否容易扩展:Lua 从设计时就是作为嵌入式语言来设计的,所以需要将某个 C/C++ 接口导出给 Lua 使用,那是相当轻松的事情。
源代码保护:LuaJIT 编译的字节码目前是无法反编译的,因为 LuaJIT 在编译时不是 1:1 直接转换源代码,而是对源代码做了相当多的深入优化。LuaJIT 编译出的字节码体积是 Lua 编译字节码的三分之一,由此可见优化程度。
客观的说,JavaScript binding 最大的优势是以前大量的 JS 前端开发人员可以很容易的上手,而且支持 HTML5 平台。但如果从手游体验来说,Lua 的运行效率是很重要的优势。
东西再好,学不会也是白搭,所以这篇文章的重点是这个部分,前面都是广告 :)
Lua 是一种简单易用的语言。学习这种语言最好的方式就是花几天时间写代码,然后在命令行中运行。
重点:
用 quick-x-player(quick 里牛叉的模拟器)运行 sample 目录里的各个例子,无差别爆改。改一点就按 F5(Mac 上按 CMD+R)刷新模拟器看看效果(做过 Web 前端的童鞋感动吧),要不了几天就成熟练工了。
最常遇到的问题:
因为 quick 里对 C++ 接口进行了二次封装,所以一些框架的方法返回的对象不一定很明确。但大多数可以从方法名上推测出来:
实在看不出来,那就去 framework 目录里翻源代码吧。
这个方法是干嘛的?
首先,从 framework 里找。找不到就去 cocos2d-x 里找。还找不到,那就是 cocos2d-x-extra 或者第三方库提供的方法。这里强烈推荐 Sublime Text 这个超神的编辑器,全文检索神马的完全不在话下。
为什么代码没有预期的效果?
不管是 Lua 还是 quick,当前的版本都非常非常稳定。所以遇到这种情况,不要首先怀疑语言特征或者引擎,而是多做测试,看看问题到底是怎么发生的。
在哪里寻求帮助?
目前 quick 还没有专门的社区,所以如果你想寻求帮助,最快捷的途径就是 QQ 群:284148017 。当然,不会有谁成天没事儿在那里义务解答,所以 QQ 群更多是交流经验的地方。未来,quick 会建立自己的社区,方便大家的交流。
本质上,quick 是 cocos2d-x 的一个增强版本,所以熟悉 cocos2d-x API 是基本要求。好在 cocos2d-x 目前已经有相当丰富的学习资料,即便是 C++ 代码的,改写为 Lua 也非常简单,也就语法的区别而已。
这个阶段可以用 quick 里的 CoinFlip 示例为基础,添加更多玩法或功能。CoinFlip 已经具备一个完整游戏的雏形,所以能够在 CoinFlip 中自在添加功能时,也就达到可以独立开发游戏的程度了。
quick 里包含了相当丰富的扩展库,从支付到网络服务都应有尽有。而这些功能也是游戏从项目变成产品时必须的,所以在熟练掌握扩展功能可以大大提高开发效率,避免重复劳动。
在学习扩展功能时,要了解这个扩展功能是基于什么开源项目来开发的,这样才能找到有针对性的学习资源。例如 LuaSocket、LuaFileSystem 等 Lua 扩展、Chipmunk 2D 物理引擎等等,它们的用法在各自项目的网站上都能找到。
有时候需要编写一些 C++ 对象,然后导出给 Lua 使用。这里可以参考 lib/cocos2dx_extra/extra/luabinding 里的 *.tolua 文件,将 C/C++ 头文件转为 tolua++ 需要的文件,然后借助 quick 中附带的脚本编译成 luabinding 接口。
在 quick 项目的 wiki 中,也有其他相关的文档可以参考。
quick 有一个附属仓库 quick-cocos2d-x-plugins,其中包含了一些 SDK 的接口文件。参考 sample/luajavabridge 示例和这些接口文件,很容易就能完成 SDK 的集成。
后续 quick 也会提供更多的 SDK 接口,以及相应的示例代码。
- END -