找回密码
 立即注册
查看: 285|回复: 0

lua入门

[复制链接]
发表于 2023-3-19 20:08 | 显示全部楼层 |阅读模式
一、为何要用lua

本章介绍热更新与lua的关系,知道了lua有什么作用才能在之后的学习里更有动力~
1、为何需要热更新

开发者开发游戏时,通常会使用c#或者c++等
体量庞大的语言,因为其功能库多,使用方便,能够构造出复杂的系统。但身为一门编译型语言,编译的过程在移动平台无法完成,运行之前需要通过开发者编译后打包,才能分发给玩家游玩。
假如你开发了一款游戏,刚上架应用市场,BUG反馈铺天盖地。
你改好了BUG后重新打包,上传应用市场。而玩家又得从应用市场将整个游戏重新下载安装。本来就被BUG折磨的玩家望着一个小时的下载时间,果断弃坑。
为了拉高玩家留存率,提升活跃度,让游戏死得不那么快,我们需要一个小巧轻便的更新方式,避开c#的编译。
2、为何热更需要lua

要解释这个问题得先明白编译性语言与脚本语言的区别:

  • 编译性语言

    • 编译性语言在编译后,可脱离环境运行
    • 需要通过虚拟机编译成汇编代码,才能供各个平台执行。随着打包的完成,程序不能进行修改。
    • 写好的代码->编译成.dll扩展程序->平台执行

  • 脚本语言

    • 脚本语言必须安装对应的脚本环境
    • 脚本语言在有虚拟机的情况下,可以直接解释执行。lua代码在运行时才编译,不运行时和文本无异。
    • 写好代码->平台中的虚拟机执行

所以热更新的方式有很多种,编译性语言和脚本语言都可以。
可以把c#代码编译成独立的dll,上传服务器,玩家启动游戏时从服务器上下载dll文件,达到热跟新的目的。但这样的更新容易给系统带来安全隐患,部分系统不允许这样的热更,为了安全起见,不能给程序太强的能力。
这个时候lua就能发挥其优势了,身为脚本语言,lua在运行时才会被动态解释,在没运行时就是一个普通的资源文件。可以很方便的传输,且不容易被平台禁止。
3、lua如何实现热更

前文说到,脚本语言需要在环境内内嵌虚拟机,在游戏运行时动态解析脚本。对于lua的解析,市面上有许多解决的框架,比如tolua、xlua、ulua、slua等等,有了这些框架,就不用担心虚拟机运作的问题,可以很方便的使用lua脚本进行热更新的处理了。
二、lua入门

对为何要使用lua有了一定的了解,接下来是lua的基础使用。鉴于网络上的教程众多,这里只列举lua特性,对其特点进行归纳,做一个简洁的版本。如果需要更系统的学习,可以去菜鸟网学习Lua 教程 | 菜鸟教程 (runoob.com)
1、lua语法

(1)变量定义
lua是弱类型语言,不需要为变量定义数据结构,只需要为变量赋值即可。
按照变量的作用域来划分,lua有三种数据类型:全局变量、局部变量、表中的域。

  • 全局变量:变量默认为全局变量,除非明确声明为局部变量。
  • 局部变量:变量指定类型为local时,其范围约束在函数范围内。
  • 表字段:这是一种特殊类型的变量,可以保存除nil之外的任何内容,包括函数。
function test()
        a = 5                        --全局变量
        local b = 6                --局部变量
end

text()
print(a,b)                        --5,nil
(2)数据类型
lua的变量有8个基本类型:nil、boolean、number、string、userdata、function、thread 和 table,可以通过type()函数查看变量的数据类型。
print(type(nil))                --> nil
print(type("Hello world"))      --> string
print(type(10))                 --> number
print(type(print))              --> function
print(type(true))               --> boolean
local a = {}
print(type(a))                      --> table(3)运算符
算数运算符
运算符描述
+两个操作数相加
-第一个数减去第二个数)
*两个操作数相乘
/两个操作数相除
%取余
^幂运算
-否定/复数
关系运算符
运算符描述
==检查两个操作数是否相等
~=检查两个操作数是否不等
>大于
<小于
>=大于等于
<=小于等于
逻辑运算符
运算符描述
and逻辑与
or逻辑或
not逻辑非
字符串运算符
运算符描述
...链接两个字符串
#返回字符串长度
(4)流程控制
(1)循环
lua提供了三种循环语句while、for、repeat,当然,常用的还是前面两种
while
当condition判断为true时,执行do、end之间的语句
while(condition)
do
   statements
endfor
for var=exp1,exp2,exp3
do  
    statements
end  初始值exp1,结束值exp2,步长exp3(默认为1)
lua也可以通过迭代器进行遍历(图中为ua自带的迭代器函数ipairs)
for k, v in pairs(t) do
    print(k, v)
end(2)分支/判断
if/elseif
lua的判断语句需要在if/elseif后需要加上then,else不需要then。整套判断流程完毕后,在末尾添加end。
a = 0
if(a>10) then
        print("a大于10")
elseif(0>a and 10<a) then
        print("a介于0到10之间")
else
        print("a小于10")
end2、lua组织结构

(1)table表
在lua中,表是一个重要又特殊的一个存在。既能充当数据结构做列表,又能保存数据与方法充当类的功能。
lua就是用table来解决模块(module)、包(package)和对象(object)的。

  • table的构造
table的构造非常简单,通过一对中括号即可完成表的初始化
--初始化表
mytable = {}

  • 赋值取值
表可以通过多种方式赋值取值,lua的表特别自由,一个类型包含了一般语言中列表、字典、类的操作方式,来操作lua表中的数据。
--赋值
mytable.wow = "哇"                --通过“.属性”的方式赋值
mytable["hah"] = "哈"                --通过中括号的方式赋值
mytable[1] = "哈"                --通过索引的方式赋值

--取值
print(mytable.wow)               --通过“.属性”的方式取值
print(mytable["hah"])            --通过列表的方式取值
print(mytable[1])                --通过索引的方式赋值如果没有指定键值对,则会用索引由索引做键,如果指定了键则以指定的值为准。
虽然表提供了很多赋值取值的方法,但是赋值取值之间方法要对应。如果通过“.属性”的方法赋值,则取值的时候也要通过“.属性”的方式取值

  • table中的方法
序号方法用途
1table.concat (table,sep,start,end)连接table,指定table的数组部分从start位置到end位置的所有元素, 元素间以分隔符(sep)隔开。
2table.insert (table, pos,value)在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾.
4table.remove (table , pos)返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起。
5table.sort (table)对table进行升序排序。
(2)模块与包

  • 模块
lua中的模块类似一个封装库,可以以API接口的形式在其他地方调用。模块的创建方式非常简单,创建一个table,并将需要导出的常量、函数放入其中,最后返回这个table
-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}

-- 定义一个常量
module.constant = "这是一个常量"

-- 定义一个函数
function module.func1()
    io.write("这是一个公有函数!\n")
end

--返回moudle
return module

  • require
lua可以通过require函数来加载其他模块,执行 require 后会返回一个由模块常量或函数组成的 table,并且还会定义一个包含该 table 的全局变量。
require("module")

print(module.constant)

module.func1()

  • C包
lua与c结合,c语言写出的模块称之为c包。lua通过loadlib函数链接c包,这个函数需要库的绝对路径与初始化函数。通过返回一个初始化函数作为lua的一个函数,这样就可以在lua文件中调用。
local path = "/usr/local/lua/lib/libluasocket.so"
local f = assert(loadlib(path, "luaopen_socket"))
f()  -- 真正打开库
(3)元表
lua中提供了一种方式,可以让我们改变table的行为——添加一张元表,通过重写元表中的元方法改变表的行为,每种行为都有对应的元方法。
处理元表的两个重要函数:
mytable = {}                          -- 普通表
mymetatable = {}                      -- 元表
setmetatable(mytable,mymetatable)     -- 把 mymetatable 设为 mytable 的元表

getmetatable(mytable)                 --返回元表对象

  • 元函数
__index元方法
Lua 查找一个表元素时的规则,其实就是如下 3 个步骤:

  • 在表中查找,如果找到,返回该元素,找不到则继续
  • 判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。
  • 判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;如果 __index 方法是一个表,则重复 1、2、3;如果 __index 方法是一个函数,则返回该函数的返回值。
该部分内容来自作者寰子:Lua查找表元素过程(元表、__index方法是如何工作的)_lua获取元素位置_寰子的博客-CSDN博客
cup={water=100}
setmetatable(cup,{__index={fire=10}})
print(cup.water)
print(cup.fire)元方法还有很多,感兴趣的读者可以自行搜索捏~
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-23 21:13 , Processed in 0.148413 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表