最近在玩一款游戏,叫部落冲突,里面又一个夜世界,操作呆瓜,很耗时,明显是用来提高用户的上线时间的,这我肯定不能忍,于是开始想着怎么用程序来提高效率,接着便发现了autojs这个神器。
目前autojs在维护的版本好像只有了 https://github.com/SuperMonster003/AutoJs6 ,由于比较小众,网上的资源其实并不多,最要命的是它文档还不齐全。在折腾了一天之后,终于被我开发出了一个可用的自动化版本。本文记录过程中的一些坑和一些可复用的代码片段。
首先是环境的配置,按照Github上项目的readme文档来,大概率可以正确的配置好。比较坑的一点是:写的代码可以自动同步到手机端,但是图片文件夹不行,这样每次截图就得手动通过数据线传到手机目录,感觉很愚蠢,但是还没找到解决方法。另外,该项目配套的AutoJs6 文档似乎没有在维护了,且已有的内容结构也很混乱,目前看下来最好的文档是在收集app上的示例代码。
常用函数
写游戏脚本,其实不需要UI,常用的函数大概只有如下几个。
点击函数
可以根据输入坐标来点击屏幕
/**
* @see Internal.Automator.click
*/
declare function click(x: number, y: number): boolean;
长按函数
/**
* @see Internal.Automator.press
*/
declare function press(x: number, y: number, delay: number): boolean;
可以根据输入的坐标和按下时间来长按屏幕
屏幕滑动
在游戏中,有时候需要在地图上不断的滑动,然后才能找到某个图标。
/**
* @see Internal.Automator.swipe
*/
declare function swipe(x1: number, y1: number, x2: number, y2: number, duration: number): boolean;
子图匹配
autojs内置的子图匹配函数签名如下:
/**
* @param img
* @param template
* @param [options={}]
* @param [options.threshold=0.9]
* @param [options.weakThreshold=0.6]
* @param [options.level=-1]
* @param [options.region]
* @see images.findImage
*/
declare function findImage(img: ImageWrapper, template: ImageWrapper, options?: {
threshold?: number;
weakThreshold?: number;
level?: number;
region?: OmniRegion;
}): OpenCV.Point;
使用案例如下:
var tar = images.read(imgPath);
var p = findImage(captureScreen(), tar, {
threshold: options && options.threshold || 0.6
})
tar.recycle();
其中:
var tar = images.read(imgPath);为读取指定路径的子图,然后用tar.recycle();回收了内存。captureScreen()为截图函数- 返回的p为匹配得到的坐标。
更加完整的使用示例见下一小节。
子图匹配场景
用来操作游戏的脚本中,有很多是需要 先匹配一个子图的位置,然后点击该位置,其实就是子图匹配的问题,autojs也提供了一个接口,但是游戏页面对于不同的皮肤,那些需要点击的按钮经常是颜色样式不一样的。于是就有了以下技巧,首先是把统一目标的多个皮肤子图都給截图截下来,按照如下的风格保存好:
const recognizable = {
"收集圣水车": {
text: "收集圣水车",
path: "images/收集圣水车_full_ysj.jpg"
},
"收集圣水车2": {
text: "收集圣水车2",
path: "images/收集圣水车_full2_ysj.jpg"
},
"收集圣水车3": {
text: "收集圣水车3",
path: "images/收集圣水车_full3_ysj.jpg"
}
}
然后通过一个while true循环来不断的找,只要匹配到一个,那么就可以break,代码如下:
function collect_sheng_shui_che(){
let paths = [
imgs['收集圣水车'].path,
imgs['收集圣水车2'].path,
imgs['收集圣水车3'].path,
]
let is_success = false
while(true){
for (let i = 0; i < paths.length; i++) {
if(cp.clickOne(paths[i])){
is_success = true
break;
}
}
if (is_success){
break;
}
sleep(3000)
}
toastLog("收集圣水车" + is_success)
}
该代码中用到了cp.clickOne(paths[i]) 函数,该函数参考自别人的代码,现拷贝如下:
/**
*
* 随机点击小图的某个位置
* @param {Number} pixel - 偏移像素最大值, 默认10
*/
capture.clickOne = function(imgPath, pixel, options) {
//取得随机值<=pixel
var i = 0;
pixel = pixel || 10;
var pix = Math.floor(Math.random() * pixel);
prompt = prompt || true;
if (capture.getOne(imgPath, function(p) {
click(p.x + pix, p.y + pix);
//log('点击了%d,%d', p.x + pix, p.y + pix);
sleep(500);
}, options)) {
return true;
}
return false;
}
/**
* 当前界面里找小图,自动回收,返回该图坐标,支持回调函数, 参数是小图坐标
*
* @param {string} imgPath - 匹配图片路径
* @callback callback 找到则执行该函数
* @param {Objcet} [threshold=0.6] - 图片相似度。取值范围为0~1的浮点数
* @return {Point|null} - 找到返回Point对象,否则null
*/
capture.getOne = function(imgPath, callback, options) {
var tar = images.read(imgPath);
var p = findImage(captureScreen(), tar, {
threshold: options && options.threshold || 0.6
});
tar.recycle();
if (p) {
if (callback && typeof callback === "function") {
var fn = callback;
res = fn(p);
if (res) return res;
}
return p;
} else {
console.warn('没有找到图:' + imgPath);
return null;
}
}