CC3.2+Lua(9) ——从C++过渡到Lua

本文出自 “夏天的风” 博客,请务必保留此出处http://www.voidcn.com/article/p-cmebpzex-wx.html  本人只是出自学习方便特转到此处
标签: lua  cocos2dx
原创作品,允许转载,转载时请务必以超链接形式标明文章  原始出处 、作者信息和本声明。否则将追究法律责任。 http://www.voidcn.com/article/p-cmebpzex-wx.html

【唠叨】

    现在开始学习Lua了,开始用 Cocos Code IDE 开发cocos2dx的游戏了。

    可是呢,因为 cocos2dx v3.x 刚刚才出来不久,所以网上的教程大部分都是基于C++版本的,

    而针对Lua版本的大部分都是老版本 v2.x 的教程,对于用 v3.x 的我来说,很多都不适用了。

    无奈之下只好自己摸索,经过几天的学习,积累了一些 Lua 与 C++ 开发cocos2dx游戏之间的差异。

    现在就在此总结一下。


【番外】

    Cocos2d-X官方就在2014年10月28日,发布了 Cocos引擎v1.0 Preview版 。

    将Cocos StudioCocos Code IDECocos2d-X 三件套进行了集成,一键部署安装。

    看着实在是太酷炫了,这也说明使用脚本语言 Lua 开发cocos2dx游戏必将越发流行。




【从C++过渡到Lua】


1、Lua中如何使用cocos2dx引擎中的类?

    在C++中是这样调用的:

1
2
3
4
5
//
     Sprite* sprite = Sprite::create();
sprite->setPosition(Vec2(100, 100));
     this ->addChild(sprite);
//

    而在Lua中是这样调用的:

//
     local  sprite = cc.Sprite: create ()
     sprite:setPosition(cc.p(100, 100))
self:addChild(sprite)
//

    是不是很简单?差别其实不是很大嘛!

    Lua中使用引擎中的类,只要在前面多加个 cc. 即可。

    而调用类的函数,不是双冒号:: ,而是一个冒号: 。


2、Lua 与 C++ 使用上有何差异?

    请耐心看完以下这个类,你或许会有基本上的了解。

    PS:我比较懒,所以用代码来代替文字描述了。

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//
winSize = cc.Director:getInstance():getWinSize()
 
 
-- 继承Layer类
MenuLayer = class( "MenuLayer" function ()
return  cc.Layer: ()
end )
 
 
-- 初始化函数
function  MenuLayer:ctor()
self. name  "hello"          -- 成员变量
size  = cc. size (0, 0)    -- 成员变量
end
 
 
-- 创建包含GameLayer的场景
MenuLayer:createScene()
scene = cc.Scene: ()
layer = MenuLayer: ()
scene:addChild(layer)
scene
end
 
 
-- 创建GameLayer层
MenuLayer: ()
layer = MenuLayer.new()   -- new()
layer:init()                    -- init()
layer
end
 
 
-- 初始化
MenuLayer:init()
self:ShowUI()        -- 添加界面元素(Sprite、Label等)
self:addBtn()        -- 添加菜单按钮
self:addTouches()    -- 添加多点触摸
end
 
 
-- 添加界面
MenuLayer:ShowUI()
 
     -- 背景图片Sprite
bg = cc.Sprite: ( "HelloWorld.png" )
bg:setPosition(cc.p(0, 0))       -- 设置位置
bg:setAnchorPoint(0, 0)          -- 设置锚点
self:addChild(bg)                -- 添加子节点
 
-- 添加文字
self.label = cc.Label:createWithSystemFont( "debug" "res/fonts/Marker Felt.ttf" self.label:setPosition(winSize.width/2, winSize.height/2)
self:addChild(self.label)
 
end
 
 
-- 添加按钮
MenuLayer:addBtn()
 
menu
normal, hard
 
-- 回调函数
-- tag 为menuItem设置的标签setTag ,menuItem为相应对象
local  menuCallback(tag, menuItem)
         print( "menuItem: "  .. tag)     -- Lua中的输出语句
end
 
normal = cc.MenuItemImage: "normal.png" )
normal:setPosition(0, 120)
normal:setTag(1)
normal:registerScriptTapHandler(menuCallback)    -- 按钮事件
 
hard = cc.MenuItemImage: "hard.png" )
hard:setPosition(0, 20)
hard:setTag(2)
hard:registerScriptTapHandler(menuCallback)      -- 按钮事件
 
-- 创建菜单,最后不需要加NULL
menu = cc.Menu: (normal, hard)
self:addChild(menu)
 
end
 
 
-- 多点触摸
MenuLayer:addTouches()
 
touch1, touch2 = cc.Touch, cc.Touch
onTouchesBegan(touches, event)
"Touches Began" )
touch1 = touches[1]      -- 第一个触点,下标从1开始
touch2 = touches[2]      -- 第二个触点
         pos1 = touch1:getLocation()    -- 获取触点1的位置
pos2 = touch2:getLocation()    -- 获取触点2的位置
delta = {
             x = pos2.x - pos1.x ,
y = pos2.y - pos1.y
}
print(delta.x ..  " , "  .. delta.y)   -- 输出log
end
 
onTouchesMoved(touches, event)
"Touches Moved" )
end
 
onTouchesEnded(touches, event)
"Touches Ended" )
end
 
-- 注册多点触摸
dispatcher = cc.Director:getInstance():getEventDispatcher()
listener = cc.EventListenerTouchAllAtOnce: ()
listener:registerScriptHandler(onTouchesBegan, cc.Handler.EVENT_TOUCHES_BEGAN)
listener:registerScriptHandler(onTouchesMoved, cc.Handler.EVENT_TOUCHES_MOVED)
listener:registerScriptHandler(onTouchesEnded, cc.Handler.EVENT_TOUCHES_ENDED)
dispatcher:addEventListenerWithSceneGraphPriority(listener, self)
 
end
//


3、Lua中的字符串格式转换?

    C++中是这样使用的:

3
    
sprintf (str,  "hero_%02d.png" 而在Lua中则是使用 string.format() 函数。

string.format( "hero_%02d.png" 4、Lua中的枚举类型

    我们都知道C++中的枚举都改成了强枚举类型,形如 Control::State::NORMAL 。

    而在Lua中将其变成形如:cc.CONTROL_STATE_NORMAL 。

    估计你已经明白了吧?把所有字母都变成大写,然后把双冒号:: 变成下划线 _ 即可。

    下面列出一些我自己整理的常见枚举类型在Lua中是如何使用的。

119
-- ResolutionPolicy 屏幕适配(就这个比较奇葩。。。)
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1550089
cc.ResolutionPolicy.EXACT_FIT
cc.ResolutionPolicy.FIXED_HEIGHT
cc.ResolutionPolicy.FIXED_WIDTH
cc.ResolutionPolicy.NO_BORDER
cc.ResolutionPolicy.SHOW_ALL
     
     
-- EventKeyboard::KeyCode 键盘按键枚举类型(这个也比较奇葩。。。)
-- 含义参见(键盘事件部分):http://shahdza.blog.51cto.com/2410787/1560222
-- 键盘按键比较多,所以就罗列一部分
cc.KeyCode.KEY_A
cc.KeyCode.KEY_1
cc.KeyCode.KEY_F1
cc.KeyCode.KEY_SPACE
cc.KeyCode.KEY_ALT
cc.KeyCode.KEY_SHIFT
 
 
-- Control::EventType 控件事件类型
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1543349
cc.CONTROL_EVENTTYPE_TOUCH_DOWN
cc.CONTROL_EVENTTYPE_DRAG_INSIDE
cc.CONTROL_EVENTTYPE_DRAG_OUTSIDE
cc.CONTROL_EVENTTYPE_DRAG_ENTER
cc.CONTROL_EVENTTYPE_DRAG_EXIT
cc.CONTROL_EVENTTYPE_TOUCH_UP_INSIDE
cc.CONTROL_EVENTTYPE_TOUCH_UP_OUTSIDE
cc.CONTROL_EVENTTYPE_TOUCH_CANCEL
cc.CONTROL_EVENTTYPE_VALUE_CHANGED
 
-- Control::State 控件状态
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1543349
cc.CONTROL_STATE_NORMAL
cc.CONTROL_STATE_DISABLED
cc.CONTROL_STATE_SELECTED
cc.CONTROL_STATE_HIGH_LIGHTED
 
 
-- EditBox::EditBoxInputMode 文本框虚拟键盘的编辑类型
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1544213
cc.EDITBOX_INPUT_MODE_ANY
cc.EDITBOX_INPUT_MODE_URL
cc.EDITBOX_INPUT_MODE_DECIMAL
cc.EDITBOX_INPUT_MODE_NUMERIC
cc.EDITBOX_INPUT_MODE_EMAILADDR
cc.EDITBOX_INPUT_MODE_SINGLELINE
cc.EDITBOX_INPUT_MODE_PHONENUMBER
 
-- EditBox::EditBoxInputFlag 文本框文本类型
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1544213
cc.EDITBOX_INPUT_FLAG_PASSWORD
cc.EDITBOX_INPUT_FLAG_SENSITIVE
cc.EDITBOX_INPUT_FLAG_INITIAL_CAPS_WORD
cc.EDITBOX_INPUT_FLAG_INITIAL_CAPS_SENTENCE
cc.EDITBOX_INPUT_FLAG_INITIAL_CAPS_ALL_CHARACTERS
 
-- EditBox::KeyboardReturnType 文本框虚拟键盘中return键显示字符
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1544213
cc.KEYBOARD_RETURNTYPE_GO
cc.KEYBOARD_RETURNTYPE_DONE
cc.KEYBOARD_RETURNTYPE_SEND
cc.KEYBOARD_RETURNTYPE_SEARCH
cc.KEYBOARD_RETURNTYPE_DEFAULT
 
 
-- ScrollView::Direction 滚动方向
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1544983
cc.SCROLLVIEW_DIRECTION_BOTH
cc.SCROLLVIEW_DIRECTION_VERTICAL
cc.SCROLLVIEW_DIRECTION_HORIZONTAL
 
 
-- TableView::VerticalFillOrder 列表视图排列方式
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1545383
cc.TABLEVIEW_FILL_TOPDOWN
cc.TABLEVIEW_FILL_BOTTOMUP
 
 
-- ProgressTimer::Type
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1546707
cc.PROGRESS_TIMER_TYPE_BAR
cc.PROGRESS_TIMER_TYPE_RADIAL
 
 
-- ParticleSystem::PositionType 粒子位置模式
-- 含义参见:
cc.POSITION_TYPE_FREE
cc.POSITION_TYPE_GROUPED
cc.POSITION_TYPE_RELATIVE
 
-- ParticleSystem::Mode 粒子发射器类型
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1547636
cc.PARTICLE_MODE_RADIUS
cc.PARTICLE_MODE_GRAVITY
 
 
-- TransitionScene::Orientation 场景切换方向
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1547977
cc.TRANSITION_ORIENTATION_UP_OVER
cc.TRANSITION_ORIENTATION_DOWN_OVER
cc.TRANSITION_ORIENTATION_LEFT_OVER
cc.TRANSITION_ORIENTATION_RIGHT_OVER
 
 
-- TextVAlignment 文本的垂直对其方式
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1560612
cc.VERTICAL_TEXT_ALIGNMENT_TOP
cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM
cc.VERTICAL_TEXT_ALIGNMENT_CENTER
 
-- TextHAlignment 文本的水平对其方式
-- 含义参见:http://shahdza.blog.51cto.com/2410787/1560612
cc.TEXT_ALIGNMENT_LEFT
cc.TEXT_ALIGNMENT_RIGHT
cc.TEXT_ALIGNMENT_CENTER
//


5、Lua中的事件回调

    cocos2dx中常用的事件回调有如下:

        > 动作回调         : CallFunc

        > 定时器刷新       : schedule

        > 菜单项事件回调   : menuItem

        > 按钮控件事件回调 : ControlButton

    在cocos2dx v3.2中,由于支持了C++ 11,使用 std::bind 集成了 CC_CALLBACK_* 。

    在Lua中可不能这样方便的使用。


  5.1、动作回调 CallFunc

    在C++中,动作回调参见:http://www.voidcn.com/article/p-kiicpnup-wx.html

    在Lua中只剩下一个 CallFunc ,其定义如下:

    至于回调函数中有什么参数,参见下面的例子。

-- hander : 执行的回调函数
-- value  : 传递给回调函数的参数,必须为一个table
cc.CallFunc: (hander, value)
//

    使用举例:

16
-- node : 执行动作的对象
-- tab  : 传过来的参数, 必须为一个table
callbackFunc(node, tab)
node:setScale(2)
"x="  .. tab.x ..  ",y="  .. tab.y)
end
 
)
sprite:setPosition(winSize.width/2, winSize.height/2)
self:addChild(sprite)
 
-- CallFunc回调动作
call = cc.CallFunc: (callbackFunc, {x=1 , y=2} )
sprite:runAction(call)
//


  5.2、定时器刷新 schedule

    在C++中,定时器参见:http://www.voidcn.com/article/p-hdoaqjqx-wx.html

    在Lua中,有两种方式:

    (1)self:scheduleUpdateWithPriorityLua(update,priority)

        > 参数一:刷新函数

        > 参数二:刷新优先级

        其中 self 为 Node类 的子类。

        该方法默认为每帧都刷新一次,无法自定义刷新时间间隔。

    (2)scheduler:scheduleScriptFunc(update,inteval,false)

        > 参数一:刷新函数

        > 参数二:每次刷新的时间间隔

        > 参数三:是否只执行一次。false为无限次。

        其中 scheduler 为定时器管理:cc.Director:getInstance():getScheduler()

    而我更推荐使用第二种方式,因为比较通用。

    使用举例:

20
scheduler, myupdate
timer = 0
     
function  update (dt)
cclog( "update: "  .. dt)  -- 输出log
timer = timer + dt
if timer >= 3  then                                   -- 执行3秒取消定时器
             -- self:unscheduleUpdate()                  -- 取消定时器
scheduler:unscheduleScriptEntry(myupdate)    -- 取消定时器
end
end
 
-- 每帧执行一次update,优先级为0
-- self:scheduleUpdateWithPriorityLua(update, 0);
 
-- 每30/60秒执行一次update,会无限执行
scheduler = cc.Director:getInstance():getScheduler()
myupdate = scheduler:scheduleScriptFunc( false )
5.3、菜单项事件回调 menuItem

    在C++中,菜单项回调参见:http://www.voidcn.com/article/p-kiicpnup-wx.html

    在Lua中,使用:registerScriptTapHandler(hander) 。

    其中 hander 即为需要绑定的回调函数,至于回调函数中有什么参数,参见下面的例子。

    使用举例:

27
menu
 
-- tag      : 为menuItem设置的标签setTag
-- menuItem : 执行回调的menuItem对象
.. tag)
end
 
)
normal:setTag(1)
 
)
hard:setTag(2)
 
-- 创建菜单,最后不需要加NULL
self:addChild(menu)
 
     
-- 菜单项回调
-- 按钮事件
-- 按钮事件
5.4、按钮控件事件回调 ControlButton

    在C++中,按钮控件事件回调参见:http://www.voidcn.com/article/p-azrzmrlp-wx.html

    在Lua中,使用:registerControlEventHandler(hander,type) 。

    其中 hander 为我们需要绑定的回调函数,而 type 则是按钮事件的类型。

    至于回调函数中有什么参数,参见下面的例子。

    对于 type ,有以下几种类型:

11
cc.CONTROL_EVENTTYPE_TOUCH_DOWN         
-- 刚刚开始触摸按钮时
cc.CONTROL_EVENTTYPE_DRAG_INSIDE         -- 在内部拖动时(保持触摸状态下)
cc.CONTROL_EVENTTYPE_DRAG_OUTSIDE        -- 在外部拖动时(保持触摸状态下)
cc.CONTROL_EVENTTYPE_DRAG_ENTER          -- 拖动刚进入内部时(保持触摸状态下)
cc.CONTROL_EVENTTYPE_DRAG_EXIT           -- 拖动刚离开内部时(保持触摸状态下)
cc.CONTROL_EVENTTYPE_TOUCH_UP_INSIDE     -- 在内部抬起手指(保持触摸状态下)
cc.CONTROL_EVENTTYPE_TOUCH_UP_OUTSIDE    -- 在外部抬起手指(保持触摸状态下)
cc.CONTROL_EVENTTYPE_TOUCH_CANCEL        -- 取消触点时
cc.CONTROL_EVENTTYPE_VALUE_CHANGED       -- 按钮控件中值发生改变时
使用举例:

25
-- node : 执行回调的按钮对象
-- type : 按钮事件的类型
btnCallback(node, type)
if type == cc.CONTROL_EVENTTYPE_TOUCH_DOWN  then
"touch down" )
elseif type == cc.CONTROL_EVENTTYPE_DRAG_INSIDE  then
"drag inside" )
elseif type == cc.CONTROL_EVENTTYPE_TOUCH_UP_INSIDE  then
"touch up inside" )
-- 添加一个按钮 ControlButton
label = cc.Label:createWithSystemFont( "button" sprite = cc.Scale9Sprite: )
btn = cc.ControlButton: (label,sprite)
btn:setPosition(winSize.width/2, winSize.height/2)
self:addChild(btn)
 
-- 按钮事件回调
btn:registerControlEventHandler(btnCallback,cc.CONTROL_EVENTTYPE_TOUCH_DOWN)
6、Lua中的事件分发机制

    在C++中,事件分发机制参见:http://www.voidcn.com/article/p-zwifwspg-wx.html

    事件分发机制包含:

        > 触摸事件     EventListenerTouchOneByOneEventListenerTouchAllAtOnce

        > 鼠标响应事件 EventListenerMouse

        > 键盘响应事件 EventListenerKeyboard

        > 加速计事件   EventListenerAcceleration

        > 自定义事件   EventListenerCustom

        > 物理碰撞事件 EventListenerPhysicsContact

        > 游戏手柄事件 EventListenerController

    而在cocos2dx v3.2版本中,Lua的使用方式与C++有点类似。

    PS:在Lua中对于 鼠标事件、自定义事件 的支持有BUG,建议大家暂时不要去使用。

    另外由于博主还未接触过物理碰撞事件、游戏手柄事件,所以也无法讲解着两个事件机制的使用方法,不过可以确定的一点是:以上几个事件处理都是通过监听器来完成的,所以用法应该都是差不多的。

    在这里我重点讲一下:触摸事件、键盘事件、加速计事件。

    事件处理的原理可以参考C++的使用方法,这里讲一下 Lua 中如何使用。

    

  6.1、使用步骤

    还是继续用代码来讲解吧,一般性都分为以下四个步骤

15
-- 1.获取事件分发器  : EventDispatcher
dispatcher = cc.Director:getInstance():getEventDispatcher()
 
-- 2.创建事件监听器  : EventListener (这里以单点触摸为例)
listener = cc.EventListenerTouchOneByOne: ()
 
-- 3.注册事件响应函数: registerScriptHandler
-- hander : 响应函数
-- type   : 事件类型
listener:registerScriptHandler(hander, type)
 
-- 4.在事件分发器中,添加监听器。事件响应委托为self
6.2、单点触摸事件EventListenerTouchOneByOne

    使用方法如下:

        > 响应函数的两个参数 touch , event 分别表示:

            > touch : cc.Touch 。触点信息

            > event : cc.Event 。事件信息

        > 注册响应函数 registerScriptHandler 中的第二个参数,表示事件类型。

            > cc.Handler.EVENT_TOUCH_BEGAN : 触摸开始

            > cc.Handler.EVENT_TOUCH_MOVED : 触摸移动

            > cc.Handler.EVENT_TOUCH_ENDED : 触摸结束

29
-- 触摸开始
onTouchBegan(touch, event)
"Touch Began" )
pos = touch:getLocation()  -- 获取触点的位置
print(pos.x ..  .. pos.y)   return  true                      -- 必须返回true 后边move end才会被处理
end
 
-- 触摸移动
onTouchMoved(touch, event)
"Touch Moved" )
end
 
-- 触摸结束
onTouchEnded(touch, event)
"Touch Ended" )
end 
 
-- 注册单点触摸
dispatcher = cc.Director:getInstance():getEventDispatcher()
()
 
listener:registerScriptHandler(onTouchBegan, cc.Handler.EVENT_TOUCH_BEGAN)
listener:registerScriptHandler(onTouchMoved, cc.Handler.EVENT_TOUCH_MOVED)
listener:registerScriptHandler(onTouchEnded, cc.Handler.EVENT_TOUCH_ENDED)
 
6.3、多点触摸事件EventListenerTouchAllAtOnce

    touches ,0)">touches : cc.Touch的table数组 。多个触点信息

            > event   cc.Event            。事件信息

        > 注册响应函数 cc.Handler.EVENT_TOUCHES_BEGAN : 多点触摸开始

            > cc.Handler.EVENT_TOUCHES_MOVED : 多点触摸移动

            > cc.Handler.EVENT_TOUCHES_ENDED : 多点触摸结束

相关文章

1.github代码实践源代码是lua脚本语言,下载th之后运行thmai...
此文为搬运帖,原帖地址https://www.cnblogs.com/zwywilliam/...
Rime输入法通过定义lua文件,可以实现获取当前时间日期的功能...
localfunctiongenerate_action(params)localscale_action=cc...
2022年1月11日13:57:45 官方:https://opm.openresty.org/官...
在Lua中的table(表),就像c#中的HashMap(哈希表),key和...