ok,我们上一篇中已经了解一大堆玩意了,不过还是冰山一角,那么今天学学循环和if else语句吧

如果你学过其他语言,绝对 对循环有回家一样的亲切感,同样的,什么for循环,while循环,do …while循环在lua中也是一样的

而且if else你绝对老熟悉了

前面我们挖了一个坑(就是数组的遍历部分),接下来可以讲讲了

没学过的小伙伴可以看一下定义:

循环是程序中用于重复执行某段代码(循环体)的控制结构,它包含一个条件判断和要重复执行的循环体,直到条件不再满足时终止。

一组被重复执行的语句称之为循环体

我们可以画一个图

image-20251224112935808

while循环

格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
while 判断条件 do
循环体
改变条件
end

--或者
while (判断条件) do
循环体
改变条件
end

--或者
while 判断条件
do
循环体
改变条件
end

--或者
while (判断条件)
do
循环体
改变条件
end

你可以把do…end想像为其他语言中的花括号{ },而判断条件里的括号可写可不写 这一点和python和gdscript很像

这里我用C#里的你可以对比一下

1
2
3
4
5
6
 //while 循环执行 
while (a < 20)
{
Console.WriteLine("a 的值: {0}", a);
a++;
}

while 循环语句在判断条件为 true 时会重复执行循环体语句

1
2
3
4
5
6
7
8
9
local cookies = 20 -- 罐子里的饼干数量

while (cookies > 0) do
print("爱丽丝拿了一块饼干 🍪")
cookies = cookies - 1
print("罐子里还剩"..cookies.."块")
end

print("罐子空了,爱丽丝溜了!")

image-20251224114117462

对了,while还可以制造无限循环

1
2
3
4
while( true )
do
print("爱丽丝一直偷吃饼干")
end

image-20251224185015296

什么,你说while无限循环除了让电脑死机还有什么用,请看Unity的Update和FixedUpdate方法的本质:

image-20251224192211585

image-20251224192529730

可以看到,这两个unity脚本离不开的核心函数都是无限调用,估计 love2d 中也有类似的函数

for 循环

for 循环语句可以重复执行指定语句,重复次数可在 for 语句中控制,刚才的while循环的循环次数是不受控制的,只有不满足条件时才会跳出循环

对了,lua里面没有a++,++a,a–,–a这种写法, 或者a+=1 a-=1这种写法, 只能写成a=a+1 或者a=a-1

格式:

1
2
3
for 局部变量名=循环起始值,循环结束值,循环步长 do  
循环体
end

同样可以参考一下C#的

1
2
3
4
for (int a = 10; a < 20; a++)
{
Console.WriteLine("a 的值: {0}",a);
}

我们用代码来讲更好理解一些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
local cookies = 20

--条件为 i = 1, cookies ,循环步长不写的话默认为1约等于其他语言里的 i++
--lua默认循环条件里的变量为local局部变量,仅循环内部可用
for i = 1, cookies do
print("爱丽丝第" .. i .. "次拿饼干 🍪")
cookies = cookies - 1
end


if cookies ~= 0 then
print("罐子里还有" .. cookies .. "个饼干,爱丽丝还能继续吃!!!")
else
print("罐子空了,爱丽丝溜了,小桃小绿回来后很生气!!!")
end

image-20251224200846230

我们可以改一下条件

1
2
3
4
5
6
7
8
9
10
11
12
13
local cookies = 20
--条件为 i = 6, cookies
for i = 6, cookies do
print("爱丽丝第" .. i .. "次拿饼干 🍪")
cookies = cookies - 1
end


if cookies ~= 0 then
print("罐子里还有" .. cookies .. "个饼干,爱丽丝还能继续吃!!!")
else
print("罐子空了,爱丽丝溜了,小桃小绿回来后很生气!!!")
end

image-20251224201338756

我们还可以验证一下循环步长的作用,这个不写的话默认为 1

1
2
3
4
5
6
7
8
9
10
11
12
13
local cookies = 20
--条件我们设置为i = 1, cookies, 2 循环步长为 2
for i = 1, cookies, 2 do
print("爱丽丝第" .. i .. "次拿饼干 🍪")
cookies = cookies - 1
end


if cookies ~= 0 then
print("罐子里还有" .. cookies .. "个饼干,爱丽丝还能继续吃!!!")
else
print("罐子空了,爱丽丝溜了,小桃小绿回来后很生气!!!")
end

image-20251224202536414

​ 还可以将饼干减少的逻辑封装到函数里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
local cookies = 20

function EatCookies(number)
number = number - 1
return number
end

for i = 1, cookies do
print("爱丽丝第" .. i .. "次拿饼干 🍪")
cookies = EatCookies(cookies)
end

if cookies ~= 0 then
print("罐子里还有" .. cookies .. "个饼干,爱丽丝还能继续吃!!!")
else
print("罐子空了,爱丽丝溜了,小桃小绿回来后很生气!!!")
end

image-20251224204337238

好了,接下来把之前挖的坑填上———表的遍历学过其他语言的数组的小伙伴通常会用for循环来遍历数组,我们lua也是一般使用for循环

这里的lua的遍历分为三种:

ipairs遍历

第一种: ``ipairs —— 顺序数组遍历

格式(缩写版,推荐):

1
2
3
4
5
local 表名 = {....}

for i, v in ipairs(表名) do
print(i, v)
end

完整版

1
2
3
4
5
local 表名 = {....}

for index, value in ipairs(表名) do
print(index, value)
end

这种遍历属于有序遍历,即从前到后, i 的值默认为1 不可更改

而且遍历的时候如果遇到 nil(即遇到空值断层) 后会停止遍历,而且遍历时遇到键值对会自动跳过

iv 是循环过程中“每一轮自动赋值的两个局部变量”

  • i = 当前元素的索引(key)
  • v = 当前元素的值(value)
1
2
3
4
5
6
7
8
9
10
11
local cookies = { "奶龙", "贝利亚", "丰川祥子", "千早爱音", "橘雪莉" }

print("唐朝最唐生物排名:")

for i, v in ipairs(cookies) do
print(i, v)
end

for i, v in ipairs(cookies) do
print(i .. v)
end

image-20251224234616575

pairs遍历

第二种: ``pairs —— 通用遍历

这个格式和 ipairs一样:

1
2
3
4
5
local 表名 = {....}

for i, v in pairs(表名) do
print(i, v)
end

完整版

1
2
3
4
5
local 表名 = {....}

for index, value in ipairs(表名) do
print(index, value)
end

这种可以遍历 table 中所有键值对(无论是数组还是字典),但是遍历的顺序是无序的,而且不同于ipairs的是,pairs遇到nil时不会停止,而是直接跳过索引对应的空值

image-20251229201435729

可以看到这是没有顺序的遍历

for循环遍历

这个其实也可以采用原生的for循环遍历,不过这个for循环只支持数组,不支持字典

和其他语言中用for遍历数组的方式是差不多的

格式:

1
2
3
4
5
local 表名 = {....}

for i=1, #表名 do
print(i, 表名[i])
end

其实就是for循环,这里就用一个例子来解释吧,我们可以变相来遍历字典实现顺序遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
local cookies = {
order = {
"tang_01",
"tang_02",
"tang_03",
"tang_04",
"tang_05",
},
data = {
tang_01 = "奶龙",
tang_02 = "贝利亚",
tang_03 = "丰川祥子",
tang_04 = "千早爱音",
tang_05 = "橘雪莉"
}
}

for i = 1, #cookies.order do
local key = cookies.order[i]
print(i, cookies.data[key])
end

image-20251229202822255

repeat … until 循环

这个非常有意思

学过其他语言比如C C++ C#这些绝对知道 do … while循环

但是我们可以看一下 do … while循环的特性

1
2
3
4
5
6
do {
// 先执行
// 代码语句
} while (condition);
// 条件condition为 true 时循环继续
// do while是先执行后判断条件,所以至少执行一次代码语句

但是看看我们的Lua就是相反的

1
2
3
4
5
6
repeat
-- 先执行
--代码语句
until condition
-- 条件condition为 true 时循环结束
-- repeat until也是先执行后判断条件,所以至少执行一次代码语句

我们可以看看代码

1
2
3
4
5
6
7
8
9
10
11
local cookies = 10

repeat
print("饼干还剩:" .. cookies .. "个")

cookies = cookies - 1

if cookies == 0 then
print("爱丽丝吃完了所有的饼干!")
end
until (cookies <= 0)

image-20251229230525588

我们修改一下条件语句

1
2
3
4
5
6
7
8
9
10
local cookies = 10

repeat
cookies = cookies - 1
print("饼干还剩:" .. cookies .. "个")

if cookies == 0 then
print("爱丽丝吃完了所有的饼干!")
end
until (cookies <= 0)

image-20251229230749486

循环嵌套

哦,对了,和其他语言一样,循环是可以嵌套的,一些学过其他语言的小伙伴估计已经掌握了冒泡排序,插入排序这些了….吧?

这里就随便讲讲几种方式吧

1
2
3
4
5
for i = 1, 3 do
for j = 1, 4 do
print(string.format("我是外层第%d次循环的第%d个", i, j))
end
end

image-20260128222809112

1
2
3
4
5
6
7
8
9
10
11
local i = 1

while i <= 3 do
local j = 1
while j <= 2 do
print(string.format("我是外层第%d次循环的第%d个", i, j))
j = j + 1
end

i = i + 1
end

image-20260128223129902

1
2
3
4
5
6
7
for i = 1, 3 do
local j = 1
while j <= 2 do
print("这是第 " .. i .. " 行,第 " .. j .. " 列")
j = j + 1
end
end

image-20260128223500029

当然还有repeat 的嵌套,不过这里不讲太多了,以后具体场景用到再说,包括那些排序算法什么的也是,现在学这些东西反正也用不上而且你们估计和我一样睡一觉起来大脑格式化了 狗头

break关键字

这个和其他语言里的break一模一样,break 用于立即终止当前循环,跳到循环后面的代码继续执行

1
2
3
4
5
6
7
for i = 1, 10 do
if i == 5 then
break -- 当 i 为 5 时,直接退出整个循环
end
print(i) -- 输出: 1 2 3 4
end
print("循环结束")

goto关键字

goto 是 Lua 5.2+ 引入的特性,可以跳转到指定的标签位置,但是因为太过于自由了,容易让代码变成牵一发动全身的屎山,所以最好不要用

语法格式为

1
2
3
::label::  -- 定义标签(用双冒号包裹)

goto label -- 跳转到标签位置

image-20260203164601539

1
2
3
4
5
6
7
8
local a = 1
::label::
print("都给我玩终末地去,咕咕嘎嘎!")

a = a + 1
if a < 3 then
goto label -- a 小于 3 的时候跳转到标签 label
end

或者这种

我把这个标签放到程序的开头,这样可以使用goto重新触发,为防止无限循环,使用break跳出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
local round = 0

--重新开始标签
::respawn::
local monkeyNumber = 10

local function killMonkey()
monkeyNumber = monkeyNumber - 1
end

for i = 1, monkeyNumber do
print("还有" .. monkeyNumber .. "只猴子")
killMonkey()

if monkeyNumber == 0 then
round = round + 1
print("第 " .. round .. " 轮结束,猴子都死光了")

-- 玩家战斗一共三轮
if round == 3 then
print("游戏结束")
break -- 跳出 for 循环
else
goto respawn -- 还有次数,重新开始
end
end
end

image-20260203171152901

lua里面没有c语言里的那种continue,但是可以通过模拟来实现

我们都知道continue的作用是跳出当前的过程不执行,但是继续该过程以后的过程

比如

1
2
3
4
5
6
7
for i = 1, 5 do
if i == 3 then
goto continue -- 跳过当前迭代
end
print("现在是" .. i) -- 输出: 1 2 4 5
::continue::
end

还有跳出多重循环

1
2
3
4
5
6
7
8
9
10
for i = 1, 3 do
for j = 1, 3 do
if i * j > 4 then
goto exit -- 直接跳到外层
end
print("第" .. i .. "行,第" .. j .. "列")
end
end
::exit::
print("全部结束")

if-else语句

这个和其他语言里的没啥区别,就是else if 变成了 elseif 写法

① 只写if

1
2
3
4
5
local money = 400

if money >= 300 then
print("速速购买黑神话吗喽")
end

② if + else

1
2
3
4
5
6
7
local money = 100

if money >= 300 then
print("速速购买黑神话吗喽")
else
print("没钱? 孩子,你还是去玩三角洲去吧")
end
image-20260204173944116

③ if + elseif + else

1
2
3
4
5
6
7
8
9
local money = 50

if money >= 300 then
print("速速购买黑神话吗喽")
elseif money >= 200 then
print("孩子,玩只狼吧")
else
print("没钱? 孩子,你还是去玩三角洲去吧")
end
image-20260204174459317

对了,lua里的if里的这个条件可以带括号也可以不带,一般不带,不过带了可读性更高

⚠️ 但是提醒一下,for循环不可以给条件语句带括号.否则会报错,但是其他循环可以

image-20260204174857146