A*范围转换 A_rect(table,table)
免费
格式 : table = A_rect( {起点x,起点y} , {目标点x,目标点y} )
适用场景 : A星寻路
其他关联函数 : ptable
初始化起点为(0,0)思路图解:
1、先求x1,y1,x2,y2范围坐标,才能进行二值化:
我们希望输入任意2个边角坐标,自动计算左上角和右下角的范围{x1,y1,x2,y2}
function A_rect(t1,t2)
local t={}
if t1[1]<t2[1] then
t[1]=t1[1]
t[3]=t2[1]
else
t[1]=t2[1]
t[3]=t1[1]
end
if t1[2]<t2[2] then
t[2]=t1[2]
t[4]=t2[2]
else
t[2]=t2[2]
t[4]=t1[2]
end
return t
end
local QI_DIAN={440,467}
local ZH_DIAN={486,407}
local rect = A_rect(QI_DIAN,ZH_DIAN) --[[人物起点,目标终点]]
--x1,y1,x2,y2:rect={440,407,486,467}
A*路线代价 A_cost(table,table)
免费
格式 : 代价 = A_rect( {起点x,起点y} , {目标点x,目标点y} )
适用场景 : A星寻路
A星寻路则需要计算起点—>终点消耗的代价:**直线每步+10,斜线每步+14**
function A_cost(Qt,Zt)
local x1=math.abs(Zt[1]-Qt[1])
local y1=math.abs(Zt[2]-Qt[2])
local a = math.abs(x1-y1) --[[找到x和y之间的差值]]
local z = 0 --[[代价]]
if x1<y1 then --[[x1,y1最小值计算斜线,a差值计算直线]]
z=x1*14+a*10
else
z=y1*14+a*10
end
return z
end
二值化代价 A_binarizeImage(table,table,number)
免费
格式 : table,缩放Zt,缩放Qt = A_binarizeImage( {范围,颜色-偏色}, {起点x, 起点y}, 步数 )
适用场景 : A星寻路
其他函数 : ptable、A_rect、A_cost
叉叉函数 : keepScreen、getColorRGB
function A_binarizeImage(t,t_1,P)
local P = P or 1 --[[遍历步数1像素]]
local x0 = math.floor((t_1[1]-t.rect[1])/P) + 1
local y0 = math.floor((t_1[2]-t.rect[2])/P) + 1
local Qt = {x0 , y0 ,0} --[[二值化起点]]
local Zt = {0,0,0} --[[找到最远距离的点]]
local getColorRGB = getColorRGB
local rect = t.rect or {0,0,0,0}
local diff = t.diff or {"0x000000-0x000000"}
local color = {}
local tab = {}
for k,v in pairs(diff) do
if color[k]==nil then
local rgb_1 = tonumber(string.sub(v,1,8)) --0xf7d363-->转数值
local rgb_2 = tonumber(string.sub(v,10,17))
color[k] = {
lr = rgb_1/0x10000,
lg = rgb_1%0x10000/0x100,
lb = rgb_1%0x100,
sr = rgb_2/0x10000, --阈值
sg = rgb_2%0x10000/0x100, --阈值
sb = rgb_2%0x100, --阈值
}
end
end
keepScreen(true) --保持屏幕
for y=rect[2],rect[4],P do
local y1 = math.floor((y - rect[2])/P) + 1 --坐标位置初始化
tab[y1] = {}
for x=rect[1],rect[3],P do
local x1 = math.floor((x - rect[1])/P) + 1 --坐标位置初始化
for i = 1,#color do --颜色参数数量
local lr,lg,lb = color[i].lr,color[i].lg,color[i].lb
local sr,sg,sb = color[i].sr,color[i].sg,color[i].sb
local r,g,b = getColorRGB(x,y) --调用这个函数需要用保持屏幕来提高效率
if math.abs(lr-r) > sr or math.abs(lg-g) > sg or math.abs(lb-b) > sb then --绝对值
local z = A_cost(Qt,{x1,y1}) --路程代价
if Zt[3] < z then
Zt = {x1, y1, z }
end
tab[y1][x1] = 0
else
tab[y1][x1] = 1 --[[匹配]]
break
end
end
end
end
keepScreen(false)
return tab,Qt,Zt
end
--rect={440,407,486,467}
local t = {
rect = rect,
diff = {"0x000400-0x333333"}
}
local t,Qt,Zt=A_binarizeImage(t,{440,467},3) --[[缩放后的:Zt=终点,Qt=起点]]
ptable(t,Qt,Zt) --Qt={1,21,0},Zt={16,1,260}
t={
{1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0},
{1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0},
{1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0},
{1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0},
{1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0},
{1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1}}
为了提高二值化速度,二值化步数设置为3,二值化图像比原图缩小3倍。
缩放**注意事项:**保证最少9格子内没有不可走“+++”或“1” ,保证路线宽敞即可,因为我并不想贴着墙走。所以后面会有一种算法,判断格子内有“墙”则不走这条路线。
游戏图:
范围只是演示,实际范围根据目标点而定!
不可走路线:“+++”默认显示 1
--转化成代价图像,起点为0,终点为260最大代价,从0周围开始寻找最小值路线
t={
{+++,+++,+++,212,216,220,224,228,232,236,240,244,248,252,256,260},
{+++,+++,198,202,206,210,214,218,222,226,230,234,238,242,246,250},
{+++,184,188,192,196,200,204,208,212,216,220,224,228,232,236,240},
{170,174,178,182,186,190,194,198,202,206,210,214,218,222,226,230},
{160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220},
{150,154,158,162,166,170,174,178,182,186,190,194,198,202,206,210},
{+++,144,148,152,156,160,164,168,172,176,180,184,188,192,196,206},
{+++,134,138,142,146,150,154,158,162,166,170,174,178,182,192,202},
{+++,+++,128,132,136,140,144,148,152,156,160,164,168,178,188,198},
{+++,114,118,122,126,130,134,138,142,146,+++,+++,+++,174,184,194},
{+++,104,108,112,116,120,124,+++,+++,+++,+++,+++,+++,+++,+++,190},
{+++,94,98,102,106,110,+++,+++,+++,+++,+++,+++,+++,+++,+++,186},
{+++,84,88,92,96,100,+++,+++,+++,+++,+++,+++,+++,+++,+++,182},
{+++,74,78,82,86,90,+++,+++,+++,+++,+++,+++,+++,+++,+++,178},
{+++,64,68,72,76,80,+++,+++,+++,+++,+++,+++,+++,+++,+++,+++},
{50,54,58,62,66,70,+++,+++,+++,+++,+++,+++,+++,+++,+++,+++},
{40,44,48,52,56,+++,+++,+++,+++,+++,+++,+++,+++,+++,+++,+++},
{30,34,38,42,52,+++,+++,+++,+++,+++,+++,+++,+++,+++,+++,+++},
{20,24,28,38,48,+++,+++,+++,+++,+++,+++,+++,+++,+++,+++,+++},
{10,14,24,34,44,+++,+++,+++,+++,+++,+++,+++,+++,+++,+++,+++},
{0,10,20,30,40,50,+++,+++,+++,+++,+++,+++,+++,+++,+++,+++}}
地图未探索区域可能发生的情况:
假设黄线内是墙,终点也是墙,那么实际返回距离终点最近的Zt={10,1,240},证明Zt是确定我们实际的终点。
这里要注意:如果黄线是墙,终点是可走的,但是并没有可走路线,返回Zt不变,这个问题我们在后面学习A星寻路,发现寻路失败,再来解决。
OK,有了代价图表,我们就可以开始写A星寻路算法,寻找0—>260最短路线。
麻麻再也不用担心我迷路了。。