@lisaisacat
2019-04-16T19:10:11.000000Z
字数 6164
阅读 46336
脚本开发
新手在学习使用触动精灵开发脚本的时候,总会进入一些误区,或者会有一些迷惑的点,觉得无从下手,本人总结了一些自己在学习过程中遇到的问题和经验技巧,欢迎大家一起交流分享。
本文中使用的截图来自游戏深海水族馆。
所用扩展库函数开发手册:https://www.zybuluo.com/miniknife/note/293935
微信公众号:脚本开发小百科,不定期更新越狱和脚本相关知识,欢迎订阅
- Lua 区分大小写!大小写!请把这句话大声的念三遍!
- 0 不是 nil! 不是 nil! 请把这句话大声的念三遍!
- 触动提供的函数不能在电脑上运行,只能在触动精灵里运行!不要再尝试在编辑器里本地运行脚本!
- Lua 能实现的,触动就可以,所以不要问触动能不能做什么,要问问你自己能不能写得出来!
其实脚本就是由无数的找色和点击组成的,所谓的找图和找字,本质上还是找色,所以如何快速高效的找到想找的颜色,非常重要。
掌握好找色技巧,对于学习脚本开发,事半功倍。
新手经常会遇到的问题
首先呢,找色一定要找非透明的部分,而就算一张图看上去几乎都是半透明,也总会有不透明的部分的。
像下面这种半透明颜色,一旦场景发生变化,十有八九是和你取得颜色不一样的,结果自然就是找、不、到。
从动图中我们可以看到,在不同的场景下,看上去都是红色的按钮,因为背景半透明,当使用
月之歌
技能时,按钮的颜色就变了。
那么如果我想判断技能面板有没有打开,要取哪几个点呢?
通过观察上面两张图可以发现,面板左上角的红心位置固定、颜色也是固定的,但是因为画面上方的小鱼吐出来的红心颜色很接近,也不能排除万一面板没打开但是颜色取到的情况,我们还需要再找一个点来确认。
当然那些数字部分是不能考虑的,为什么呢?
虽然颜色固定,但数值是一直在变化的啊!
中间部分和底部也是变化的,只能考虑面板顶部的几个图标了,位置固定,颜色不变。
选哪个好呢?我个人更倾向于小鱼标志,原因如下:
- 颜色单一,通过取色可以发现几乎就是纯白色
- 色块面积较大,就算分辨率很小也能取到四周都是同样颜色的点
确定了,取三个点,那么自然就要用到多点找色了,由于位置固定,用多点比色会更好。
由于找到颜色后要点击的位置固定但颜色也受场景影响不固定,那么就不能用 multiColTap 多点颜色判断单点击
而要用 multiColor 多点颜色判断
了。
最后,如果发现操作面板没有打开就点击面板菜单的代码如下:
if multiColor({{ 35, 632, 0xbe516a},{ 39, 635, 0xbe516a},{ 434, 670, 0xffffff}}) == false then--左上角红心,右侧白鱼
tap(584, 1090)--右下角面板菜单的坐标
end
代码详解
如果坐标 (35, 632)和(39, 635) 的颜色值不是 0xbe516a,坐标 (434, 670) 的颜色值不是 0xffffff,返回值为 false 就代表这三个坐标和颜色值不完全符合,也就是说,只要其中任何一个坐标和颜色值对不上,就是没找到,也就是面板没有打开。
看上面两张图中小鱼吐出来的红心泡泡,就是在屏幕中间部分来回游动的,虽然泡泡位置一直在变化,但是红心的相对位置是固定的,比如下图中我取的这三个点。
那么怎么找呢,位置不固定,比色函数是用不了的。
这种情况就要用到区域多点找色了,正好抓色器自动生成的代码中就有。
其实上图中的鱼儿吐的红心泡泡就是动态的,红心会有一个呼吸动画变大变小,但是这并不影响找色,因为红心中间部分的颜色是固定的,多点比色或者区域多点找色一样可以解决。因为找色是毫秒级别的,非常快,只要动画有一瞬间能跟你取色的颜色一致,就能找到。
如果想要点击的部分正好背景透明,在不同的时候颜色不一样;或者有很酷炫的动画效果,取不到固定的色值;甚至可能要点击的部分位置也是不固定的,随机在屏幕上移动。这种时候要怎么办呢?
可以观察下你要点击的部分周围是否有固定不变的画面,比如下图中的商店和魔法,当有新广告可以观看时会出现一个播放按钮,我们可以用多点比色来确定是否有新广告,有的话就去点击。此处可用触动精灵函数扩展库中的 multiColor 或者 multiColTap 函数判断播放按钮,再计算要点击的位置与取的第一个坐标之间的相对位置。
但是我们可以看到,魔法、商店都有可能出现播放按钮,如果代码中坐标固定的话,就意味着要分别去找这两个按钮。对于这种重复出现的画面,我们可以用区域多点找色在整个范围内查找,使代码更加简洁。
优化前的代码
if multiColor({{ 414, 1070, 0xffffff},{ 414, 1073, 0xffffff},{ 416, 1072, 0xffffff},}) then--商店播放按钮
tap(395, 1086)--点击商店
adtimes()
elseif multiColor({{ 330, 1070, 0xffffff},{ 330, 1073, 0xffffff},{ 333, 1072, 0xffffff},}) then--魔法播放按钮
tap(395, 1086)--点击魔法
adtimes(313, 1088)
end
优化后的代码
x,y = findMultiColorInRegionFuzzy( 0xffffff, "-9|-1|0x5bb3b5,1|-9|0x5bb3b5,2|9|0x5bb3b5", 90, 316, 1054, 522, 1089)--判断菜单栏(316, 1054) ,(522, 1089)范围内是否有播放按钮
if x ~= -1 then--如果返回值不是 -1,说明按钮存在
tap(x-20,y+15)--根据播放按钮计算要点击的位置
mSleep(1000)
adtimes()--封装的观看广告函数
end
相信很多新手都会有这个疑惑:
- 判断是不是自己想要的按钮或者界面,到底要在什么地方取色?
- 比如一个长方形的按钮,取四个角行不行呢?
- 要取几个点?是越多越好吗?
下面我们用另外一个游戏来简单讲解一下这个问题,以下截图全部来自游戏「我家的魔王大人-不愧勇者2」。
我们可以看到,左图中的按钮右上角有时候会显示一个 NEW 圆形图,如果取第三个小人头部位置的点的话,当圆形出现时就会影响找色。
所以,要考虑到各种情况,尽量取靠近中间区域的位置。
比如右图中椭圆红圈中间那个小人的位置。
至于取几个点,其实是越少越好,只要能够成功的区别于其他位置,不要出现乱点的情况就行,能两个点解决的就不要用三个点。
为什么呢?因为找的点越多速度越慢啊!
当然两个点和三个点可能差别是毫秒级别的很小可以忽略不计。
那么有些人又要问了,只取一个点不就好了~
如果你要取的这个地方其他所有界面都不会再出现,当然可以这么做,但是这么极端的情况很少见,否则只取一个点很可能就会乱点。
不管是背景透明还是位置不固定,或者是让新人头疼的动画效果,其实明白了找色原理之后都能通过分析找到解决办法:
首先要考虑的是取坐标的位置颜色必须是固定的,如果是动画,那么就取相对停留时间较长、色块区域较大的时间点截图取色;
然后就要考虑是固定坐标还是相对坐标,这就决定了是用比色还是区域找色;
其实说白了最佳的找色方案就是:仔细观察要识别的画面,找出独特的特征色的同时又要兼顾效率。
这就意味着用尽量少的点确定画面,既不会因为取色同质化胡乱识别,也不会因为取点太多降低脚本效率。
新人在群里问找图问题的时候,绝大多数都会被人提醒:不要用找图,找色效率更高。
为什么呢?
我们来打个比方,大家都知道图片其实是由一个一个的像素点组成的,取色也就是取了一个像素点。
那么一张 10x10 像素的图有多少像素点?没错,100个。
假如我们在 100 x 100 的范围内去找这样图,需要 100 个像素点匹配上才算找到了(当然找图函数 findImage 其实并不是真的每个点都找了)。
而正常情况下,我们取色就算取得多肯定也不会超过100个,如果你有特别的取色习惯这里不做讨论。
如果有一个 100 x 100 的房间,每一平米都放了不同编号的物品。
让两个人拿着一张表格去找房间里的东西,一张表上有 100 个物品,一张表上只有 3 个,谁先完成任务的几率更大?
我个人几乎没用过文字点阵识别,一般都用找色解决了,但是由于工作需要,参与测试过找字函数还有字库工具。
之前也做过大漠工具的教程,实际识别效果并不理想。当然大漠只能识别 11 行像素点是很大的限制,但是我总觉得找字是实在没办法了才会用,因为很没效率。
下面讲一下我对文字点阵识别的理解,很多内容都是百度来的,欢迎指正。
引用来源:http://blog.csdn.net/a511244213/article/details/45846443
点阵字库是一个数据文件,在这个数据文件里面保存了所有文字的点阵数据。
至于什么是点阵,我想我不讲大家都知道的,使用过"文曲星"之类的电子辞典吧,那个的液晶显示器上面显示的汉字就能够明显的看出"点阵"的痕迹。
在手机屏幕也是如此,文字也是由点阵来组成了,不同的是,手机屏幕的显示分辨率更高,高到了我们肉眼无法区分的地步,因此"点阵"的痕迹也就不那么明显了。
我个人比较明显的感受是大漠只识别 11 行像素点,生成的字库文件就很小,触动字库工具是全文字识别,字库文件大了很多。这就是因为要识别的文字越大,所需要存储的数据就越大。
所有的汉字或者英文都是下面的原理,由左至右,每 8 个点占用一个字节,最后不足 8 个点的占用一个字节,而且从最高位向最低位排列。
换句话说,所谓的点阵,顾名思义,就是把文字放到格子上,从左上角开始,每个像素为一个格子,通过对比格子中是否有颜色来判断是什么字。
生成的字库说明:(以12 × 12例子)
下图是点阵字库结构的图形化例子,在 16 x 16 的网格中显示 “汉” 字,其中 1 代表该网格中有点,0 代表没有。
关于函数封装部分的详细讲解可以先百度了解一下 Lua 中 function 的基础知识,再观看下。
函数封装的意义就在于减少重复代码,一旦游戏更新需要重新取色,只需要更新一个地方就行了,而不是满篇的去找。
比如下面这段代码,脚本打算提供两个功能:
- 仅解锁新的珊瑚
- 除了解锁还要升级最下面的珊瑚
功能 2 是包含了功能 1 的,脚本逻辑是这样的:
如果选了功能1,就在面板右侧按钮部分区域找黄色,找到就点击;如果选了功能2,除了找黄色,还要在右下角找蓝色按钮。
当然,不管选1还是2,都要先把杉树(其实是珊瑚)面板给打开。
第一版的代码
function ssup()
if multiColor({{ 146, 1093, 0xffffff},{ 146, 1085, 0xffffff},{ 150, 1072, 0xffffff}}) == false then--杉树未开
tap(146, 1085)
end
x,y = findMultiColorInRegionFuzzy( 0xe8972d, "154|0|0xe8972d", 90, 440, 693, 628, 1051)--查找黄色
if x ~= -1 then
tap(x,y)
end
x,y = findMultiColorInRegionFuzzy( 0x0099bc, "146|1|0x0099bc,-4|62|0x0099bc,142|59|0x0099bc", 90, 441, 905, 618, 1052)--下半部分区域查找蓝色
if x ~= -1 then
tap(x,y)
end
end
function ssunlock()
if multiColor({{ 146, 1093, 0xffffff},{ 146, 1085, 0xffffff},{ 150, 1072, 0xffffff}}) == false then--杉树未开
tap(146, 1085)
end
x,y = findMultiColorInRegionFuzzy( 0xe8972d, "154|0|0xe8972d", 90, 440, 693, 628, 1051)--查找黄色
if x ~= -1 then
tap(x,y)
end
end
杉树未开和查找黄色部分是重复代码,而修改之后就变成了:
function ssunlock()
if multiColor({{ 146, 1093, 0xffffff},{ 146, 1085, 0xffffff},{ 150, 1072, 0xffffff}}) == false then--杉树未开
tap(146, 1085)
end
x,y = findMultiColorInRegionFuzzy( 0xe8972d, "154|0|0xe8972d", 90, 440, 693, 628, 1051)--查找黄色
if x ~= -1 then
tap(x,y)
end
end
function ssup()
x,y = findMultiColorInRegionFuzzy( 0x0099bc, "146|1|0x0099bc,-4|62|0x0099bc,142|59|0x0099bc", 90, 441, 905, 618, 1052)--下半部分区域查找蓝色
if x ~= -1 then
tap(x,y)
end
end
对于新手来说最直接的感受就是对于点击的封装了,不封装的时候是这样的:
touchDown(x,y)
mSleep(50)
touchUp(x,y)
意味着每执行一次点击就要写三行代码,而封装之后呢,是这样的:
function tap(x,y)
touchDown(x,y)
mSleep(50)
touchUp(x,y)
end
以后要点击的话只需要写一行就可以了:
tap(x,y)
需要注意的是,封装的函数必须要在上面,下面才可以调用,否则就会出现非常常见的错误:xxx is a nil value.
脚本报错并不可怕,可怕的是看不懂报错。
新手经常遇到的报错无非就是调用的函数没有封装,或者 require 调用了函数库却没有发到设备上,要么就是没有区分大小写。
作为一个新手,也不会遇到什么特别复杂难解的错误的,因为你也写不出来。
自己写的源码,报错都有行数提示,在附近找找一般就能解决。
如果实在解决不了,可以去群里问一下别人,但是记得截图带上源码的行数。
触动精灵教学群:305168851
调用的函数不存在,如果是触动官方的函数,大概就是客户端该升级了。
如果是函数库中的函数,就是函数库文件没传到设备或者该升级了。
如果是自己写的函数,那就看看是不是顺序错了或者手误打错了。
这种错误一般是函数中的参数类型写错了,比如本来应该是个数值型(number),你给加了双引号,或者返回值本身就是字符型(string),反之亦然。