微信小游戲「跳一跳」外掛(java版)

image

其實也不能說算是外掛吧,算是個游戲小助手吧狸捅,畢竟不能抓包微王,也不能直接修改分數(shù)(據(jù)說之前可以直接抓包修改分數(shù),不過這漏洞已經(jīng)被微信官方修復)松嘶,今天這個是 Android 同學可以非常容易看懂的一篇文章艘狭,是從 Android 的角度實現(xiàn)的,附帶著技術原理分析和代碼分析翠订。

這個開源庫已經(jīng)被我同學分享到 GitHub 上巢音,他自己很無聊,就寫了這個東西和這篇文章尽超,自己通過寫代碼實現(xiàn)高分也是玩的不亦樂乎官撼,這就是程序員和普通玩家的區(qū)別吧。

開源庫地址:https://github.com/xushanmeng/WechatJumpHelper

功能簡介

用JAVA自動控制手機玩跳一跳

  • 自動識別圖像計算距離

  • 自動幫你點擊屏幕

  • 自動緩存圖片似谁,并在圖片上標記一些識別結果傲绣,如下圖:

    image

運行環(huán)境

  1. JAVA掠哥,最低版本為7.0,官網(wǎng)下載

  2. adb驅動秃诵,官網(wǎng)下載(需要翻墻)续搀,或者到這里下載SDK-tools,其中就包含adb

  3. 安卓手機菠净,目前已適配分辨率

  • 1600x2560

  • 1440x2560

  • 1080x1920

  • 720x1080

使用方法

有JAVA開發(fā)工具的同學可以直接運行java代碼禁舷,便于代碼調試,下面主要介紹運行已經(jīng)打包好的jar包的方法

  1. 手機打開USB調試毅往,并連接電腦
  • 打開USB調試方法牵咙,進入設置,找到開發(fā)者選項攀唯,打開并勾選USB調試洁桌;

  • 如果沒有開發(fā)者選項,進入關于手機侯嘀,連續(xù)點擊版本號7次另凌,即可開啟開發(fā)者選項

  1. 通過下面的命令戒幔,運行Android.jar

    java -jar Android.jar

  2. 根據(jù)手機分辨率選擇跳躍系數(shù)途茫,目前已適配機型:

    其他分辨率請自己微調。

  • 1600x2560機型推薦0.92

  • 1440x2560機型推薦1.039

  • 1080x1920機型推薦1.392

  • 720x1080機型推薦2.078

原理說明

  1. 通過adb命令控制手機截圖溪食,并取回到本地

    adb shell screencap -p /sdcard/screen.png

    adb pull /sdcard/screen.png .

  2. 圖片分析

  • 有靶點,即目標物體中心的白色圓點娜扇,則靶點中心為目標落點

  • 無靶點错沃,但是純色平面,或者規(guī)則平面雀瓢,則平面中心為目標落點

  • 無靶點枢析,又無純色規(guī)則平面,但是左上和右上位置的斜率是固定的刃麸,可根據(jù)固定斜率的斜線和目標物體中心線的焦點計算落點

  • 根據(jù)棋子的顏色醒叁,取頂部和底部的特征像素點,在截圖中進行匹配泊业,找到棋子坐標

  • 由于目標物體不是在左上就是在右上把沼,可以從上往下掃描,根據(jù)色差判斷目標物體位置吁伺,其中又分為以下幾種類型

    image
    image
    image
  • 計算棋子坐標和目標落點的距離

  • 距離×跳躍系數(shù)=按壓屏幕的時間饮睬,不同分辨率的手機,跳躍系數(shù)也有所不同

  1. 通過adb命令篮奄,給手機模擬按壓事件

    adb shell input swipe x y x y time

    其中xy是屏幕坐標捆愁,time是觸摸時間割去,單位ms。

工程結構

image

代碼詳解

這里將針對一些關鍵算法的代碼進行解釋

  1. 尋找棋子位置

    把截圖放大昼丑,可以看到棋子頂部像素連成一條橫線呻逆,那么我們通過顏色匹配,找到這一條線的始末位置菩帝,取中間位置咖城,就得到了棋子的x坐標。

    image

    棋子的底部也是一條橫線胁附,用顏色匹配酒繁,我們檢測到相似顏色的最大y坐標,就是棋子底部了控妻,不過考慮到棋子底部是個圓盤州袒,我們把棋子的y坐標再往上提一些。

    image.gif

    這樣我們就得到了棋子的xy坐標弓候,下面是相關代碼:

    /* 計算棋子位置 */Pixel piece = new Pixel();for (int i = TOP_BORDER; i < screenHeight - BOTTOM_BORDER; i++) {   int startX = 0;   int endX = 0;   for (int j = LEFT_BORDER; j < screenWidth - RIGHT_BORDER; j++) {       int red = Color.red(pixels[i][j].color);       int green = Color.green(pixels[i][j].color);       int blue = Color.blue(pixels[i][j].color);       if (50 < red && red < 55               && 50 < green && green < 55               && 55 < blue && blue < 65) {//棋子頂部顏色           //如果偵測到棋子相似顏色贝润,記錄下開始點           if (startX == 0) {               startX = j;               endX = 0;           }       } else if (endX == 0) {           //記錄下結束點           endX = j;           if (endX - startX < PIECE_TOP_PIXELS) {               //規(guī)避井蓋的BUG,像素點不夠長劫狠,則重新計算               startX = 0;               endX = 0;           }       }       if (50 < red && red < 60               && 55 < green && green < 65               && 95 < blue && blue < 105) {//棋子底部的顏色           //最后探測到的顏色就是棋子的底部像素           piece.y = i;       }   }   if (startX != 0 && piece.x == 0) {       piece.x = (startX + endX) / 2;   }}//棋子縱坐標從底部邊緣調整到底部中心piece.y -= PIECE_BOTTOM_CENTER_SHIFT;
    
  2. 尋找靶點

    所謂靶點狰域,就是目標物體中心的那個小圓點,顏色值為0xf5f5f5依鸥。

    image

    那么我們只需要尋找顏色值為0xf5f5f5的色塊就可以了亥至,為了規(guī)避其他物體相近顏色干擾,我們可以限制色塊的大小贱迟,正確大小的色塊才是靶點姐扮。

    但是如何計算色塊的大小呢,色塊最頂端到最底端y坐標的差值我們作為色塊的高度衣吠,同理茶敏,最左側到最右側x坐標的差值作為寬度,我們只需要查找這四個頂點的坐標就可以了缚俏。

    本來打算用凸包的Graham掃描算法惊搏,后來發(fā)現(xiàn)色塊已經(jīng)是凸包了,且邊緣像素是連續(xù)的忧换,那么我們按照一定順序恬惯,遍歷邊緣像素,就可以在O(n^-2)的時間復雜度里亚茬,得到色塊的頂點坐標了宿崭。

    我們從第一個像素點開始,尋找的順序如圖所示:

    image
    /**    * 尋找色塊頂點像素    */   public static final Pixel[] findVertexs(Pixel[][] pixels, Pixel firstPixcel) {       Pixel[] vertexs = new Pixel[4];       Pixel topPixel = firstPixcel;       Pixel leftPixel = firstPixcel;       Pixel rightPixel = firstPixcel;       Pixel bottomPixel = firstPixcel;       Pixel currentPixcel = firstPixcel;       //先把坐標置于左上角       while (checkBorder(pixels, currentPixcel)//判斷是否超出圖像邊緣               && Color.compareColor(pixels[currentPixcel.y - 1][currentPixcel.x], firstPixcel)) {//判斷是否是相同顏色            currentPixcel = pixels[currentPixcel.y - 1][currentPixcel.x];       }       while (checkBorder(pixels, currentPixcel)               && Color.compareColor(pixels[currentPixcel.y][currentPixcel.x - 1], firstPixcel)) {            currentPixcel = pixels[currentPixcel.y][currentPixcel.x - 1];       }       //尋找上頂點像素       while (checkBorder(pixels, currentPixcel)) {           if (Color.compareColor(pixels[currentPixcel.y - 1][currentPixcel.x], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y - 1][currentPixcel.x];           } else if (Color.compareColor(pixels[currentPixcel.y][currentPixcel.x + 1], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y][currentPixcel.x + 1];           } else {               topPixel = findCenterPixcelHorizontal(pixels, currentPixcel);               break;           }       }       //尋找右頂點像素       while (checkBorder(pixels, currentPixcel)) {           if (Color.compareColor(pixels[currentPixcel.y][currentPixcel.x + 1], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y][currentPixcel.x + 1];           } else if (Color.compareColor(pixels[currentPixcel.y + 1][currentPixcel.x], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y + 1][currentPixcel.x];           } else {               rightPixel = findCenterPixcelVertial(pixels, currentPixcel);               break;           }       }       //尋找下頂點像素       while (checkBorder(pixels, currentPixcel)) {           if (Color.compareColor(pixels[currentPixcel.y + 1][currentPixcel.x], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y + 1][currentPixcel.x];           } else if (Color.compareColor(pixels[currentPixcel.y][currentPixcel.x - 1], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y][currentPixcel.x - 1];           } else {               bottomPixel = findCenterPixcelHorizontal(pixels, currentPixcel);               break;           }       }       //尋找左頂點像素       while (checkBorder(pixels, currentPixcel)) {           if (Color.compareColor(pixels[currentPixcel.y][currentPixcel.x - 1], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y][currentPixcel.x - 1];           } else if (Color.compareColor(pixels[currentPixcel.y - 1][currentPixcel.x], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y - 1][currentPixcel.x];           } else {               leftPixel = findCenterPixcelVertial(pixels, currentPixcel);               break;           }       }       vertexs[0] = leftPixel;       vertexs[1] = topPixel;       vertexs[2] = rightPixel;       vertexs[3] = bottomPixel;       return vertexs;   }
    

    得到了四個坐標點才写,我們就可以計算色塊的中點了葡兑,也就是目標落點奖蔓。

    對于沒有靶點,但是落點是規(guī)則平面的讹堤,也可以用類似算法吆鹤。

  3. 斜率計算對于沒有靶點,又不是規(guī)則平面的洲守,我們怎么計算落點呢疑务,這時候就要用到斜率了。

    可以看得出來梗醇,每次左上角或右上角出現(xiàn)的物體知允,針對當前物體的方向都是一樣的,也就是兩個物體中心的連線叙谨,斜率是固定的温鸽。

    基本所有的目標物體,最頂點像素中點的x坐標手负,都是在物體中間涤垫,我們至少先得到了目標物體x坐標了,記為des.x 竟终,接下來要求des.y 蝠猬。

    image.gif

    如上圖所示,計算過程如下:

    斜線的公式為 y=kx+b

    那么统捶,在棋子坐標上有 piece.y=k*piece.x+b

    在目標落點坐標上有 des.y=kdes.x+b

    代入得到 des.y=k*(des.x-piece.x)+piece.y

    然而這種算法還是有偏差的榆芦。

    image.gif

    可以看到,同樣的斜率喘鸟,如果棋子的位置有偏差歧杏,計算出來最終落點還是會有偏差的。

    代碼解析就先講這么多迷守,希望有大神可以提出更好的解決方案。

玩游戲小竅門

  1. 連續(xù)的落到物體中心位置旺入,是有分數(shù)加成的兑凿,最多跳一次可以得幾十分

  2. 井蓋、商店茵瘾、唱片礼华、魔方,多停留一會拗秘,有音樂響起后也是有分數(shù)加成的

那么看一下程序員的朋友圈有多殘酷吧

image

原文作者:Samon
閱讀原文

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末圣絮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子雕旨,更是在濱河造成了極大的恐慌扮匠,老刑警劉巖捧请,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異棒搜,居然都是意外死亡疹蛉,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門力麸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來可款,“玉大人,你說我怎么就攤上這事克蚂」刖ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵埃叭,是天一觀的道長摸恍。 經(jīng)常有香客問我,道長游盲,這世上最難降的妖魔是什么误墓? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮益缎,結果婚禮上谜慌,老公的妹妹穿的比我還像新娘。我一直安慰自己莺奔,他們只是感情好欣范,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著令哟,像睡著了一般恼琼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屏富,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天晴竞,我揣著相機與錄音,去河邊找鬼狠半。 笑死噩死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的神年。 我是一名探鬼主播已维,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼已日!你這毒婦竟也來了垛耳?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎堂鲜,沒想到半個月后栈雳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡泡嘴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年甫恩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酌予。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡磺箕,死狀恐怖,靈堂內的尸體忽然破棺而出抛虫,到底是詐尸還是另有隱情松靡,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布建椰,位于F島的核電站雕欺,受9級特大地震影響,放射性物質發(fā)生泄漏棉姐。R本人自食惡果不足惜屠列,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伞矩。 院中可真熱鬧笛洛,春花似錦、人聲如沸乃坤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽湿诊。三九已至狱杰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間厅须,已是汗流浹背仿畸。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留朗和,地道東北人错沽。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像例隆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子抢蚀,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內容