开发愤怒的小鸟的Lua语言:Wax框架详解

标签: 开发 愤怒 lua | 发表时间:2011-10-05 04:32 | 作者:戴铭 sun
分享到:
出处:http://www.starming.com/
摘要:我们都知道Objective-C和Cocoa语言可以开发iOS应用,但是一年前,苹果决定在 iOS系统上使用Lua语言。Wax框架的想法很简单:凡是Objective-C能做的,Lua也能做!考虑使用像Lua这样一门简单而高效的编程语 言,构建原生iPhone应用程序有许多充分的理由,而本文将深入探讨Wax具有的一些好处,同时演示把Lua与Xcode 4和iOS软件开发工具包(SDK)集成起来必不可少的实际步骤。

  2011年6月的编程语言排行榜Lua 语言一军突起,一举进入前十名。这与一年前苹果决定在iOS系统上使用Lua语言密不可分。但是,你了解如何用Lua语言在iOS上开发应用吗?这里将向 各位介绍Lua语言的iOS应用开发框架Wax,其中在iOS平台上无比火爆的《愤怒的小鸟》就是由Lua语言用Wax开发的。全文共分两部分,第一部分 将带您深入探讨Wax具有的一些好处,同时演示把Lua与Xcode 4和iOS软件开发工具包(SDK)集成起来必不可少的实际步骤。第二部分将逐步介绍如何用Wax构建一个简单的应用程序,显示Twitter上的当前趋 势话题列表,可以用按钮来更新内容。

Wax框架及愤怒的小鸟

  Wax是什么?

  Wax for iPhone这种框架在开发时,旨在把Lua脚本语言和原生Objective-C应用编程接口(API)结合起来。这意味着,你可以从Lua里面,使用任何和全部的Objective-C类及框架。

  从技术上来讲,Wax结合了Objective-C类和原生C代码。Lua语言嵌入了C语言,然后Objective-C类并入到其中。

  为什么使用Wax?

  Wax是免费的、开源的。与其他一些基于Lua的移动开发解决方案不同,Wax是个开源框架,只需要你花一点点时间就可以上手,不需要花钱。不喜欢Wax的工作方式,或者发现实施方面的缺陷?源代码可免费获取,你总是可以改动源代码,以满足自己的需要。

  可以利用原生API。这意味着,为教Objective-C而编写的教程很容易由Lua for Wax来改动和编写。这还意味着,你的应用程序在外观感觉上总是如同原生应用程序,不过又得到了用Lua这种高效脚本语言编写代码可以节省时间的好处。

  可以使用Xcode。这意味着,模拟器和设备部署都轻而易举,不会轻易与未来的iOS版本决裂。

  可以利用所有现有的Objective-C库。如果你有一个Objective-C类是以前编写的,不需要改动,就可以将它用在Lua中只要把它放入到Xcode。Three20之类的库也是一样。只要按照正常指令来添加库,就可以使用Lua代码访问它们。

  可以利用Wax Lua模块。Wax有几个内置的Lua模块,使得异步HTTP请求和JavaScript对象标注(JSON)创建/解析极其容易而快速(因为模块是用C编写的)。

  没必要管理内存。不再需要操心内存分配之类的事务。Wax为你处理这一切。

  Lua类型自动转换成对应的Objective-C类型,反之亦然。 这意味着,如果你调用了需要NSString和NSInteger的某个方法,但传送了Lua字符串和Lua整数,Wax会为你搞定转换工作。这种转换功能强大,甚至可以处理复杂的Objective-C特性,比如选择器。

  你可以利用所有上述特性。不需要精挑细选。你获得所有特性!

  OK,实在太棒了!我该如何安装Wax?

  首先你需要Xcode和iPhone SDK。要是你还没有这些东西,赶紧弄一份!

  用Xcode创建项目

  我们先创建一个新的基于Windows的项目,名为WaxApplication。别忘了把设备设置成iPhone:

WaxApplication

WaxApplication

  通过Finder浏览到你保存该项目的文件夹。创建三个新的文件夹:wax、scripts和Classes。你的文件夹看起来应该像这样:

通过Finder浏览到你保存该项目的文件夹

  设置Wax(第一部分,处理文件)

  首先,下载源代码的压缩包。Wax放在GitHub上(https://github.com/probablycorey/wax),那样下载源代码就很容易。从这里下载压缩包。

  现在,解压缩刚下载的文件。浏览到刚解压缩的文件夹。它会有probablycorey-wax-124ca46之类的名称。

  你的屏幕现在看起来应该像这样:

解压缩刚下载的文件

  现在,执行下列操作:

  ◆ 拷贝lib和bin文件夹,把它们粘贴到位于WaxApplication项目文件夹里面的wax文件夹。

  ◆ 将xcode-template/Classes/ProtocolLoader.h拷贝到WaxApplication项目文件夹。

  ◆ 拷贝xcode-template/scripts/文件夹,将它放到WaxApplication项目文件夹里面。

  ◆ 打开WaxApplication项目文件夹里面的wax/lib/extensions/文件夹。删除SQLite和xml文件夹,下图所示:

你的屏幕

  你的屏幕应该看起来像这样:

  设置Wax(第二部分,配置项目)

   现在用Finder选择Classes、scripts和wax文件夹,把它们拖入到Xcode项目中。把它们放到显示Wax Application和1 target, iOS SDK X.X的那个条下方。不要勾选显示Copy items into destination group’s folder(if needed)的复选框。点击完成。

  现在点击显示Wax Application和1 target, iOS SDK 4.3的那个条。接着采取下列步骤:

  ◆ 在右边窗格中,寻找Targets标题,点击WaxApplication。点击Build Phases(构建阶段)选项卡。点击Copy Bundle Resources(复制捆绑资源),清除所有lua文件。

  ◆ 在右下角,先点击Add Build Phase(添加构建阶段),再点击Add Run Script(添加运行脚本)。

  ◆ 将Shell设成/bin/zsh

  ◆ 将Shell下面的文本区域设成$PROJECT_DIR/wax/lib/build-scripts/copy-scripts.sh。

  你的屏幕现在看起来像这样:

打开main.m

  改动main.m

  在左边窗格中,打开名为WaxApplication的文件夹。接下来,打开Supporting Files文件夹。接着,打开main.m,把文件的内容换成如下:

   //这是发生奇迹的地方!
   // Wax并不使用nib文件来装入主视图,一切在AppDelegate.lua文件里面完成
   #import <UIKit/UIKit.h>
   #import "wax.h"
   #import "wax_http.h"
   #import "wax_json.h"
   #import "wax_filesystem.h"
   int main(int argc, char *argv[]) {
   NSAutoreleasePool * pool =[[NSAutoreleasePool alloc] init];
    
   wax_start("AppDelegate.lua", luaopen_wax_http, luaopen_wax_json, luaopen_wax_filesystem, nil);
    
   int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate");
   [pool release];
   return retVal;
   }

  别忘了保存文件!

  删除不必要的文件

   删除MainWindow.xib、WaxApplicationAppDelegate.h和 WaxApplicationAppDelegate.m三个文件。打开WaxApplication/Supporting Files/WaxPallication-Info.plist,然后删除键是Main nib file base name的那一行。

  测试安装的Wax

  按↵(命令+回车键),或者按左上角的Run,就可以在模拟器中运行应用程序。要是一切正常,你会看到一个简单的应用程序会说Hello Lua!。

  要是你没看到这个消息,检查之前的步骤,看看有没有步骤漏了。

  查看Lua

  展开Scripts文件夹,打开AppDelegate.lua。你会看到运行该应用程序的Lua代码。

  你可能会先注意到,没有语法高亮。遗憾的是,对于Xcode中的Lua语法高亮问题,我还没有发现稳定的解决方案(是你发现了,请留言告诉我!)。

  接下来你可能会注意到,没有方括号,不过使用了像UIScreen和UIWindow这些类。那是由于你在使用Lua构建一个AppDelegate类;在苹果和苹果的代码看来,你在使用Objective-C、构建Objective-C类!

  方法名称

   你可能还注意到奇怪的方法名称colorWithRed_green_blue_alpha。要是你熟悉Objective-C,就知道方法名称可以有 冒号。Lua中的函数名称不能有冒号。为了补偿这个差异,凡是Objective-C中隔开方法名称的地方,在Lua中都换成下划线。比如说:

  Objective-C中的colorWithRed:green:blue:alpha对应于Lua中的colorWithRed_green_blue_alpha。

  Objective-C中的selectRowAtIndexPath:animated:scrollPosition:对应于Lua中的selectRowAtIndexPath_animated_scrollPosition。

  面向对象的模型

  Lua的另一个问题是,它没有像Objective-C那样的继承体系。Lua中根本没有类。为了克服这个问题,Wax突出显示了放在每个Wax Lua文件最前面的一个函数:waxClass。在默认的AppDelegate.lua中,这一行看起来像这样:

   waxClass{"AppDelegate", protocols = {"UIApplicationDelegate"}}

  想通过Lua创建一个Objective-C类,就要使用waxClass{CLASS NAME, PARENT_CLASS}这个函数。你添加到该Lua文件的所有之后的函数(在同一个文件里面)都会作为实例方法,自动添加到新的类。

  AppDelegate.lua的这一行显示,还可以定义你的类定义哪些协议。

   虽然waxClass解决了定义Objective-C可以使用的类这个问题,但还是存在一个问题:由于Lua没有类,它没有像Objective-C 那样的动态自变量。为了克服这个问题,Wax自动将每个方法的第一个变量作为类的当前实例。你可以发现,当你查看AppDelegate.lua中的 applicationDidFinishLaunching时,第一个变量是自变量,即使Objective-C版的这个方法只有1个变量。然而,如果 你非得将类的当前实例作为每个方法的第一个变量来传送,就会很烦人,于是添加了一些语法上的便利(syntactical sugar)。不是使用.操作符在Lua中进行方法调用,而是使用了:操作符:

local view = UIView.initWithFrame(CGRect(0, 0, 100, 100))

  --以下一模一样

   view:addSubview(someView)
   
iew.addSubview(view, someView)

  值得一提的另一个重要方面是,Wax不支持Objective-C属性。Wax迫使Lua和Objective-C只与方法进行联系。

  -- 这不行

someView.frame

  -- 你而是需要使用getter/setter方法

   View:frame() some
  
View:setFrame(someFrame)

  只用于Lua的变量

   你可以使用点.操作符,为任何Objective-C对象创建成员变量。不像冒号:操作符(用于对Objective-C类/实例调用方法),点.操作 符可以针对对象的Lua方面,动态创建成员变量(对象的Objective-C方面对这些变量一无所知)。在对象的生命周期之内,都可以使用成员变量。

  输出到控制台

  AppDelegate.lua还显示了你如何可以编写调试文本、输出到控制台。你可以使用函数puts。

  内存管理

  我之前说过,使用Lua的话,你根本没必要分配、保留和释放内存。你在调用任何初始化器之前,根本不需要调用内存分配。实际上,如果你这么做的话,程序可能会出现内存泄漏。

  太棒了!接下来做什么?

  你已经深入了解了专门针对Wax的Lua的基本知识,就可以准备编写iPhone应用程序了!

  在这个教程的第二个部分,我们将只用几行Lua,就可以编写出拥有刷新按钮的一个Twitter示例应用程序。

  看完这个教程是不是你也有信心打造出自己的《愤怒的小鸟》呢?

小贴士

Lua程序设计语言 是一个简洁、轻量、可扩展的脚本语言。Lua读作/'lua/(噜啊),是葡萄牙语中"Luna"(月亮)的意思。

Lua 是一种轻量语言,它的官方版本只包括一个精简的核心和最基本的库。这使得Lua体积小、启动速度快。它用标准C语言编写并以源代码形式开放,编译后仅仅一 百余K,可以很方便的嵌入别的程式里。和许多"大而全"的语言不一样,网路通讯、图形界面等都没有默认提供。但是Lua可以很容易地被扩展:由宿主语言 (通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。事实上,现在已经有很多成熟的扩展模块可供选用。

Lua的目标是成为一个很容易嵌入其它语言中使用的语言。大多数程序员也认为它的确做到了这一点。

很多应用程序使用Lua作为自己的嵌入式脚本语言,以此来实现可配置性、可扩展性。这其中包括大话西游II、仙境传说、魔兽世界、战锤40k、博德之门、轩辕剑外传汉之云等,在移动领域最著名的便是《愤怒的小鸟》。

  第四步:UITableViewController数据方法

   我们的应用程序可以启动,这很好,但我们想要显示一些数据。为了显示这些数据,所有UITableViewController必须实施几个方法,告诉 设备显示什么数据。其中第一个方法是numberOfSectionsInTableView:,它会返回将在表中显示的群组数量。对该应用程序来说,这 一步很容易,因为我们只需要一个表段,即拥有当前趋势的那个表段。

   function numberOfSectionsInTableView(self, tableView)
  
return1
  
end

   是不是很容易?现在我们得实施tableView_numberOfRowsInSection方法,它告诉设备某个特定的分组会有多少行。对该应用程 序来说,这同样很容易,因为我们只有一个表段。记得我们如何用init方法对Lua表进行初始化吗?只要计数该表中的表项数量,就知道该表需要显示多少 行:

   function tableView_numberOfRowsInSection(self, tableView, section)
   
return #self.trends
  
end

  这使用Lua简写方法来计数表中的表项数量。如果你不熟悉Lua表,下面有几个要点:

  1. 大多数语言中被称为词典的东西在Lua中被称为表。

  2. 大多数语言中被称为数组的东西被称为带有序数字键的表。

  3. 数组使用从1开始的索引,而几乎其他每种语言使用从0开始的索引。

  接下来是tableView_titleForHeaderInSection方法。该方法告诉设备显示什么作为某群组的标题。你只要返回某个指定群组的字符串,标题之后会神奇地出现在表行上方: 

   function tableView_titleForHeaderInSection(self, tableView, section)
  if section == 0 then
  return "Currently Trending Topics"
  end
  return nil
  end

  相当简单。现在我们只要往表格填充从Twitter的服务器取来的数据。如果你熟悉Objective-C中的UITableViewControllers,就会认识这下一个方法:

  function tableView_cellForRowAtIndexPath(self, tableView, indexPath)
  local identifier = "TwitterTableViewControllerCell"
  local cell = tableView:dequeueReusableCellWithIdentifier(identifier) or
   UITableViewCell:initWithStyle_reuseIdentifier(UITableViewCellStyleDefault, identifier)
  local object = self.trends[indexPath:row() +1] -- 必须是+1,因为Lua数组从1开始
   cell:textLabel():setText(object)
  return cell
  end

   这个方法要复杂一点。首先,我们定义了对同一种类型,但可能有不同内容的所有表格单元(cell)来说很独特的标识符。这种情况下,我们称之为 TwitterTableViewControllerCell。接下来,我们使用Lua简写方法,获得UITableViewCell的实例。注意夹在 这两个方法调用之间的or。如果第一个方法调用的结果不是false或nil, cell就被设成第一个方法调用的值。否则,cell会被设成是第二个方法调用的结果。

  我们这么做是为了节省内存。这样一来,设备每次 只要为屏幕上10个左右的表格单元分配内存,而不是为数据源里面可能拥有的数千个表格单元分配内存。当然,我们不会有数千行要显示,但这仍是个有必要养成 的好习惯。接下来,我们把表格单元的内容设成从self.trends数组的合适部分获取的趋势。我们知道,该索引从来不会超出self.trends的 范围,因为我们通过方法tableView_numberOfRowsInSection,将数组大小告诉给了设备。最后,我们返回刚创建的表格单元。如 果你现在按Run,它应该看起来像这样:

返回刚创建的表格单元

  第五步:从Twitter装入数据

  现在说说真正展现Wax魅力的好玩部分:从互联网、或者更准确地说从Twitter的服务器装入JSON数据。先不妨创建一个名为loadDataFromTwitter的新方法。该方法会从Twitter的服务器获取JSON数据,然后为表重新装入新数据。

  function loadDataFromTwitter(self)
   UIApplication:sharedApplication():setNetworkActivityIndicatorVisible(true) -- show spinner
   wax.http.request{"http://api.twitter.com/1/trends.json", callback =function(json, response)
   UIApplication:sharedApplication():setNetworkActivityIndicatorVisible(false) -- hide spinner
  if response:statusCode() == 200 then
   self.trends = {} -- Reset the list of trends when the trends are refreshed
  for index,value in ipairs(json["trends"]) do-- iterate over a table with numerical keys
  table.insert(self.trends, value["name"]) -- append the value to the "array"
  end
  end
   self:tableView():reloadData()
  end}
  end

   是的,就这么简单。你定义了请求的URL以及请求完毕后执行的回调。Wax自动确认服务器在运行JSON后,会将JSON文本自动转换成Lua表。这使 得显示网络活动指示器(设备右上角靠近无线信号指示器的图标)异常容易。返回的JSON看起来像这样。键trends保存一组对象,这些对象包含趋势名称 和访问提到该趋势的所有Twitter消息的URL。

  趋势名称存储到self.trends变量里面后,重新装入tableView,它可以再次调用我们之前定义的所有数据方法。这导致趋势在表中显示,非常类似最终产品。

  如果你立即试图运行该应用程序,看上去没什么不同。那是因为该方法从未调用。如果从viewDidLoad:里面调用该方法,我们就能确保总是可以显示最新趋势。把这行添加到viewDidLoad:方法末行的前一行:

   self:loadDataFromTwitter()

  如果你点击Run,应用程序看起来有点像这样(你得等几秒钟装入趋势,请留意那个活动指示器!):

请留意那个活动指示器

  第六步:添加重新装入按钮

  该应用程序相当棒。不过,要是有重新装入按钮让你可以显示最新趋势,就更好了。幸好,这很容易实现。

  不妨把重新装入按钮放到屏幕的右上角。苹果其实提供了上面有刷新图标的按钮,以图方便,就用这个按钮吧。先开始用viewDidLoad:方法创建一个按钮。把下面这行添加到loadDataFromTwitter调用的前面。

  local button = UIBarButtonItem:initWithBarButtonSystemItem_target_action(UIBarButtonSystemItemRefresh, self, "loadDataFromTwitter")

  这创建了一个UIBarButtonItem:一旦按下按钮,就会对当前对象实例调用loadDataFromTwitter方法。如果你想尝试其他风格。

  我们已创建好了按钮,现在需要把它添加到我们的界面上。使用UITableViewController使得这项工作轻而容易,我们只要对导航栏对象实例调用setRightBarButtonItem:方法,就像这样(这行位于上面给出的那一行后面):

   self:navigationItem():setRightBarButtonItem(button)

  如果你各方面都做好了,完成的应用程序应该看起来像这样:

完成的应用程序

  第七步:额外好处

  这个项目一个有意思的扩展就是制作更显眼的装入指示器。这可能需要把UIActivityIndicatorView放到其中一个按钮位置。

  结论

  我希望你觉得这篇教程深入浅出地介绍了Wax。如果你想看到有关某个课题的更多Wax教程,欢迎给我留言。

全文阅读>>

推荐小组: 设计 插画 网站技术

关注我们: 关注新浪微博 豆瓣小组 人人网 腾讯微博 RSS

Starming 星光社 版本:0.06 email:ming1016@gmail.com 关于我们 点击这里给我QQ发消息 小组 wave 购物 精选 鄂ICP备11004199

相关 [开发 愤怒 lua] 推荐:

开发愤怒的小鸟的Lua语言:Wax框架详解

- sun - Starming星光社最新更新
摘要:我们都知道Objective-C和Cocoa语言可以开发iOS应用,但是一年前,苹果决定在 iOS系统上使用Lua语言. Wax框架的想法很简单:凡是Objective-C能做的,Lua也能做. 考虑使用像Lua这样一门简单而高效的编程语 言,构建原生iPhone应用程序有许多充分的理由,而本文将深入探讨Wax具有的一些好处,同时演示把Lua与Xcode 4和iOS软件开发工具包(SDK)集成起来必不可少的实际步骤.

《愤怒的小鸟》开发语言Lua爆红,挤掉JavaScript排名

- http://groups.google.com/group/dotnet_cn - ITeye资讯频道
    随着iOS开始支持Lua脚本语言,许多iPhone游戏开始使用Lua开发,例如大名鼎鼎的《愤怒的小鸟》,Lua流行指数快速窜起,甚至在今年6月超越了JavaScript,进入TIOBE前10大开发语言排行.     根据全球开发语言普及度排行榜TIOBE最新的6月统计结果,Lua脚本语言首度进入前10名,热门程度仅次于Perl,也将JavaScript挤出前十名而排名第11位,前两年因Rails开发框架窜起的Ruby语言则落到第12名.

5本Lua免费电子书

- sospartan - 读写网 ReadWriteWeb
在最新的编程语言排名中,Lua超过了JavaScript进入了前十名──许多人使用Lua进行“魔兽世界”的脚本编写. 所以,在本周的免费资源推荐中我们找到了一些免费的学习Lua的电子书,无论你想使.

Lua 下实现抢占式多线程

- Coder(码农) - 云风的 BLOG
Lua 5.2 的开发进度可以回溯到 2010 年 1 月. 漫长的流程到今天已经快两年过去,终于等到了 beta 版. 我十分期待它可以在 2011 年内正式发布. 在这几经折腾的两年里,许多新特性企图挤进 5.2 版,又最终被否决. 当我们审视改进列表,似乎看不到太多耳目一新的东西. 但如果仔细阅读一下源代码,就会发现,大部分地方都重新实现过了,以配合这些表面上看起来不大的修改.

编写高性能的Lua代码

- - 九点 科技
Lua是一门以其性能著称的脚本语言,被广泛应用在很多方面,尤其是游戏. 像《魔兽世界》的插件,手机游戏《大掌门》《神曲》《迷失之地》等用Lua来写游戏逻辑. 所以大部分时候我们不需要去考虑性能问题. Knuth有句名言:“过早优化是万恶之源”. 其意思就是过早优化是不必要的,会浪费大量时间,而且容易导致代码混乱.

nginx+lua+memcache实现灰度发布

- - 开源软件 - ITeye博客
灰度发布在百度百科中解释:. 灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式. AB test就是一种灰度发布方式,让一部分用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面 来. 灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度.

采访 Lua 发明人的一篇文章

- KK - 云风的 BLOG
《Masterminds of Programming: Conversations with the Creators of Major Programming Languages》是本相当不错的书. 博文翻译出版了这本书,中文名叫做《编程之魂》. 书是好书,可惜翻译这本书需要对各种语言的深入研究,看起来译者有点力不从心.

lua中处理变参数的一些技巧

- return - 为着理想勇敢前进
从lua 5.1开始,就不鼓励用隐含的arg来处理可变变量了,推荐做法是使用递归来处理.... 在lua中,不论多返回值还是函数调用,...都只能用于最后剩下的参数,例如下列代码中. 这是因为第一个print调用是把...作为剩余的所有参数传进去,而第二次调用,...则被调整为1个参数. 如果要想把参数添加到...后面,有两种做法.

使用varnish + nginx + lua搭建网站的降级系统

- - 博学无忧
通常一个网站数据库挂掉后,后果将是非常严重的. 对于一些网站来说,当数据库挂掉后,如果能提供基本的浏览服务,也是不错的. 本文将尝试使用varnish + nginx + lua 搭建网站降级系统来实现整个目标. 降级方案的目标是,当网站出现致命故障时(如出现500错误,不能提供服务),可以把缓存的页面数据展现给用户.

基于Lua+Kafka+Heka的Nginx Log实时监控系统

- - 开源软件 - ITeye博客
在我们的系统架构中,Nginx作为所有HTTP请求的入口,是非常重要的一层. 每天产生大量的Nginx Access Log,闲置在硬盘上实在是太浪费资源了. 所以,能不能把Nginx日志利用起来,实时监控每个业务的访问趋势、用户行为、请求质量和后端异常呢,这就是本文要探讨的主题. 错误码告警(499、500、502和504);.