首先说明我使用的编辑器是Cocos Code IDE,大家可以去官网下载这个软件(我个人使用的时候总体上来说感觉还是不错的),然后参照官方的教程搭建环境,一切准备OK以后,就开始我们的小游戏吧!

首先用Cocos Code IDE新建一个工程,取名为DontCrash,然后删除原工程下的GameScene.lua文件。再新建一个文件,取名为FlashScene,我们要将该文件作为一个场景类,那么如何组织这个模块呢?我们需要明确的是模块的基本定义是在一个Lua文件中写一个表,然后返回这个表,这样就将FlashScene作为一个模块了。

1--创建一个类,继承自scene,class返回一张表
2local FlashScene = class("FlashScene",function()
3    return cc.Scene:create()
4end
5)
6 
7--最后返回这张表
8return FlashScene

我们使用class函数返回了一张表,然后把它赋给了变量FlashScene,class函数的第一个参数是类名,第二个参数是继承的父类,以后需要继承父类的时候参照这种写法就OK了,最后比较重要的是要记得返回FlashScene这张表,当其他模块require该模块的时候,我们返回了FlashScene表,这张表中将包含该类用到的所有方法和变量,我们需要调用函数和使用变量的时候从这张表中获取数据就好了。

接下来再看俩个函数,一个是ctor,一个是create。

1--类似c++中的构造函数
2function FlashScene:ctor()
3    --self代表的就是FlashScene,将size作为它的成员,添加到这张表中
4    self.size = cc.Director:getInstance():getWinSize()
5end
6 
7--create留下给外部调用的接口
8function FlashScene:create()
9    --new函数的作用是调用了构造函数ctor,然后将表FlashScene的所有元素复制到了一张新的表中,最后返回这张表
10    local flashScene = FlashScene:new()
11    local layer = flashScene:createLayer()
12    flashScene:addChild(layer)
13 
14    return flashScene
15end

ctor函数类似c++中的构造函数,这个在原生Lua中是没有的,是Cocos采用的做法。当FlashScene调用new函数的时候在函数的内部创建了一张新表,然后至少做了三步操作,1、调用class函数传入的第二个参数——一个函数,在这个函数中完成了初始化父类的工作,然后将父类表里边的内容复制到这张新的表中。2、将表FlashScene的所有元素(变量和方法)复制到了新表中,也就是本表中的成员变量复制到了这张新的表中。3、调用ctor函数,在这个函数中我们可以初始化一些成员变量,然后将这些成员变量放到表中,这样这张新创建的表中就有了父类的所有内容,FlashScene所有的内容,以及初始化的内容,create函数在最后返回了这张新表,所以我们外部调用create的时候就相当于创建了一个对象。因此无论我们是否去创建一个create函数,这个new函数是必须要调用的,否则你自己用Lua实现类和继承。在ctor中,调用cocos提供出来的模块cc,获得了窗口的大小,赋值给了FlashScene中的成员size。在create函数中flashScene还调用了createLayer函数,该函数的实现如下,最后返回一个layer。

1--创建一个层,在层上加入元素
2function FlashScene:createLayer()
3    local layer = cc.Layer:create()
4 
5    --动作的回调函数
6    local action_callback = function()
7        cc.Director:getInstance():replaceScene(require("MainGameScene"):create())
8    end
9 
10    --使用Cocos提供的模块cc,调用Sprite的方法创建一个logo出来,你在Cocos2d-x看到的内容,都可以从这个模块中获得(前提是有导出)
11    local logo = cc.Sprite:create("logo.png")
12    logo:setPosition(self.size.width/2,self.size.height/2)
13    layer:addChild(logo)
14 
15    --logo执行一个淡入淡出的动作
16    logo:setOpacity(0)
17    local action = cc.Sequence:create(cc.FadeIn:create(2),cc.CallFunc:create(action_callback))
18    logo:runAction(action)
19 
20    --游戏标题
21    local title = cc.Sprite:create("title.png")
22    title:setPosition(self.size.width+title:getContentSize().width/2,self.size.height*0.88)
23    layer:addChild(title)
24 
25    --title执行动作
26    --moveto的第二个参数是一个table,里边的成员是命名参数,必须指定参数的名字为x和y,许多的函数调用都需要这么做
27    local title_action = cc.Sequence:create(cc.MoveTo:create(0.5,{x=self.size.width/2-100,y=title:getPositionY()}),
28         cc.Spawn:create(cc.MoveBy:create(0.1,{x=200,y=0}),cc.SkewTo:create(0.1,0,-45)),
29         cc.Spawn:create(cc.MoveBy:create(0.2,{x=-150,y=0}),cc.SkewTo:create(0.2,0,45)),
30         cc.Spawn:create(cc.MoveBy:create(0.2,{x=50,y=0}),cc.SkewTo:create(0.2,0,0))
31         )
32    title:runAction(title_action)    
33 
34    return layer
35end

这个函数中涉及的多数知识都是Cocos中的基本内容,比如精灵,动作等等这些东西,相信会Cocos的朋友理解起来不难。我需要说明的是如何使用Cocos提供给我们的接口。我们需要使用模块cc,这个模块通过lua-binding已经放到了Lua的全局表中,在该模块中注册了Cocos给我们导出的所有接口,所以我们要使用这些接口,这些类的时候就需要用cc.的形势,然后其他场景、层、精灵等等的思想就和Cocos中的完全一样了。函数的调用使用冒号的形式,变量的获得(因为是从表中获取)使用.的形式。例如cc.Sprite:create()这个调用,Sprite是模块cc中的变量,所以使用.的形式,create函数是Sprite中的成员,使用:将自己作为一个参数传入到了create函数中,相当于是Sprite.create(Sprite),Cocos提供出来的函数接口我们需要用:的形式访问函数。

这样一个基本的模块就写好了,在Lua中写游戏的时候就是这样一个模块一个模块来写的,每一个模块都是一个场景,而模块的实质就是一张表,把函数和变量放到这个表里边,没有放入到表里边的内容如果是局部变量外部是访问不到的,如果是全局变量外部同样可以访问。以上的内容是一个模块最基本的内容,为了实现其他的功能,我们需要在这个的基础上再添加其他的内容。我将这个基本的结构列举如下,大家在写其他模块的时候参照这个基本的结构来写。

1--使用require引入其他模块
2require("Cocos2d")
3require("Cocos2dConstants")
4 
5--创建一个类,继承自scene
6local FlashScene = class("FlashScene",function()
7    return cc.Scene:create()
8end
9)
10 
11--类似c++中的构造函数
12function FlashScene:ctor()
13    --self代表的就是FlashScene,将size作为它的成员,添加到这张表中
14    self.size = cc.Director:getInstance():getWinSize()
15end
16 
17--create留下给外部调用的接口
18function FlashScene:create()
19    --new函数的作用是调用了构造函数ctor,然后将表FlashScene的所有元素复制到了一张新的表中,最后返回这张表
20    local flashScene = FlashScene:new()
21 
22    return flashScene
23end
24 
25--其他的一些函数(包括局部函数)以及变量...
26 
27--返回FlashScene这个模块
28return FlashScene

Lua小游戏别撞车——搭建开始场景

刚刚我们定义了一个模块FlashScene,现在我们在main.lua中使用一下这个模块。我们使用require引入模块FlashScene,require函数会去查找对应的.lua文件或者是库文件,查找的路径放到了变量package.path(查找Lua文件)和package.cpath(查找dll或者是so文件)中。

1--使用模块FlashScene
2    local scene = require("FlashScene")
3    --使用模块中的接口函数create,创建一个场景
4    local gameScene = scene.create()
5 
6    --判断当前是否存在正在运行的场景,如果存在切换场景,不存在的话就使用runWithScene运行场景
7    if cc.Director:getInstance():getRunningScene() then
8        cc.Director:getInstance():replaceScene(gameScene)
9    else
10        cc.Director:getInstance():runWithScene(gameScene)
11    end

最后我们在main.lua中添加一下适配的代码,整个main.lua完整的代码如下。

1require "Cocos2d"
2 
3-- cclog
4local cclog = function(...)
5    print(string.format(...))
6end
7 
8-- for CCLuaEngine traceback
9function __G__TRACKBACK__(msg)
10    cclog("----------------------------------------")
11    cclog("LUA ERROR: " .. tostring(msg) .. "n")
12    cclog(debug.traceback())
13    cclog("----------------------------------------")
14    return msg
15end
16 
17local function main()
18    collectgarbage("collect")
19    -- avoid memory leak
20    collectgarbage("setpause", 100)
21    collectgarbage("setstepmul", 5000)
22 
23    cc.FileUtils:getInstance():addSearchPath("src")
24    cc.FileUtils:getInstance():addSearchPath("res")
25    cc.Director:getInstance():getOpenGLView():setDesignResolutionSize(480, 320, 0)
26 
27    --我采用如下的适配方法
28    local pEGLView = cc.Director:getInstance():getOpenGLView()
29    local frameSize = pEGLView:getFrameSize()
30    --这里的尺寸写背景图片的大小
31    local winSize = {width=1280,height=720}
32 
33    local widthRate = frameSize.width/winSize.width
34    local heightRate = frameSize.height/winSize.height
35 
36    if widthRate > heightRate then
37        pEGLView:setDesignResolutionSize(winSize.width,
38            winSize.height*heightRate/widthRate, 1)
39    else
40        pEGLView:setDesignResolutionSize(winSize.width*widthRate/heightRate, winSize.height,
41            1)
42    end
43 
44    --使用模块FlashScene
45    local scene = require("FlashScene")
46    --使用模块中的接口函数create,创建一个场景
47    local gameScene = scene.create()
48 
49    --判断当前是否存在正在运行的场景,如果存在切换场景,不存在的话就使用runWithScene运行场景
50    if cc.Director:getInstance():getRunningScene() then
51        cc.Director:getInstance():replaceScene(gameScene)
52    else
53        cc.Director:getInstance():runWithScene(gameScene)
54    end
55 
56end
57 
58local status, msg = xpcall(main, __G__TRACKBACK__)
59if not status then
60    error(msg)
61end