Lua

什么是脚本

  • 脚本
    纯文本格式的程序。

  • 脚本的执行
    由于脚本是纯文本的,所以CPU无法直接执行脚本程序,而是通过脚本解析器来执行脚本程序。

  • 脚本语言
    一个脚本语言,包含脚本解析器、脚本语言语法

  • 流行的脚本语言
    bash, python, javascript, php, lua, perl....

  • 脚本语言的特点
    优点:简单,在某些特定的领域有特定的用途;缺点:效率底

Lua脚本

Lua定位和脚本的特点

Lua脚本的定位是嵌入到应用程序中,用来拓展应用程序功能的轻量级脚本,因此Lua有如下特点:

  • 小巧
  • 效率高
  • 语法少,库少,简单易学

Lua环境搭建

  • windows环境需要翻墙,或者编译源码,都是蛮复杂的
  • 在ubuntu上虽然方便,但是毕竟是Linux
  • 在线的脚本学习环境最方便,但是对于初学者来说,不利于理解脚本的执行方式
  • 在线Lua Shell:
    http://www.mcqyy.com/RunCode/lua/

最后的总结是:在linux上搭建环境,理解脚本执行的概念
学习语法在在线环境中进行

Lua基本语法

Lua保留字

and break do else elseif end false for function if in local nil not or repeat return then true until while

Lua类型

  • nil
  • boolean
  • number
  • string
  • table
  • function
  • thread
  • userdata

符号

  • 算术运算符
    [+ - * / % ^ -]
  • 关系运算符
    [== ~= < > <= >=]
  • 逻辑运算符
    [and or not]
  • 其他运算符
    [.. #]
  • 其他符号
    [... . :]

语句和执行顺序

  • 注释语句
  • 顺序执行
  • 条件判断
  • 循环

代码块

按照一定条件划分的有意义的代码组合,大的代码块,可以嵌套包含小代码块,这些一定条件可以为:

  • 文件
  • for循环体
  • while循环体
  • if条件分支
  • 函数体等等

变量的作用域

  • 全局变量
    默认变量就是全局变量
  • 局部变量
    局部变量只能在它所在的代码块中被访问

Lua脚本语法注意点汇总

  • 没有continue保留字
  • 定义变量不需要类型,它被赋值成什么它就是什么类型,并且随时可以改变类型
  • number类型包含了整数和浮点数
  • string类型的值只能整体赋值,不能修改其中某个字符
  • string的表达方式很多
  • 表类型其实只是保存表数据的引用,因此当表t1 = t2之后,改变t2,也就改变了t1,改变了t1,也就改变了t2
  • table包含了数组和映射表
  • 除法不像C语言 3/5不是0,而是0.6
  • and和or的操作结果不是boolean类型,而是参与运算的数据类型
  • 在逻辑判断时,0不代表false,只有false和nil代表false
  • 函数可以返回多个值
  • 可以对多个变量进行复制

Lua库函数

基础库函数

  • assert(v [,message])
  • collectgarbage([opt[,arg]])
  • dofile([filename])
  • error(message [, level])
  • _G
  • gefenv([f])
  • getmetatable(object)
  • iparis(t)
  • load(func[, chunkname])
  • loadstring(string, [,chunkname])
  • next(table [, index])
  • pairs(t)
  • pcall(f, arg1, ...)
  • print(...)
  • rawequal(v1, v2)
  • rawget(table, index)
  • rawset(table, index, value)
  • select(index, ...)
  • setfenv(f, table)
  • setmetatable(table, metatable)
  • tonumber(e [,base])
  • tostring(e)
  • type(v)
  • unpack(list[, i[,j]])
  • _VERSION
  • xpcall(f, err)

table库函数

  • table.concat(t [,sep,[,i[,j]]])
  • table.insert(t, [pos,] value)
  • table.maxn(t)
  • table.remove(t [,pos])
  • table.sort(t [,comp])

string库函数

  • string.byte[s [,i [,j]]])
  • string.char(...)
  • string.dump(function)
  • string.find(s, pattern[, init[,plain]])
  • string.format(formatString, ...)
  • string.gmatch(s, pattern)
  • string.gsub(s pattern, repl[,n])
  • string.len(s)
  • string.lower(s)
  • string.match(s, patterns[,init])
  • string.rep(s, n)
  • string.reverse(s)
  • string.sub(s, i [,j])
  • string.upper(s)

math库函数

  • math.abs(x)
  • math.acos(x)
  • math.asin(x)
  • math.atan(x)
  • math.atan2(y, x)
  • math.ceil(x)
  • math.cos(x)
  • math.cosh(x)
  • math.deg(x)
  • math.exp(x)
  • math.floor(x)
  • math.fmod(x, y)
  • math.frexp(x)
  • math.huge
  • math.ldexp(m, e)
  • math.log(x)
  • math.log10(x)
  • math.max(x, ...)
  • math.min(x, ...)
  • math.modf(x)
  • math.pi
  • math.pow(x, y)
  • math.rad(x)
  • math.random([m, [,n])
  • math.randomseed(x)
  • math.sin(x)
  • math.sinh(x)
  • math.sqrt(x)
  • math.tan(x)
  • math.tanh(x)

io库函数

  • io.close([file])
  • io.flush()
  • io.input([file])
  • io.lines([filename])
  • io.open([filename [,mode]])
  • io.output([file])
  • io.read(...)
  • io.tmpfile()
  • io.type(obj)
  • io.write(...)

file对象函数

  • file:close()
  • file:flush()
  • file:lines()
  • file:read([format])
  • file:seek([whence] [,offset])
  • file:setvbuf(mode, [,size])
  • file:write(...)

os库函数

  • os.clock()
  • os.date([format[,time]])
  • os.difftime(t2, t1)
  • os.execute([command])
  • os.exit()
  • os.getenv(varname)
  • os.remove(filename)
  • os.rename(oldname, newname)
  • os.setlocale(locale [,category])
  • os.time([table])
  • os.tmpname()

  • 数组
  • Map
  • 混合
  • 添加元素
  • 表的操作:遍历

元表

  • 元数据(metadata)是指描述数据的数据,因此元表就是指描述数据的表。
  • 在Lua中,每个数据都可以有一个表描述它,这个表,可以通过getmetatable来获取
  • 这个表规定了这个数据的一些操作,比如相加,相减等等的操作
  • 只有表这种类型的数据才可以修改元表,因此这里只讨论表的元表,修改元表的函数是setmetatable
  • 元表的可以设置metatable来实现加法
local t = {1, 2}
local s = {3, 4}

local function add(a, b)
    local result = {}
    for k, v in pairs(a) do 
        table.insert(result, v)
    end
    for k, v in pairs(b) do
        table.insert(result, v)
    end
    return result
end

local metaTable = 
{
    __add = add
}

setmetatable(t, metaTable)

local x = t + s

for k, v in pairs(x) do
    print(k, v)    
end
  • 元表的固有元素
    __add(a, b) --加法
    __sub(a, b) --减法
    __mul(a, b) --乘法
    __div(a, b) --除法
    __mod(a, b) --取模
    __pow(a, b) --乘幂
    __unm(a) --相反数
    __concat(a, b) --连接
    __len(a) --长度
    __eq(a, b) --相等
    __lt(a, b) --小于
    __le(a, b) --小于等于
    __index(a, b) --索引查询
    __newindex(a, b, c) --索引更新
    __call(a, ...) --执行方法调用
    __tostring(a) --字符串输出
    __metatable --保护元表

Lua面向对象

Lua面向对象和C++不同,类和对象都是表

在表中定义函数

调用表中定义的函数(. :)

定义一个类

产生一个对象

类的抽象

cocos2dx与Lua的关系

使用Lua编写的cocos2dx程序,由三部分组成,一部分是C++部分编译的cocos2dx引擎库,一部分是Lua解析器,一部分是Lua脚本

C++与Lua之间的相互调用

#include <lua.h>
#include <lualib.h>
#include <luaxlib.h>

int cppFunctionForLua(lua_State* lua)
{
    int n = lua_gettop(lua);
    for(int i=1; i<=n; ++i)
    {
        printf(“arg %d is %s\n”, i, lua_tostring(lua, i));
    }
    lua_pushnumber(lua, “this is return result”);
    return 1;
}

void callLuaFunc(lua_State* lua, int x, int y)
{
    lua_getglobal(lua, “luaFunction”);
    lua_pushnumber(lua, x);
    lua_pushnumber(lua, y);
    lua_call(lua, 2, 1);
    int ret = (int)lua_tonumber(lua, -1);
    lua_pop(lua, 1);
}

int main(int argc, char* argv[])
{
    lua_State* lua = lua_open();
    luaL_openlibs(lua);
    lua_register(lua, “cppFunctionForLua”, cppFunctionForLua);
    luaL_dofile(lua, “luaScript.lua”);

    callLuaFunc();

    lua_close(lua);
    return 0;
}

cocos2dx的Lua接口

  • 创建节点对象
    node = cc.Node:create()

  • 格式化字符串
    string.format(“hero_%d.png”, i);
    或者直接连接
    a = “hero_” .. i .. “.png"

  • 枚举常量,类似只举例一个
    cc.ResolutionPolicy.EXACT_FIT
    屏幕适配
    cc.KeyCode.KEY_A
    键盘
    cc.CONTROL_EVENTTYPE_TOUCH_DOWN
    Control的EventType
    cc.CONTROL_STATE_NORMAL
    Control的控件状态
    cc.EDITBOX_INPUT_MODE_ANY
    EditBox的输入模式
    cc.EDITBOX_INPUT_FLAG_PASSWORD
    EditBox的文本框类型
    cc.EDITBOX_RETURNTYPE_GO
    EditBox的Return显示
    cc.SCROLLVIEW_DIRECTION_BOTH
    ScrollView的滚动方向
    cc.TABLEVIEW_FILL_TOPDOWN
    TableView的列表视图排列方式
    cc.PROGRESS_TIMER_TYPE_BAR
    ProgressTimer的类型
    cc.POSITION_TYPE_FREE
    粒子位置模式
    cc.PARTICLE_MODE_RADIUS
    粒子发射器类型
    cc.TRANSITION_ORIENTATION_UP_OVER
    场景切换方向
    cc.VERTICAL_TEXT_ALIGNMENT_TOP
    文本竖直对齐方式
    cc.TEXT_ALIGNMENT_LEFT
    文本水平对齐方式

  • callFunc
local function callback(node, tab)  — tab是一个表
 
end

local sprite = cc.Sprite:create();
local call = cc.CallFunc:create(callback, {x=1, y=2})
sprite:runAction(call)
  • schedule
local timerEntry = nil
local scheduler = nil
local function update(dt)
    scheduler:unscheduleScriptEntry(timerEntry)
end

scheduler = cc.Director:getInstance():getScheduler()
timerEntry = scheduler:scheduleScriptFunc(update, 0, false)
  • MenuItem
local menu = nil
local normal = nil
local hard = nil

local function menuCallback(tag, menuItem)

end

normal = cc.MenuItemImage(“normal.png”, “normal.png”)
normal:setTag(1)

hard = cc.MenuItemImage(“hard.png”, “hard.png”)
hard:setTag(2)

menu = cc.Menu:create(normal, hard)   — 没有nil结尾

normal:registerScriptTapHandler(menuCallback)
hard:registerScriptTapHandler(menuCallback)
  • Control
local function btnCallback(node, type)
    if type == cc.CONTROL_EVENTTYPE_TOUCH_DOWN then
        --do something;
     end
end

local label = cc.Label:createWithSystemFont(“button”, “Arial”, 30)
local sprite = cc.Scale9Sprite(“normal.png”)
local btn = cc.ControlButton:create(label, sprite)

btn:registerControlEventHandler(btnCallback, cc.CONTROL_EVENTTYPE_TOUCH_DOWN)
btn:registerControlEventHandler(btnCallback, cc.CONTROL_EVENTTYPE_DRAG_INSIDE)
  • EventListener
local function onTouchBegan(touch, event)
    print(“Touch began”)
    local pos = touch:getLocation()
    print(pos.x .. “,” .. pos.y)
    return true
end

local function onTouchMoved(touch, event)
end

local function onTouchEnded(touch, event)
end

local dispatcher = cc.Director:getInstance():getEventDispatcher()
local listener = cc.EventListenerTouchOneByOne:create()

listener:registerScriptHandler(onTouchBegan, cc.Handler.EVENT_TOUCH_BEGAN)
listener:registerScriptHandler(onTouchMoved, cc.Handler.EVENT_TOUCH_MOVED)
listener:registerScriptHandler(onTouchEnded, cc.Handler.EVENT_TOUCH_ENDED)

dispathcher:addEventListenerWithSceneGraphPriority(listener, node)
  • Point, Size, Rect
    cc.p(x, y)
    cc.size(width, height)
    cc.rect(x, y, width, height)

  • 坐标运算
    cc.pIsSegmentIntersect(ptA, ptB, ptC, ptD)
    cc.pIsLineIntersect(ptA, ptB, ptC, ptD, float, float)
    cc.pAdd(pt1, pt2)
    cc.pSub(pt1, pt2)
    cc.pMidPoint(pt1, pt2)
    cc.pNormalize(p1)
    cc.pGetClampPoint(minPt, maxPt, p)
    cc.pForAngle(angle) — return cc.p(cos(angle), sin(angle))
    cc.pPerp(p) — return (-y, x)
    cc.rPerp(p) —return (y, -x)
    cc.pGetIntersectPoint(pA, pB, pC, pD) — 获取相交点

  • 矩形运算
    cc.rectGetMinX(rect)
    cc.rectGetMidX(rect)
    cc.rectGetMaxX(rect)
    cc.rectGetMinY(rect)
    cc.rectGetMidY(rect)
    cc.rectGetMaxY(rect)
    cc.rectEqualRect(rect1, rect2)
    cc.rectContainsPoint(rect, point)
    cc.rectIntersectsRect(rect1, rect2)
    cc.rectUnion(rect1, rect2)

  • Color
    cc.c3b(r, g, b)
    cc.c4b(r, g, b, a) — r, g, b, in [0, 255]
    cc.c4f(r, g, b, a) — r, g, b, a in [0, 1]

  • onEnter onExit
local function onEnter()
end

local function onExit()
end

local function nodeEvent(event)
    if event == “exit” then
        onExit()
    elseif event == “onter” then
        onEnter()
    end
end

node:registerScriptHandler(nodeEvent)

标签: none

仅有一条评论

  1. SZ03-陈苇东 SZ03-陈苇东

    薛老师,谢谢你这篇博文,是它带我入lua门的(会撸又会哇)
    刚刚进公司的时候,还害怕学不动,还好有这个博文!!!谢谢 谢谢!!

添加新评论