lua在魔兽争霸编辑中的使用



2.如何初始化一个lua脚本


lua在魔兽争霸编辑中的使用_第1张图片

通过 Cheat 函数来调用lua脚本
如图所示,执行地图中导入的 test.lua 脚本
已改为: execlua:test
  • 3.如何写lua脚本
    有2种办法:用其他工具写好了导入到地图中/在编辑器里写
    这里只介绍第二种



    如图所示,在脚本的任意位置写下这样的格式遍可以自动往地图中导入名为"test.lua"的文件,文件内容即为 [[]] 括起来的部分
      应该是三种,1.27+的ydwe支持从本地硬盘上导入lua脚本文件。并且import本身就是一个lua函数,对lua熟悉的童靴可以编写自己的导入函数,比如导入一个文件夹内的所有lua脚本。
  • 建议使用 的形式,等号数量前后一致就行,这样就可以和脚本中的 [[ ]] 进行区分以免冲突
    4.建立第一个lua文件
    lua在魔兽争霸编辑中的使用_第2张图片

    在第一个文件中,我建议你只写以下代码


    jass_ext.EnableConsole()

    setmetatable(_G, {__index = getmetatable(jass).__index})


    第一句的作用是打开一个cmd窗口,这样你的其他脚本有错误话会提示你


    第二句代码如果不写的话你得用 jass.SetUnitState(jass.GetTriggerUnit(), jass.UNIT_STATE_LIFE, 0) 来写代码,写了以后"jass."就可以都省略掉了


      _G是5.1的旧写法,有可能在未来lua版本中被移除,请使用_ENV代替
    之后你可以在jass中用Cheat函数来运行其他lua脚本,你也可以在lua中通过
    require "another.lua"
    来运行其他lua脚本


    注意这样运行的话每个脚本只能运行一次,如果你之前运行过"another.lua",那么之后的require "another.lua"就不会执行了

    5.lua的基本介绍
    lua是一个简单,高效,强大的脚本语言,其语法和jass有很多相似之处,因此有jass基础的话可以很快掌握lua


    lua和jass最大的不同在于lua不需要写变量类型,例:


    local a = 1
    if a == 1 then
    a = "等于1"
    end


    这个例子中a分别是数字(number)和字符串(string)


    lua有以下几个类型
    nil --空值,任何变量在复制前都是nil,类似于jass的null
    boolean --布尔值,和jass一样包括true和false
    number --数字,jass中的real和integer在lua中统一为number,因此在lua中 5/2 == 2.5
    string --字符串,和jass中的string基本相同
    function --函数,和jass不同的是lua中函数是一个变量,你随时可以把一个函数赋值给另一个变量,或传递给另一个函数做参数
    userdata --自定义数据,你可以理解为jass中的handle,lua无法直接对其进行操作
    table类型呢……thread应该不能用。:table漏了...thread会和GetTriggerUnit什么不兼容所以不介绍了,acb正在写新的协同线程
    lua有以下保留字
    and break do else elseif
    end false for function if
    in local nil not or
    repeat return then true until
    while

    6.变量
    lua对变量进行操作时不需要set 关键字
    lua使用全局变量无须事先声明,任何时候
    a = 10
    都是有效的.在a被复制前,如果去获取a的类型将返回"nil"


    局部变量的声明方式类似于jass:
    local a = 10


    记住,lua不需要写变量类型哦


    补充一下
    对于 if a then 这样的判定,当a为nil或false时不成立,其他包括0与""在内都是成立的


    lua中字符串连接符是 .. 而不是 + ,原因很简单:
    1 + 2 = 3
    1 .. 2 = "12"

    7.表达式
    jass中的 != 在lua中写为 ~= ,其他加减乘除 括号 比较 and or 都一样
    此外lua还自带了取余(%)和幂(^)
    5%2 = 1
    2^3 = 8

    8.关于数字和字符串的一些特殊写法


    lua和jass一样都支持 0x前缀的16进制数字,但是jass中 '' 表示的256进制数字符号在lua中要改为 || (注:这是acb加入的村规,lua并不自带256进制)


    lua的字符串符号有3个,分别是 "" '' 和 [[ ]]
    不过最后一个和YDWE有点冲突请不要使用(如果你是在外面写脚本然后导入地图可以无视)

    9.数据结构
    抛弃掉jass的哈希表吧


    lua只有一种数据结构:table(表)


    t = {} --将一张新建的表赋值给变量t
    t[1] = 10
    t[2] = 20 --当数组用


    t.x = 50
    t.y = 100 --当哈希表用


    任何非nil的值都可以当做索引,例如
    t["呜喵"] = "wumiao"
    t[GetTriggerUnit()] = "厉害" --这里做索引的是一个单位,你可以抛弃GetHandleId了


    你可以在新建的时候直接定义数组内容,例:
    t = {
    10, --10赋值给t[1]
    x = 50, --50赋值给t.x
    y = 100, --100赋值给t.y
    20 --20赋值给t[2]
    }


    注意这样写的话,数据之间要加上一个逗号


    table可以进行多层嵌套,例如
    t = {}
    t[1] = {}
    t[1][2] = {}
    t[1][2][3] = "呜喵"


    lua在魔兽争霸编辑中的使用_第3张图片

    10.函数
    函数的内容比较多,我得分成好几段...


    函数声明:
    lua的函数声明有2种:
    function func(a, b, c)
    end


    func = function(a, b, c)
    end


    这2种方法是等价的,都是声明了一个名为"func",参数为a b c 的函数
    显然,参数不需要写类型,也不需要写返回类型.endfunction改为end即可


    在lua中函数是一个变量,这在第二种声明方式中得以显现.你可以随时将他赋值给另一个值,例如
    R2I = math.floor --后者是lua自带的取整函数
    这样你以后写 R2I(11.2) 就完全等价于 math.floor(11.2)


    既然是变量,那么他就可以局部化:
    local function func(a, b, c)
    end


    local func = function(a, b, c)
    end


    这样外部就调用不到这个func了


    函数定义还有一种形式 function point:get_x() return self.x end,这也是一个语法糖。和function point.get_x(self) return self.x end的写法是完全等价的
    函数的调用


    与jass不同,lua调用函数不需要写 call
    以上面注册的函数为例,我只需要
    func(1, 2, 3)
    即可调用这个函数


    lua调用函数没有顺序限制,只要func已经被赋值了函数就能调用,即使他赋值的函数是在之后定义的


    lua也不限定你的参数,如果你写成
    func(1, 2)
    也依然可以正常调用func函数,只是该函数的参数c将为nil


    lua也不限定你的返回值,你可以这样声明函数:
    func = function(a)
    if a == 1 then
    return 1
    elseif a == 2 then
    return "呜喵"
    elseif a == 3 then
    return true
    elseif a == 4 then
    return {50, 100}
    end
    end


    此时如果你
    local r = func(0)
    r的值就是nil


    lua还支持多返回值:
    GetXY = function(u)
    return GetUnitX(u), GetUnitY(u)
    end


    local x, y, z = GetXY(u) → x = 0, y = 0, z = nil

    函数的特殊调用
    当函数只有一个字符串或表参数,且不是变量时,可以省掉括号
    例如之前的例子:
    require "another.lua"
    其实是
    require("another.lua")
    的缩写


    还有个很常用的写法是
    func = function(data)
    SetUnitState(data.unit, data.state, GetUnitState(data.unit, data.state) + data.plus)
    end


    func{
    unit = GetTriggerUnit(),
    state = UNIT_STATE_LIFE,
    plus = 100
    }
    这个例子中,我将参数全部保存在一个表中,然后将整个表作为一个参数传递给函数.

    闭包
    当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量,这种特征我们称作词法定界。虽然这看起来很清楚,事实并非如此,词法定界加上第一类函数在编程语言里是一个功能强大的概念,很少语言提供这种支持。


    ↑↑我反正是看着眼花,直接上演示:


    lua在魔兽争霸编辑中的使用_第4张图片

    很显然,这个函数的实现方式是开了个1秒的循环计时器
    需要注意的是,我直接在本该传入code参数的位置写了个性的函数在上面(这个函数无需命名,称为匿名函数)
    这个匿名函数可以正确调用到父函数"heal"的参数以及其声明的局部变量


    嗯,这个就叫做闭包


    看下面一个例子:
    lua在魔兽争霸编辑中的使用_第5张图片

    这里我将一个函数作为一个参数传递给了test,然后在1秒后运行了这个函数.思考一下,运行后,cmd窗口上将显示几呢?(print函数即为在cmd窗口上显示内容)


    11.条件与循环
    嗯..应该在函数之前讲的说...


    条件语句与jass基本相同,只需要将endif改成end即可,可以看16楼函数返回值的例子


    lua中有3种循环方式
    1.for 循环
    最常用的循环方式


    for i = 1, 10, 2 do
    print(i)
    end


    cmd窗口中将显示"1 3 5 7 9"
    例子中的 1 10 2 分别代表 开始 结束 步长
    这里的 i 是自动声明的局部变量
    如果步长是1,那么可以省略不写,例如


    for i = 1, 5 do
    print(i)
    end


    显示"1 2 3 4 5"


    要注意的是,你不能通过修改i的值来临时更改循环,你可以理解为
    forLoop(1, 5,
    function(i)
    print(i)
    end
    )


    2.while 循环
    当条件成立时进行循环


    local i = 1
    while i <= 5 do
    print(i)
    i = i + 1
    end


    如果你要手动修改i来控制循环,可以使用while


    3.repeat 循环
    至少我没用过


    local i = 1
    repeat
    print(i)
    i = i + 1
    until i >= 5


    你可以使用break来提前退出一个循环,常见的写法有
    local i = 1
    while true do
    print(i)
    i = i + 1
    if i >= 5 then
    break
    end
    end


    需要注意的是,break与return必须写在一段代码的最后面,身后紧靠着end,elseif之类
    如果你必须要在代码中间使用,请写成 do break end(do return end)

    12.对表的操作
    通过前面的学习我们可以直到,与jass的"某个变量是数组"不同,lua中"某个变量的值是表".因此这个表可以重新赋值给别的变量或当做参数


    lua自带了许多table相关的函数,你可以完全用table来取代group


    例:
    t = {10, 9, 8, 7, 6 , a = "呜喵", b = "喵呜", c = true}


    这个表分为2个部分,数组与哈希表
    我们可以通过 #t 来获取数组的长度(5)


    for i = 1, #t do
    print(i .. " = " .. t[i])
    end


    这是遍历数组的一个简单的方式
    lua还提供了一种遍历数组的方式:


    for i, v in ipairs(t) do
    print(i .. " = " .. v)
    end


    这里的i 与 v都是局部变量


    此外lua还提供一个遍历表中所有值的方式:


    for i, v in pairs(t) do
    print(i .. " = " .. v)
    end


    除了数组部分,可以将哈希表部分也都遍历出来,并将对应的索引放在i中,值放在v中
    不过要注意的时,虽然这样遍历时依然会先按照顺序遍历出数组部分,但之后的哈希表部分的遍历顺序是随机的,与你储存时的顺序是没有关系的哦


    lua还提供了2个常用的插入/拔出...好吧删除功能
    table.insert(t, 3, 20)
    将20插入到t[3]上,之前从[3]开始的数据都会被挤得往后挪一个位置


    table.remove(t, 3)
    将t[3]删除,同时之后的数据都会往前挪一个位置填补空缺


    如果你不填位置,那么将默认在数组的尾端上操作:
    table.insert(t, 20) == t[#t + 1] = 20
    table.remove(t) == t[#t] = nil

    13.面向对象
    面向对象是区别于面向过程的编程方式
    jass使用者应该对面向过程很清楚-----你平时写的就是面向过程


    一个简单的例子:
    lua在魔兽争霸编辑中的使用_第6张图片

    我使用了一张表保存了一个单位,以及其一些数据,此外还在里面保存了一个函数,这个函数的作用就是删除这个单位


    之后,我只需要使用 hero:remove 即可调用到这个函数,从而删除hero里记录的单位


    注意这个函数的调用的方式,hero与remove之间有一个冒号,代表调用hero的成员函数.如果你不能理解,你只要知道


    hero:remove() 完全等价于 hero.remove(hero)


    我们还可以在表的外面添加一个成员函数
    lua在魔兽争霸编辑中的使用_第7张图片

    这2种声明方式是等价的,当然你也可以使用
    function hero:resethpmp(hp, mp)
    来添加函数,效果是一样的


    相对的,调用方式则为
    hero.resethpmp(hero, 0, 0)
    或者
    hero:resethpmp(0, 0)


    面向对象的好处在于,你可以把一系列的数据当做一个整体来处理,当你调用其中的一个函数时,这个函数可以获得这个整体的信息


    看不懂的话看这句


    如果说RemoveUnit(hero.unit)是找一把武器来杀死这个单位,那么hero:remove()就是按下这个单位身上的自爆按钮


    14.重载函数
    重载函数这个名字很好听,但说白了就是给函数重新赋值罢了...


    例子:
    lua在魔兽争霸编辑中的使用_第8张图片

    首先我将KillUnit保存在局部变量中,然后重新赋值了KillUnit:
    如果单位不是"最萌小汐"才能执行杀死动作


    由于lua的函数都是动态的,因此我们可以只在需要的时候进行重载.当你不再需要这个判断的时候,只需一句


    KillUnit = oldKillUnit


    即可取消重载


    在lua中,不再使用的lua数据会被自动回收,这就包括的table
    我们可以利用table来重载location相关的函数,例如:


    lua在魔兽争霸编辑中的使用_第9张图片

    这样你便可以放心大胆的使用location,完全无需担忧泄露问题


    15.重载操作符
    我们定义2个三维向量


    a = {10, 20, 0}
    b = {20, 30, 90}


    我们希望通过相加的方式来获得一个新的三维向量,但直接写 a + b 是错误的,因为lua并没有定义过表的相加方式


    不过我们可以定义


    我们可以使用setmetatable这个函数来为一个表添加一个元表,当table执行一些操作时,lua会去元表中寻找这个操作的定义方式


    lua在魔兽争霸编辑中的使用_第10张图片



    这里的mt就是一个a和b的元表
    我们现在需要定义的是加法操作,其名称为: __add






    之后我们可以通过
    c = a + b
    来获取a和b相加后的三维向量c


    具体的流程如下:
    当lua执行a + b时,检查出a的类型的table,于是打开它的元表mt,寻找加法操作__add.在这里lua很顺利的找到了mt.__add,于是执行了mt.__add(a, b),并将返回值赋值给了c.如果元表不存在,或原表中没有__add函数,lua将抛出错误


    __add 加法 +
    __sub 减法 -
    __mul 乘法 *
    __div 除法 /
    __unm 负值 -(符号)
    __pow 幂 ^
    __mod 取模 %
    __concat 链接 ..

    16.表的继承
    除了操作符外,读取与新建表不存在的数据也可以进行重载,其关键字分别为__index与__newindex,同样也是通过元表(setmetatable)来实现的


    例子:
    lua在魔兽争霸编辑中的使用_第11张图片

    这里我定义了一个单位,他的数据包括hp和mp,然后我定义了一个英雄,既然是英雄那么他就要有三维,但同时他也要有单位的数据


    在这里,我通过元表mt将__index赋值为了unit,这样当你获取hero.hp时将会返回100.流程如下:
    试图获取hero.hp,但是hero里没有hp的定义,打开元表mt,成功找到了__index,他的值是另一张表unit,于是便到unit中寻找hp,成功找到了100,将其返回


    在这个例子中,我将__index赋值为了一张表.不过他也可以赋值为函数,进行逻辑操作


    例子:
    lua在魔兽争霸编辑中的使用_第12张图片

    此时print(t[10]) 的结果是89


    __newindex的例子:


    lua在魔兽争霸编辑中的使用_第13张图片

    如果你试图 unit.str = 15,那么就会赋值失败并显示错误


    同样__newindex 也接受table做参数,例如前面的例子中我可以 hero.hp = 200,通过__newindex我可以实现让hero继承的unit来进行unit.hp = 200

    嗯...想不到还有什么比较简单的东西能讲了...
    https://github.com/actboy168/jass2lua/blob/master/lua-engine.md


lua引擎的使用教程

你可能感兴趣的:(lua在魔兽争霸编辑中的使用)