5. Lua:循环#
本节中我们来了解另一个重要概念——循环。循环可以让计算机自动完成许多重复的工作, 同时也可以让我们的所有操作更为简化。
5.1. 遍历一个列表#
上文提到了列表,并且解说了对列表的修改和增删操作。然而在实际操练中,我们经常需要遍历列表,对每个元素执行相同的操作。例如技能“神愤”,要对所有人造成1点伤害, 这就需要我们对保存着“所有角色”的列表中的每个元素都执行相同的操作了。举个例子:
local generals = { "张飞", "刘备", "曹操", "徐盛", "孙权" }
print("发动技能神愤!")
print("对" .. generals[1] .. "造成了1点伤害")
print("对" .. generals[2] .. "造成了1点伤害")
print("对" .. generals[3] .. "造成了1点伤害")
print("对" .. generals[4] .. "造成了1点伤害")
print("对" .. generals[5] .. "造成了1点伤害")
上面的代码中我们徒手操作列表,对其中的每个人造成了一点伤害;我们先用索引取得对应的字符串,
然后再用拼接运算符拼出一条完整的信息,打印到屏幕上。但这种做法显得很笨,
我们接下来看看如何使用Lua的 for 循环完成一样的操作:
local generals = { "张飞", "刘备", "曹操", "徐盛", "孙权" }
print("发动技能神愤!")
for _, general in ipairs(generals) do -- [1]
local message = "对" .. general .. "造成了1点伤害"
print(message)
end
运行一下,发现输出的是一样的结果。你可以试试修改generals列表中的内容,程序会毫不保留的将所有内容都打印一行出来。
仔细观察[1]处的代码:我们定义了一个for循环,这行代码能让Lua从列表generals中先取出一个元素,并把他储存在临时变量general中。这之后,Lua就会执行for语句内层的那个语句块了,这里就是拼出一条消息然后打印出来。这样一来,对于generals中的每个元素,Lua都会重复执行一次for内层的代码,直到所有元素都处理完毕了。
5.1.1. 在遍历列表中执行一些特殊的操作#
因为for语句内部是一个语句块,所以我们可以在那里编写任意多的代码。何不趁现在操练一下之前学习的if语句?我们修改一下代码吧,如果是对徐盛造成了伤害,则多输出一条消息,毕竟这有着某种特殊的含义。
做法很简单;我们只要在内层进行一次if判断就行了,如果当前遍历到的是“徐盛”,那么就多输出一条消息:
local generals = { "张飞", "刘备", "曹操", "徐盛", "孙权" }
print("发动技能神愤!")
for _, general in ipairs(generals) do -- [1]
local message = "对" .. general .. "造成了1点伤害"
print(message)
if general == "徐盛" then
print("你犯大吴疆土了!")
end
end
回忆一下for语句执行的步骤:首先,他从列表generals中拿出一个元素,然后将其保存到临时变量general中。有了这个临时变量之后,Lua就会继续执行for语句的内层代码块。如此循环往复,直到列表中的元素被全部拿完了。因为拿出来的元素是保存在临时变量里面的,所以当我们遍历到“徐盛”的时候,变量general的值就是“徐盛”,于是就通过了if语句的条件检测,执行了if语句那里的print。
5.1.2. 使用break中途退出循环#
要立即退出for循环,不再运行循环中余下的代码,可使用break语句。 break语句用于控制程序流程,可使用它来控制哪些代码行将执行, 哪些代码行不执行,从而让程序按你的要求执行你要执行的代码。
例如,当对徐盛造成伤害后,我们想让徐盛保卫吴国疆土,以保证孙权不受伤, 这里就可以加一个break语句强行退出循环:
local generals = { "张飞", "刘备", "曹操", "徐盛", "孙权" }
print("发动技能神愤!")
for _, general in ipairs(generals) do -- [1]
local message = "对" .. general .. "造成了1点伤害"
print(message)
if general == "徐盛" then
print("徐盛保卫了大吴疆土,神愤被中途结束了。")
break
end
end
运行一下,可以看到对孙权造成伤害的那行不再显示了。这是因为这里使用了break,把整个循环中途掐断了。
5.2. while循环简介#
前面我们提到了for循环,他可以通过遍历一个列表来不断的执行循环;而while循环则更加通用,他像if一样进行着一个条件检测,如果通过的话就执行代码, 如此循环往复,直到那个条件检测不通过为止。
下面的代码使用了while循环,让程序从1数到5:
local num = 1
while num <= 5 do
print(num)
num = num + 1
end
在第1行,我们将 num 设置为1,从而指定从1开始数。接下来的while循环被设置成这样: 只要 num 小于或等于5,就接着运行这个循环。循环中的代码打印num的值, 再使用代码num = num + 1将其值加1。
只要满足条件 num <= 5 ,Lua就接着运行这个循环。由于1小于5,因此Lua打印1,并将num加1,使其为2;由于2小于5,因此Lua打印2,并将num加1,使其为3, 以此类推。一旦num大于5,循环将停止,整个程序也将到此结束。
while循环非常有用。例如,出牌阶段就是一个while循环:只要角色没有阵亡, 他就一直循环往复的让玩家选择出一张牌或者发动一个技能,直到玩家想要结束的时候才退出循环。
和for循环一样,使用break语句亦可让while循环立即结束。这个就请读者们自行操练吧。
5.3. 操练:使用while来遍历列表#
回到前面关于for循环遍历列表的话题吧。既然while这么有用,想必也可以用来遍历列表。
local generals = { "张飞", "刘备", "曹操", "徐盛", "孙权" }
print("发动技能神愤!")
for _, general in ipairs(generals) do -- [1]
local message = "对" .. general .. "造成了1点伤害"
print(message)
end
像这样的for循环可以直接遍历整个列表;而while循环需要我们手动编写条件检测。 回想一下for循环的运行流程,首先拿出一个元素,然后执行代码,下一轮执行又拿出下一个元素,直到没有可以拿的为止。为此,我们可以设置一个变量表示当前元素的索引,每执行一次while循环,就根据这个索引取出值,然后把索引加一;如此往复, 直到取不出值为止(取了个nil出来),此时我们就用break手动结束掉循环。
代码如下:
local generals = { "张飞", "刘备", "曹操", "徐盛", "孙权" }
print("发动技能神愤!")
local index = 1
while true do -- 条件判断填了个true,这将导致无限的循环下去
local general = generals[index] -- 首先取出值,保存在变量general
index = index + 1 -- 然后将索引加一
if general == nil then -- 如果我已经没有值可以取了怎么办?
break -- 用break直接中断循环就行了
end
local message = "对" .. general .. "造成了1点伤害"
print(message)
end