三、关于走迷宫
其实新增的迷宫如果不是随机变化的话,你只需要走一遍,记录一下路径,然后加到两头的节点上,或者制作一个alias,就可以了。
再变态一点的,就是将所有新增迷宫当做新房间都录入地图。但是这样难度大在于重复的房间太多,迷宫内定位会错误率较高。
当然,如果你没有录入所有房间也没有alias,或者说迷宫会随机变化,那么如何实现快速行走呢。
这里用到的就是根据房间出口进行自动行走。
关于抓取出口我一般用这个trigger
^\s+这里.+的(出口|方向)有 (.+)$
那么抓取之后我们把出口存成一个table。
chukou="%2"
if string.find("%2","。") then
chukou=string.gsub(chukou,"、",";")
chukou=string.gsub(chukou,"和",";")
chukou=string.gsub(chukou," ","")
chukou=string.gsub(chukou,"。","")
chukou=utils.split(chukou,";")
else
EnableTrigger("get_exists",1)
end
moved=1
EnableTrigger("get_exist",0)
由于有时候出口较多会超过一行,那么需要另作处理。在这先不讨论。
好了,房间出口会抓取,而且也转化成table了,那么我们只需要从中选取一个出口来开始走。
由于第一个房间我们只需要朝着一个方向前行,其它出口可以从table中删掉。
那么我们利用函数
function dellj(nowlj,fx) ----用于删除方向table中的某一个方向
local fx=fx
local nowlj=nowlj
local i=1
if fx==nil then return
else for i=1,table.getn(nowlj) do
if nowlj[i]==fx then table.remove(nowlj,i) end
i=i+1
end
end
end
假设走了一步 north ,那么来到的房间肯定有一个出口 south,那么这个south是回去的路,
我们独立存入一个table,用来记录返程路径,当前出口table中我们把south删掉,我们下一步要走的是south之外的其它出口。
那么根据方向求反方向,这个很简单,也算是常用函数
function revfx(fx)
if fx=="enterbj" then return "outbj" end
if fx=="outbj" then return "enterbj" end
if fx=="swboxiaolu" then return "boxiaolune" end
if fx==nil then return end
if fx=="south" then return "north" end
if fx=="east" then return "west" end
if fx=="west" then return "east" end
if fx=="north" then return "south" end
if fx=="southup" then return "northdown" end
if fx=="southdown" then return "northup" end
if fx=="westup" then return "eastdown" end
if fx=="westdown" then return "eastup" end
if fx=="eastup" then return "westdown" end
if fx=="eastdown" then return "westup" end
if fx=="northup" then return "southdown" end
if fx=="northdown" then return "southup" end
if fx=="northwest" then return "southeast" end
if fx=="northeast" then return "southwest" end
if fx=="southwest" then return "northeast" end
if fx=="southeast" then return "northwest" end
if fx=="enter" then return "out" end
if fx=="out" then return "enter" end
if fx=="up" then return "down" end
if fx=="down" then return "up" end
if fx=="u" then return "d" end
if fx=="d" then return "u" end
if fx=="s" then return "n" end
if fx=="e" then return "w" end
if fx=="w" then return "e" end
if fx=="n" then return "s" end
if fx=="su" then return "nd" end
if fx=="sd" then return "nu" end
if fx=="wu" then return "ed" end
if fx=="wd" then return "eu" end
if fx=="eu" then return "wd" end
if fx=="ed" then return "wu" end
if fx=="nu" then return "sd" end
if fx=="nd" then return "su" end
if fx=="nw" then return "se" end
if fx=="ne" then return "sw" end
if fx=="sw" then return "ne" end
if fx=="se" then return "nw" end
return fx
end
好了我们来写前进的函数
有点基础的朋友会发现,我们需要的实际上就是一个深度优先遍历。
首先我们用一个table来存储每一步中可用的出口方向 chukou_all_list (请原谅我的英语水平,只能用中英文混合。名字你自己随便设置)
chukou_all_list[1]表示第一个步
chukou_all_list[1][1]表示第一步中的第一个方向
再用另一个table来存储返回的路径 fx_back
然后我们需要知道最终的目的,我们设置一个变量 findmubiao (好吧,又是中英文混合的)表示到达目的,这个需要通过到达的房间的触发来给变量赋值1。
另外我们也可能需要中途停止遍历,那么再用一个变量 bl_finish 来表示终止。
这两个值有一个被赋值为 1 ,那么遍历行动停止。
再然后呢,需要通过一个触发来进行下一步的动作,在这里,我选择set
set bianli_wait 前进一步
set bianli_wait 后退一步
通过触发来进行下一个动作,如果走到死胡同,或者我们设定的出口不是想要的出口,那么后退一步。
否则的话,就继续向下走一步。
有时候走进迷宫之后有多个出口,比如既能通往松树林又能通往达摩洞,但我们不希望走进松树林。
那就通过松树林的描述触发,赋值给reach_end函数,告诉程序,这个路径点不希望继续下去,往回走。
好吧,放一段完整的函数供参考:
require "wait"
wait.make( function()
i=i+1
if math.fmod(i,"15") < 1 then
print("延时1秒后继续")
wait.time(1)
end
if i==1 then
table.insert(chukou_all_list,chukou)
else
if moved==1 then
if fx~=nil then
table.insert(chukou_all_list,chukou)
local fx_b=revfx(fx)
dellj(chukou_all_list[ck_i],fx_b)
moved=0
end
else
Note("被拦路,放弃此出口!!")
dep=dep-1
ck_i=ck_i-1
end
end
if ck_i==1 and chukou_all_list[ck_i][1]==nil then
Note("结束遍历!")
EnableGroup("bianli",0)
Send("unset brief")
else
if tonumber(GetVariable("bl_finish"))==1 or tonumber(GetVariable("findmubiao"))==1 then
Execute("say action 找到目标,遍历结束")
EnableGroup("bianli",0)
Execute("unset brief;look")
else
if chukou_all_list[ck_i][1]==nil or tonumber(GetVariable("reach_end"))==1 then
Note("后退一步")
dep=dep-1
table.remove(chukou_all_list,ck_i)--删除此空记录
ck_i=ck_i-1--应该走的方向列表
fx=fx_back[1]
Execute(fx..";set bianli_wait 后退一步")
table.remove(fx_back,1)
else
fx=chukou_all_list[ck_i][1]--当前房间出口的第一个方向
Note("前进一步,当前层数"..dep..",当前步数 "..i)
EnableTrigger("get_exist",1)
Execute(fx..";set bianli_wait 前进一步")
dellj(chukou_all_list[ck_i],fx)
ck_i=ck_i+1
dep=dep+1
fx_b=revfx(fx)
table.insert(fx_back,1,fx_b)
end
end
end
end)
那么同理,稍微修改一下就是后退的函数:
require "wait"
wait.make( function()
if ck_i==1 and chukou_all_list[1][1]==nil then
Note("未找到出口!")
EnableGroup("bianli",0)
else
i=i+1
if math.fmod(i,"15") == 1 then
print("延时1秒后继续")
wait.time(1)
end
if tonumber(GetVariable("bl_finish"))==1 or tonumber(GetVariable("findmubiao"))==1 then
Execute("say action 完成遍历,结束自动行走。")
EnableGroup("bianli",0)
else
if chukou_all_list[ck_i][1]==nil or tonumber(GetVariable("reach_end"))==1 then
Note("后退一步")
dep=dep-1
table.remove(chukou_all_list,ck_i)--删除此空记录
ck_i=ck_i-1--应该走的方向列表
fx=fx_back[1]
Execute(fx..";set bianli_wait 后退一步")
table.remove(fx_back,1)
else
fx=chukou_all_list[ck_i][1]--当前房间出口的第一个方向
Note("前进一步,当前层数"..dep..",当前步数 "..i)
EnableTrigger("get_exist",1)
Execute(fx..";set bianli_wait 前进一步")
dellj(chukou_all_list[ck_i],fx)
dep=dep+1
ck_i=ck_i+1
fx_b=revfx(fx)
table.insert(fx_back,1,fx_b)
end
end
end
end) |