函数(一)
函数(一)
上一节中,我主要讲了怎么查看API,以及一个简单的例子。这一节,我会将这个例子详细说明一下。
先回顾一下例子:
local function Player_ClickBlock (event)
if event.blockid == 104 then
Block:placeBlock(410, event.x, event.y, event.z, 0)
end
end
ScriptSupportEvent:registerEvent([=[Player.ClickBlock]=], Player_ClickBlock)
要看懂这几行脚本,首先就要了解数据类型的知识。
讲数据类型之前,先说一下变量。变量可以简单理解为未知数,类比数学里的x、y、z。不过变量里不仅仅能放数,它可以放所有数据类型。
lua中有8种数据类型,这一节就讲一下函数。
函数,可以简单理解为对一系列动作的一个整合,而一行脚本可能就是一个动作。这个现在不理解也没关系。
函数定义的结构很简单,是由“function 函数名 (参数) 函数体 end”构成。其中参数就是变量,可以有0个或多个。
对照上面的脚本例子,先看第1行:local
表明这是一个局部函数,可以先忽略不管。function
是函数定义的标志,Player_ClickBlock
是函数名,event
是参数。2~4行是函数体。第5行的end
表示函数结束。至于为什么不是第4行的end
,这是因为第4行的end
是对应的第2行的if
。
函数定义后需要调用(使用),不然定义函数就没有意义。函数的调用格式为:函数名(变量)。比如上面1~5行定义的函数,调用时可以写成如下所示:
Player_ClickBlock()
只是这样写是没有传入参数的,那么event
就没有值。上面例子的第7行,也是函数的调用,括号中有两个参数。不过这是面向对象的调用方式,涉及的内容比较复杂,不在教程的讲解范围之内。
至于为什么需要使用函数,下面举个通俗的例子。
我现在要将大象放入冰箱,需要做三个动作:
打开冰箱门 将大象放入冰箱 关上冰箱门 当我需要将大象A放入冰箱A时,写成伪码就是:
打开冰箱A门
将大象A放入冰箱
关上冰箱A门
当我每次需要将一头大象放入一个冰箱时,都要写三行。我觉得太麻烦了,于是定义了一个函数:
function 把大象放入冰箱 (大象参数, 冰箱参数)
打开冰箱参数
将大象参数放入冰箱
关上冰箱参数
end
这时,当我需要将大象A放入冰箱A中,大象B放入冰箱B中,那么只需要调用函数就行了:
把大象放入冰箱(大象A, 冰箱A)
把大象放入冰箱(大象B, 冰箱B)
好了,下面我们来实践一下。
现在我们来做这样一个效果:当有玩家进入游戏时,聊天框提示所有玩家谁进入了游戏。当有玩家离开游戏时,聊天框提示所有玩家谁离开了游戏。
简单分析一下,我们需要以下的API:
事件:玩家进入游戏事件,玩家离开游戏事件 信息:玩家的名字 动作:对玩家显示聊天框信息 然后去查API。
点击左侧的事件系统,在右侧找到游戏逻辑:
点击找到对应事件:
通过模仿,我们就可以把两个事件的结构写出来了:
local function Game_AnyPlayer_EnterGame (event)
end
ScriptSupportEvent:registerEvent([=[Game.AnyPlayer.EnterGame]=], Game_AnyPlayer_EnterGame)
local function Game_AnyPlayer_LeaveGame (event)
end
ScriptSupportEvent:registerEvent([=[Game.AnyPlayer.LeaveGame]=], Game_AnyPlayer_LeaveGame)
接着我们找一下获得玩家名字的API。
点击左侧的玩家管理接口,在右侧找到获取玩家昵称:
点击跳转到对应接口说明:
正巧,在聊天框显示API例子里也写了。那么,我们连蒙带猜,大概是这样写:
local function Game_AnyPlayer_EnterGame (event)
local result, name = Player:getNickname(event.eventobjid)
Chat:sendSystemMsg(name .. "进入了游戏")
end
ScriptSupportEvent:registerEvent([=[Game.AnyPlayer.EnterGame]=], Game_AnyPlayer_EnterGame)
local function Game_AnyPlayer_LeaveGame (event)
local result, name = Player:getNickname(event.eventobjid)
Chat:sendSystemMsg(name .. "离开了游戏")
end
ScriptSupportEvent:registerEvent([=[Game.AnyPlayer.LeaveGame]=], Game_AnyPlayer_LeaveGame)
如果你没猜对,那就多猜几次。如果完全不知道函数体里怎么写,我们可以仔细看看接口说明。接口的参数是objid,我们没有这个objid,只能从事件去找:
事件里有个eventobjid,还有个toobjid。不知道哪个就都试一下。
至于为什么要写成event.eventobjid
,还是那句话,模仿,看看文档上的例子,模仿着写,比如如下例子:
仔细看看例子,获取参数都是event.eventobjid或event.toobjid,虽然不太明白为什么这么写,但是可以大致猜到这么写的作用。如果猜不到,就照搬,然后试试。
是不是觉得这一节例子和今天讲的关系不大。没错,因为还有事情没有做,那就是提取函数。在两个事件里,所做的动作都差不多,我们可以将相似的动作提取出来。先定义一个函数:
function showPlayerMsg (event, msg)
local result, name = Player:getNickname(event.eventobjid)
Chat:sendSystemMsg(name .. msg)
end
函数名为showPlayerMsg
,将要提示的内容通过msg
参数传入。整合进来,代码如下:
function showPlayerMsg (event, msg)
local result, name = Player:getNickname(event.eventobjid)
Chat:sendSystemMsg(name .. msg)
end
local function Game_AnyPlayer_EnterGame (event)
showPlayerMsg(event, "进入了游戏")
end
ScriptSupportEvent:registerEvent([=[Game.AnyPlayer.EnterGame]=], Game_AnyPlayer_EnterGame)
local function Game_AnyPlayer_LeaveGame (event)
showPlayerMsg(event, "离开了游戏")
end
ScriptSupportEvent:registerEvent([=[Game.AnyPlayer.LeaveGame]=], Game_AnyPlayer_LeaveGame)
如果其他地方也有需要显示玩家名的提示,就可以直接调用showPlayerMsg
。