龙空技术网

微信跳一跳 程序猿JavaScript代码实现自动跳跃

不爱bug爱吉他 2164

前言:

现在咱们对“wechaty java”都比较注重,同学们都想要了解一些“wechaty java”的相关内容。那么小编也在网上汇集了一些关于“wechaty java””的相关资讯,希望姐妹们能喜欢,小伙伴们快快来了解一下吧!

## 使用方法

1. 下载脚本WechatJumpingAI.js并安装软件Auto.js,使用Auto.js打开或导入该脚本文件

2. 打开微信跳一跳界面,切回Auto.js,运行脚本(可能需要根据分辨率调整系数),回到微信跳一跳界面

3. 第一次运行脚本时可能会弹出需要打开无障碍服务的请求并跳转到权限申请界面,此时需要在该界面的无障碍权限应用列表中中找到Auto.js并开启权限,并重新运行脚本;同时会弹出请求屏幕截图的权限申请,此时请点击"总是允许"并同意权限

4. 现在可以愉快地刷分啦~如果因算法问题导致游戏失败,脚本会自动重新开始游戏;一旦退出微信界面,脚本会自动停止。

系数的调整是,如果是720p分辨率建议为2.099,1080p则为1.392,2k屏幕则为1.045;如果发现总是跳的太远则调小,反之调大。

## 算法与原理

本脚本由wangshub的python代码修改而来,参见

1. 使用opencv实现的快速找色函数找出并计算棋子位置。具体为先根据棋子颜色找出棋子顶部位置,再遍历顶部这一行的像素找出顶部的中点位置,偏移得到棋子底部中点位置。

2. 使用项目wangshub/wechat_jump_game的算法缓慢找出并计算跳跃目标的位置。

3. 根据跳跃距离乘以系数计算按压时间并按压

----------------------------------------------------------------------废话不多说 直接上代码-------------------------------------------------------

// 根据wangshub的Python代码修改而来(原项目地址)

// 运行环境:安卓软件Auto.js(), 下载地址:

// 需求root权限或者安卓7.0以上才能运行本脚本

// 在原算法基础上优化了找出棋子的算法(直接使用Auto.js内置使用opencv实现的找色函数, 比原算法快很多),但是在手机设备上找出跳跃位置的算法的效率还是不够理想

var press_coefficient = device.height == 1920 ? 1.392 : 2.099; // 长按的时间系数,请自己根据实际情况调节

const under_game_score_y = 300 // 截图中刚好低于分数显示区域的 Y 坐标,300 是 1颜色920x1080 的值,2K 屏、全面屏请根据实际情况修改

//按压位置为再来一局的位置

const press_x = device.width / 2;

const press_y = 1584 * (device.height / 1920.0);

const piece_body_width = 80 // 棋子的宽度,比截图中量到的稍微大一点比较安全,可能要调节

const piece_dist_from_top_to_base = 188; //棋子最顶部到棋子底部中点的距离

// 下面的 (353, 859) 和 (772, 1100) 是游戏截图里的两个台 子的中点坐标,主要用来算角度,可能要调节

const sample_board_x1 = 353;

const sample_board_y1 = 859;

const sample_board_x2 = 772;

const sample_board_y2 = 1100;

const piece_color = "#3d3752"; //棋子大致颜色

var w = device.width;

var h = device.height;

//使这些函数调用更方便

const red = colors.red;

const green = colors.green;

const blue = colors.blue;

const max = Math.max;

const abs = Math.abs;

//如果debug为true则开启调试,将会把每次计算的棋子位置和目标位置标记在截图中并保存在一下目录

const debug = false;

const debug_images_dir = "/sdcard/debug/";

prepare();

main();

function press_compat(x, y, duration){

if(device.sdkInt >= 24){

press(x, y, duration);

}else{

root_automator.press(x, y, duration);

}

}

function jump(distance){

var press_time = distance * press_coefficient;

press_time = max(200, press_time);

press_compat(press_x, press_y, parseInt(press_time));

}

function find_piece_and_board(im){

var piece = find_piece(im);

var board = find_board(im, piece);

return {

piece: piece,

board: board

};

}

function find_board(im, piece){

var board_x = 0;

var board_y = 0;

var scan_start_y = get_scan_start_y(im);

for(var i = parseInt(h / 3); i < parseInt(h * 2 / 3); i++){

last_pixel = im.pixel(0, i);

if(board_x || board_y){

break;

}

var board_x_sum = 0

var board_x_c = 0

for(var j = 0; j < w; j++){

var pixel = im.pixel(j, i);

// 修掉脑袋比下一个小格子还高的情况的 bug

if(abs(j - piece.x) < piece_body_width){

continue;

}

// 修掉圆顶的时候一条线导致的小 bug,这个颜色判断应该 OK,暂时不提出来

if(abs(red(pixel) - red(last_pixel)) + abs(blue(pixel) - blue(last_pixel)) + abs(green(pixel) - green(last_pixel)) > 10){

board_x_sum += j;

board_x_c += 1;

}

}

if(board_x_sum){

board_x = board_x_sum / board_x_c

}

}

// 按实际的角度来算,找到接近下一个 board 中心的坐标

var board_y = piece.y - abs(board_x - piece.x) * Math.sqrt(3) / 3;

if(!(board_x && board_y)){

return null;

}

return {

x: board_x, y: board_y

}

}

function get_scan_start_y(im){

var scan_x_border = parseInt(w / 8) // 扫描棋子时的左右边界

var scan_start_y = 0 // 扫描的起始y坐标

// 以50px步长,尝试探测scan_start_y

for(var i = under_game_score_y; i < h; i += 50){

var last_pixel = im.pixel(0, i);

for(var j = 1; j < w; j++){

var pixel = im.pixel(j,i);

// 不是纯色的线,则记录scan_start_y的值,准备跳出循环

if(red(pixel) != red(last_pixel) || green(pixel) != green(last_pixel) || blue(pixel) != blue(last_pixel)){

scan_start_y = i - 50

break;

}

}

if(scan_start_y){

break;

}

}

return scan_start_y;

}

function find_piece(im){

//使用内置找色函数找出棋子最顶部的位置

var piece_top = findColor(im, piece_color, {

threshold: 3

});

var piece_start_x = -1;

var piece_end_x = -1;

//遍历该行找出棋子顶部中点位置

for(var x = 0; x < w; x++){

var is_piece = images.detectsColor(im, piece_color, x, piece_top.y, 2);

if(is_piece && piece_start_x < 0){

piece_start_x = x;

}

if(!is_piece && piece_start_x >= 0){

piece_end_x = x;

break;

}

}

//棋子顶部中点位置

var piece_top_center_x = (piece_start_x + piece_end_x) / 2;

var piece_x = piece_top_center_x;

var piece_y = piece_top.y + piece_dist_from_top_to_base;

return {

x: piece_x, y: piece_y

}

}

function main(){

toast("请在5秒内打开游戏,并点击开始按钮");

waitForPackage("com.tencent.mm");

sleep(5000);

while(currentPackage() == "com.tencent.mm"){

var im = captureScreen();

// 获取棋子和 board 的位置

var result = find_piece_and_board(im);

var board = result.board;

var piece = result.piece;

log("find result: ", result);

if(debug && result){

save_result(im, result);

}

jump(Math.sqrt(Math.pow(board.x - piece.x, 2) + Math.pow(board.y - piece.y, 2)));

sleep(2000);

}

}

var root_automator = null;

function prepare(){

//确保无障碍服务开启

auto();

//请求截图权限

requestScreenCapture();

device.keepScreenOn(1000 * 3600);

if(device.sdkInt < 24){

root_automator = new RootAutomator();

}

events.on("exit", function(){

device.cancelKeepingAwake();

if(root_automator){

root_automator.exit();

}

});

if(debug){

files.ensureDir(debug_images_dir);

}

//从存储中读取系数

var storage = storages.create("org.autojs.wxjumping");

press_coefficient = storage.get("press_coefficient", press_coefficient);

//让用户输入系数

press_coefficient = dialogs.input("调整跳跃系数(可选)", press_coefficient);

storage.put("press_coefficient", press_coefficient);

}

function save_result(im, result){

importPackage(android.graphics);

var bmp = im.getBitmap();

var canvas = new Canvas(bmp);

var paint = new Paint();

paint.setStyle(Paint.Style.FILL);

paint.setColor(colors.rgb(255, 0, 0));

drawCircle(canvas, result.piece, paint);

paint.setColor(colors.rgb(0, 255, 0));

drawCircle(canvas, result.board, paint);

var out = new java.io.FileOutputStream(files.join(debug_images_dir, new Date().getTime() + ".png"));

bmp.compress(Bitmap.CompressFormat.PNG, 100, out);

}

function drawCircle(canvas, point, paint){

canvas.drawCircle(point.x, point.y, 8, paint);

}

标签: #wechaty java